121617c04Sjeremylt // Copyright (c) 2017-2018, Lawrence Livermore National Security, LLC. 221617c04Sjeremylt // Produced at the Lawrence Livermore National Laboratory. LLNL-CODE-734707. 321617c04Sjeremylt // All Rights reserved. See files LICENSE and NOTICE for details. 421617c04Sjeremylt // 521617c04Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software 621617c04Sjeremylt // libraries and APIs for efficient high-order finite element and spectral 721617c04Sjeremylt // element discretizations for exascale applications. For more information and 821617c04Sjeremylt // source code availability see http://github.com/ceed. 921617c04Sjeremylt // 1021617c04Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 1121617c04Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office 1221617c04Sjeremylt // of Science and the National Nuclear Security Administration) responsible for 1321617c04Sjeremylt // the planning and preparation of a capable exascale ecosystem, including 1421617c04Sjeremylt // software, applications, hardware, advanced system engineering and early 1521617c04Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative. 1621617c04Sjeremylt 17ec3da8bcSJed Brown #include <ceed/ceed.h> 18ec3da8bcSJed Brown #include <ceed/backend.h> 193d576824SJeremy L Thompson #include <math.h> 203d576824SJeremy L Thompson #include <stdbool.h> 213d576824SJeremy L Thompson #include <stddef.h> 223d576824SJeremy L Thompson #include <stdint.h> 2321617c04Sjeremylt #include "ceed-ref.h" 2421617c04Sjeremylt 25f10650afSjeremylt //------------------------------------------------------------------------------ 26f10650afSjeremylt // Setup Input/Output Fields 27f10650afSjeremylt //------------------------------------------------------------------------------ 28fe2413ffSjeremylt static int CeedOperatorSetupFields_Ref(CeedQFunction qf, CeedOperator op, 2991703d3fSjeremylt bool inOrOut, 30d1d35e2fSjeremylt CeedVector *full_evecs, CeedVector *e_vecs, 31d1d35e2fSjeremylt CeedVector *q_vecs, CeedInt starte, 32d1d35e2fSjeremylt CeedInt num_fields, CeedInt Q) { 334d537eeaSYohann CeedInt dim, ierr, size, P; 34aedaa0e5Sjeremylt Ceed ceed; 35e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 36d1bcdac9Sjeremylt CeedBasis basis; 37d1d35e2fSjeremylt CeedElemRestriction elem_restr; 38d1d35e2fSjeremylt CeedOperatorField *op_fields; 39d1d35e2fSjeremylt CeedQFunctionField *qf_fields; 40fe2413ffSjeremylt if (inOrOut) { 41d1d35e2fSjeremylt ierr = CeedOperatorGetFields(op, NULL, &op_fields); CeedChkBackend(ierr); 42d1d35e2fSjeremylt ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields); CeedChkBackend(ierr); 43fe2413ffSjeremylt } else { 44d1d35e2fSjeremylt ierr = CeedOperatorGetFields(op, &op_fields, NULL); CeedChkBackend(ierr); 45d1d35e2fSjeremylt ierr = CeedQFunctionGetFields(qf, &qf_fields, NULL); CeedChkBackend(ierr); 46fe2413ffSjeremylt } 4721617c04Sjeremylt 48885ac19cSjeremylt // Loop over fields 49d1d35e2fSjeremylt for (CeedInt i=0; i<num_fields; i++) { 50d1d35e2fSjeremylt CeedEvalMode eval_mode; 51d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); 52e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 53d1d35e2fSjeremylt 54d1d35e2fSjeremylt if (eval_mode != CEED_EVAL_WEIGHT) { 55d1d35e2fSjeremylt ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &elem_restr); 56d1d35e2fSjeremylt CeedChkBackend(ierr); 57d1d35e2fSjeremylt ierr = CeedElemRestrictionCreateVector(elem_restr, NULL, 58d1d35e2fSjeremylt &full_evecs[i+starte]); 59e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 60135a076eSjeremylt } 61135a076eSjeremylt 62d1d35e2fSjeremylt switch(eval_mode) { 63885ac19cSjeremylt case CEED_EVAL_NONE: 64d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetSize(qf_fields[i], &size); CeedChkBackend(ierr); 65d1d35e2fSjeremylt ierr = CeedVectorCreate(ceed, Q*size, &q_vecs[i]); CeedChkBackend(ierr); 66aedaa0e5Sjeremylt break; 67aedaa0e5Sjeremylt case CEED_EVAL_INTERP: 68d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetSize(qf_fields[i], &size); CeedChkBackend(ierr); 69d1d35e2fSjeremylt ierr = CeedElemRestrictionGetElementSize(elem_restr, &P); 70e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 71d1d35e2fSjeremylt ierr = CeedVectorCreate(ceed, P*size, &e_vecs[i]); CeedChkBackend(ierr); 72d1d35e2fSjeremylt ierr = CeedVectorCreate(ceed, Q*size, &q_vecs[i]); CeedChkBackend(ierr); 73885ac19cSjeremylt break; 74885ac19cSjeremylt case CEED_EVAL_GRAD: 75d1d35e2fSjeremylt ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis); CeedChkBackend(ierr); 76d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetSize(qf_fields[i], &size); CeedChkBackend(ierr); 77e15f9bd0SJeremy L Thompson ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr); 78d1d35e2fSjeremylt ierr = CeedElemRestrictionGetElementSize(elem_restr, &P); 79e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 80d1d35e2fSjeremylt ierr = CeedVectorCreate(ceed, P*size/dim, &e_vecs[i]); CeedChkBackend(ierr); 81d1d35e2fSjeremylt ierr = CeedVectorCreate(ceed, Q*size, &q_vecs[i]); CeedChkBackend(ierr); 82885ac19cSjeremylt break; 83885ac19cSjeremylt case CEED_EVAL_WEIGHT: // Only on input fields 84d1d35e2fSjeremylt ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis); CeedChkBackend(ierr); 85d1d35e2fSjeremylt ierr = CeedVectorCreate(ceed, Q, &q_vecs[i]); CeedChkBackend(ierr); 86d1bcdac9Sjeremylt ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, 87d1d35e2fSjeremylt CEED_VECTOR_NONE, q_vecs[i]); CeedChkBackend(ierr); 88885ac19cSjeremylt break; 89885ac19cSjeremylt case CEED_EVAL_DIV: 904d537eeaSYohann break; // Not implemented 91885ac19cSjeremylt case CEED_EVAL_CURL: 924d537eeaSYohann break; // Not implemented 9321617c04Sjeremylt } 94885ac19cSjeremylt } 95e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 9621617c04Sjeremylt } 9721617c04Sjeremylt 98f10650afSjeremylt //------------------------------------------------------------------------------ 99f10650afSjeremylt // Setup Operator 100f10650afSjeremylt //------------------------------------------------------------------------------/* 101885ac19cSjeremylt static int CeedOperatorSetup_Ref(CeedOperator op) { 10221617c04Sjeremylt int ierr; 103d1d35e2fSjeremylt bool setup_done; 104d1d35e2fSjeremylt ierr = CeedOperatorIsSetupDone(op, &setup_done); CeedChkBackend(ierr); 105d1d35e2fSjeremylt if (setup_done) return CEED_ERROR_SUCCESS; 106aedaa0e5Sjeremylt Ceed ceed; 107e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 1084ce2993fSjeremylt CeedOperator_Ref *impl; 109e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr); 1104ce2993fSjeremylt CeedQFunction qf; 111e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr); 112d1d35e2fSjeremylt CeedInt Q, num_input_fields, num_output_fields; 113e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChkBackend(ierr); 114*0b454692Sjeremylt ierr = CeedQFunctionIsIdentity(qf, &impl->is_identity_qf); CeedChkBackend(ierr); 115d1d35e2fSjeremylt ierr = CeedQFunctionGetNumArgs(qf, &num_input_fields, &num_output_fields); 116e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 117d1d35e2fSjeremylt CeedOperatorField *op_input_fields, *op_output_fields; 118d1d35e2fSjeremylt ierr = CeedOperatorGetFields(op, &op_input_fields, &op_output_fields); 119e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 120d1d35e2fSjeremylt CeedQFunctionField *qf_input_fields, *qf_output_fields; 121d1d35e2fSjeremylt ierr = CeedQFunctionGetFields(qf, &qf_input_fields, &qf_output_fields); 122e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 123885ac19cSjeremylt 124885ac19cSjeremylt // Allocate 125d1d35e2fSjeremylt ierr = CeedCalloc(num_input_fields + num_output_fields, &impl->e_vecs); 126e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 127d1d35e2fSjeremylt ierr = CeedCalloc(num_input_fields + num_output_fields, &impl->e_data); 128e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 129885ac19cSjeremylt 130d1d35e2fSjeremylt ierr = CeedCalloc(16, &impl->input_state); CeedChkBackend(ierr); 131d1d35e2fSjeremylt ierr = CeedCalloc(16, &impl->e_vecs_in); CeedChkBackend(ierr); 132d1d35e2fSjeremylt ierr = CeedCalloc(16, &impl->e_vecs_out); CeedChkBackend(ierr); 133d1d35e2fSjeremylt ierr = CeedCalloc(16, &impl->q_vecs_in); CeedChkBackend(ierr); 134d1d35e2fSjeremylt ierr = CeedCalloc(16, &impl->q_vecs_out); CeedChkBackend(ierr); 135885ac19cSjeremylt 136d1d35e2fSjeremylt impl->num_e_vecs_in = num_input_fields; 137d1d35e2fSjeremylt impl->num_e_vecs_out = num_output_fields; 138885ac19cSjeremylt 139d1d35e2fSjeremylt // Set up infield and outfield e_vecs and q_vecs 140885ac19cSjeremylt // Infields 141d1d35e2fSjeremylt ierr = CeedOperatorSetupFields_Ref(qf, op, 0, impl->e_vecs, 142d1d35e2fSjeremylt impl->e_vecs_in, impl->q_vecs_in, 0, 143d1d35e2fSjeremylt num_input_fields, Q); 144e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 145885ac19cSjeremylt // Outfields 146d1d35e2fSjeremylt ierr = CeedOperatorSetupFields_Ref(qf, op, 1, impl->e_vecs, 147d1d35e2fSjeremylt impl->e_vecs_out, impl->q_vecs_out, 148d1d35e2fSjeremylt num_input_fields, num_output_fields, Q); 149e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 150885ac19cSjeremylt 15116911fdaSjeremylt // Identity QFunctions 152*0b454692Sjeremylt if (impl->is_identity_qf) { 153d1d35e2fSjeremylt CeedEvalMode in_mode, out_mode; 154d1d35e2fSjeremylt CeedQFunctionField *in_fields, *out_fields; 155d1d35e2fSjeremylt ierr = CeedQFunctionGetFields(qf, &in_fields, &out_fields); 156e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 157*0b454692Sjeremylt ierr = CeedQFunctionFieldGetEvalMode(in_fields[0], &in_mode); 158d1d35e2fSjeremylt CeedChkBackend(ierr); 159*0b454692Sjeremylt ierr = CeedQFunctionFieldGetEvalMode(out_fields[0], &out_mode); 160d1d35e2fSjeremylt CeedChkBackend(ierr); 161d1d35e2fSjeremylt 162*0b454692Sjeremylt if (in_mode == CEED_EVAL_NONE && out_mode == CEED_EVAL_NONE) { 163*0b454692Sjeremylt impl->is_identity_restr_op = true; 164*0b454692Sjeremylt } else { 165*0b454692Sjeremylt ierr = CeedVectorDestroy(&impl->q_vecs_out[0]); CeedChkBackend(ierr); 166*0b454692Sjeremylt impl->q_vecs_out[0] = impl->q_vecs_in[0]; 167*0b454692Sjeremylt ierr = CeedVectorAddReference(impl->q_vecs_in[0]); CeedChkBackend(ierr); 16816911fdaSjeremylt } 16916911fdaSjeremylt } 17016911fdaSjeremylt 171e15f9bd0SJeremy L Thompson ierr = CeedOperatorSetSetupDone(op); CeedChkBackend(ierr); 172885ac19cSjeremylt 173e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 174885ac19cSjeremylt } 175885ac19cSjeremylt 176f10650afSjeremylt //------------------------------------------------------------------------------ 177f10650afSjeremylt // Setup Operator Inputs 178f10650afSjeremylt //------------------------------------------------------------------------------ 179d1d35e2fSjeremylt static inline int CeedOperatorSetupInputs_Ref(CeedInt num_input_fields, 180d1d35e2fSjeremylt CeedQFunctionField *qf_input_fields, CeedOperatorField *op_input_fields, 181d1d35e2fSjeremylt CeedVector in_vec, const bool skip_active, CeedOperator_Ref *impl, 1821d102b48SJeremy L Thompson CeedRequest *request) { 1831d102b48SJeremy L Thompson CeedInt ierr; 184d1d35e2fSjeremylt CeedEvalMode eval_mode; 185d1bcdac9Sjeremylt CeedVector vec; 186d1d35e2fSjeremylt CeedElemRestriction elem_restr; 1878d713cf6Sjeremylt uint64_t state; 188885ac19cSjeremylt 189d1d35e2fSjeremylt for (CeedInt i=0; i<num_input_fields; i++) { 190d1bcdac9Sjeremylt // Get input vector 191d1d35e2fSjeremylt ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec); 192d1d35e2fSjeremylt CeedChkBackend(ierr); 1931d102b48SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 194d1d35e2fSjeremylt if (skip_active) 1951d102b48SJeremy L Thompson continue; 1961d102b48SJeremy L Thompson else 197d1d35e2fSjeremylt vec = in_vec; 1981d102b48SJeremy L Thompson } 1991d102b48SJeremy L Thompson 200d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode); 201e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 2021d102b48SJeremy L Thompson // Restrict and Evec 203d1d35e2fSjeremylt if (eval_mode == CEED_EVAL_WEIGHT) { // Skip 2041d102b48SJeremy L Thompson } else { 205668048e2SJed Brown // Restrict 206e15f9bd0SJeremy L Thompson ierr = CeedVectorGetState(vec, &state); CeedChkBackend(ierr); 2078d713cf6Sjeremylt // Skip restriction if input is unchanged 208d1d35e2fSjeremylt if (state != impl->input_state[i] || vec == in_vec) { 209d1d35e2fSjeremylt ierr = CeedOperatorFieldGetElemRestriction(op_input_fields[i], &elem_restr); 210e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 211d1d35e2fSjeremylt ierr = CeedElemRestrictionApply(elem_restr, CEED_NOTRANSPOSE, vec, 212d1d35e2fSjeremylt impl->e_vecs[i], request); CeedChkBackend(ierr); 213d1d35e2fSjeremylt impl->input_state[i] = state; 2148d713cf6Sjeremylt } 215668048e2SJed Brown // Get evec 216d1d35e2fSjeremylt ierr = CeedVectorGetArrayRead(impl->e_vecs[i], CEED_MEM_HOST, 217d1d35e2fSjeremylt (const CeedScalar **) &impl->e_data[i]); 218e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 219885ac19cSjeremylt } 220885ac19cSjeremylt } 221e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 222885ac19cSjeremylt } 223885ac19cSjeremylt 224f10650afSjeremylt //------------------------------------------------------------------------------ 225f10650afSjeremylt // Input Basis Action 226f10650afSjeremylt //------------------------------------------------------------------------------ 2271d102b48SJeremy L Thompson static inline int CeedOperatorInputBasis_Ref(CeedInt e, CeedInt Q, 228d1d35e2fSjeremylt CeedQFunctionField *qf_input_fields, CeedOperatorField *op_input_fields, 229d1d35e2fSjeremylt CeedInt num_input_fields, const bool skip_active, CeedOperator_Ref *impl) { 2301d102b48SJeremy L Thompson CeedInt ierr; 231d1d35e2fSjeremylt CeedInt dim, elem_size, size; 232d1d35e2fSjeremylt CeedElemRestriction elem_restr; 233d1d35e2fSjeremylt CeedEvalMode eval_mode; 2341d102b48SJeremy L Thompson CeedBasis basis; 2351d102b48SJeremy L Thompson 236d1d35e2fSjeremylt for (CeedInt i=0; i<num_input_fields; i++) { 2371d102b48SJeremy L Thompson // Skip active input 238d1d35e2fSjeremylt if (skip_active) { 2391d102b48SJeremy L Thompson CeedVector vec; 240d1d35e2fSjeremylt ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec); 241d1d35e2fSjeremylt CeedChkBackend(ierr); 2421d102b48SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) 2431d102b48SJeremy L Thompson continue; 2441d102b48SJeremy L Thompson } 245d1d35e2fSjeremylt // Get elem_size, eval_mode, size 246d1d35e2fSjeremylt ierr = CeedOperatorFieldGetElemRestriction(op_input_fields[i], &elem_restr); 247e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 248d1d35e2fSjeremylt ierr = CeedElemRestrictionGetElementSize(elem_restr, &elem_size); 249e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 250d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode); 251e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 252d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetSize(qf_input_fields[i], &size); 253d1d35e2fSjeremylt CeedChkBackend(ierr); 254885ac19cSjeremylt // Basis action 255d1d35e2fSjeremylt switch(eval_mode) { 256885ac19cSjeremylt case CEED_EVAL_NONE: 257d1d35e2fSjeremylt ierr = CeedVectorSetArray(impl->q_vecs_in[i], CEED_MEM_HOST, 258d1d35e2fSjeremylt CEED_USE_POINTER, &impl->e_data[i][e*Q*size]); 259d1d35e2fSjeremylt CeedChkBackend(ierr); 260885ac19cSjeremylt break; 261885ac19cSjeremylt case CEED_EVAL_INTERP: 262d1d35e2fSjeremylt ierr = CeedOperatorFieldGetBasis(op_input_fields[i], &basis); 263e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 264d1d35e2fSjeremylt ierr = CeedVectorSetArray(impl->e_vecs_in[i], CEED_MEM_HOST, 265d1d35e2fSjeremylt CEED_USE_POINTER, &impl->e_data[i][e*elem_size*size]); 266e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 267d1d35e2fSjeremylt ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, 268d1d35e2fSjeremylt impl->e_vecs_in[i], impl->q_vecs_in[i]); CeedChkBackend(ierr); 269885ac19cSjeremylt break; 270885ac19cSjeremylt case CEED_EVAL_GRAD: 271d1d35e2fSjeremylt ierr = CeedOperatorFieldGetBasis(op_input_fields[i], &basis); 272e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 273e15f9bd0SJeremy L Thompson ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr); 274d1d35e2fSjeremylt ierr = CeedVectorSetArray(impl->e_vecs_in[i], CEED_MEM_HOST, 275d1d35e2fSjeremylt CEED_USE_POINTER, &impl->e_data[i][e*elem_size*size/dim]); 276e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 277d1bcdac9Sjeremylt ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, 278d1d35e2fSjeremylt CEED_EVAL_GRAD, impl->e_vecs_in[i], 279d1d35e2fSjeremylt impl->q_vecs_in[i]); CeedChkBackend(ierr); 280885ac19cSjeremylt break; 281885ac19cSjeremylt case CEED_EVAL_WEIGHT: 282885ac19cSjeremylt break; // No action 283bbfacfcdSjeremylt // LCOV_EXCL_START 284885ac19cSjeremylt case CEED_EVAL_DIV: 2851d102b48SJeremy L Thompson case CEED_EVAL_CURL: { 286d1d35e2fSjeremylt ierr = CeedOperatorFieldGetBasis(op_input_fields[i], &basis); 287e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 2881d102b48SJeremy L Thompson Ceed ceed; 289e15f9bd0SJeremy L Thompson ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr); 290e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 291e15f9bd0SJeremy L Thompson "Ceed evaluation mode not implemented"); 292bbfacfcdSjeremylt // LCOV_EXCL_STOP 293885ac19cSjeremylt } 294885ac19cSjeremylt } 295885ac19cSjeremylt } 296e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 297885ac19cSjeremylt } 298885ac19cSjeremylt 299f10650afSjeremylt //------------------------------------------------------------------------------ 300f10650afSjeremylt // Output Basis Action 301f10650afSjeremylt //------------------------------------------------------------------------------ 3021d102b48SJeremy L Thompson static inline int CeedOperatorOutputBasis_Ref(CeedInt e, CeedInt Q, 303d1d35e2fSjeremylt CeedQFunctionField *qf_output_fields, CeedOperatorField *op_output_fields, 304d1d35e2fSjeremylt CeedInt num_input_fields, CeedInt num_output_fields, CeedOperator op, 3051d102b48SJeremy L Thompson CeedOperator_Ref *impl) { 3061d102b48SJeremy L Thompson CeedInt ierr; 307d1d35e2fSjeremylt CeedInt dim, elem_size, size; 308d1d35e2fSjeremylt CeedElemRestriction elem_restr; 309d1d35e2fSjeremylt CeedEvalMode eval_mode; 3101d102b48SJeremy L Thompson CeedBasis basis; 3111d102b48SJeremy L Thompson 312d1d35e2fSjeremylt for (CeedInt i=0; i<num_output_fields; i++) { 313d1d35e2fSjeremylt // Get elem_size, eval_mode, size 314d1d35e2fSjeremylt ierr = CeedOperatorFieldGetElemRestriction(op_output_fields[i], &elem_restr); 315e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 316d1d35e2fSjeremylt ierr = CeedElemRestrictionGetElementSize(elem_restr, &elem_size); 317e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 318d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode); 319e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 320d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetSize(qf_output_fields[i], &size); 321e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 322885ac19cSjeremylt // Basis action 323d1d35e2fSjeremylt switch(eval_mode) { 324885ac19cSjeremylt case CEED_EVAL_NONE: 325885ac19cSjeremylt break; // No action 326885ac19cSjeremylt case CEED_EVAL_INTERP: 327d1d35e2fSjeremylt ierr = CeedOperatorFieldGetBasis(op_output_fields[i], &basis); 328e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 329d1d35e2fSjeremylt ierr = CeedVectorSetArray(impl->e_vecs_out[i], CEED_MEM_HOST, 330aedaa0e5Sjeremylt CEED_USE_POINTER, 331d1d35e2fSjeremylt &impl->e_data[i + num_input_fields][e*elem_size*size]); 332e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 333aedaa0e5Sjeremylt ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE, 334d1d35e2fSjeremylt CEED_EVAL_INTERP, impl->q_vecs_out[i], 335d1d35e2fSjeremylt impl->e_vecs_out[i]); CeedChkBackend(ierr); 336885ac19cSjeremylt break; 337885ac19cSjeremylt case CEED_EVAL_GRAD: 338d1d35e2fSjeremylt ierr = CeedOperatorFieldGetBasis(op_output_fields[i], &basis); 339e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 340e15f9bd0SJeremy L Thompson ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr); 341d1d35e2fSjeremylt ierr = CeedVectorSetArray(impl->e_vecs_out[i], CEED_MEM_HOST, 342aedaa0e5Sjeremylt CEED_USE_POINTER, 343d1d35e2fSjeremylt &impl->e_data[i + num_input_fields][e*elem_size*size/dim]); 344e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 345aedaa0e5Sjeremylt ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE, 346d1d35e2fSjeremylt CEED_EVAL_GRAD, impl->q_vecs_out[i], 347d1d35e2fSjeremylt impl->e_vecs_out[i]); CeedChkBackend(ierr); 348885ac19cSjeremylt break; 349c042f62fSJeremy L Thompson // LCOV_EXCL_START 350bbfacfcdSjeremylt case CEED_EVAL_WEIGHT: { 3514ce2993fSjeremylt Ceed ceed; 352e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 353e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 354e15f9bd0SJeremy L Thompson "CEED_EVAL_WEIGHT cannot be an output " 3551d102b48SJeremy L Thompson "evaluation mode"); 3564ce2993fSjeremylt } 357885ac19cSjeremylt case CEED_EVAL_DIV: 3581d102b48SJeremy L Thompson case CEED_EVAL_CURL: { 3591d102b48SJeremy L Thompson Ceed ceed; 360e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 361e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 362e15f9bd0SJeremy L Thompson "Ceed evaluation mode not implemented"); 3631d102b48SJeremy L Thompson // LCOV_EXCL_STOP 364885ac19cSjeremylt } 365885ac19cSjeremylt } 366885ac19cSjeremylt } 367e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 3681d102b48SJeremy L Thompson } 3691d102b48SJeremy L Thompson 370f10650afSjeremylt //------------------------------------------------------------------------------ 371f10650afSjeremylt // Restore Input Vectors 372f10650afSjeremylt //------------------------------------------------------------------------------ 373d1d35e2fSjeremylt static inline int CeedOperatorRestoreInputs_Ref(CeedInt num_input_fields, 374d1d35e2fSjeremylt CeedQFunctionField *qf_input_fields, CeedOperatorField *op_input_fields, 375d1d35e2fSjeremylt const bool skip_active, CeedOperator_Ref *impl) { 3761d102b48SJeremy L Thompson CeedInt ierr; 377d1d35e2fSjeremylt CeedEvalMode eval_mode; 3781d102b48SJeremy L Thompson 379d1d35e2fSjeremylt for (CeedInt i=0; i<num_input_fields; i++) { 3801d102b48SJeremy L Thompson // Skip active inputs 381d1d35e2fSjeremylt if (skip_active) { 3821d102b48SJeremy L Thompson CeedVector vec; 383d1d35e2fSjeremylt ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec); 384d1d35e2fSjeremylt CeedChkBackend(ierr); 3851d102b48SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) 3861d102b48SJeremy L Thompson continue; 3871d102b48SJeremy L Thompson } 3881d102b48SJeremy L Thompson // Restore input 389d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode); 390e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 391d1d35e2fSjeremylt if (eval_mode == CEED_EVAL_WEIGHT) { // Skip 3921d102b48SJeremy L Thompson } else { 393d1d35e2fSjeremylt ierr = CeedVectorRestoreArrayRead(impl->e_vecs[i], 394d1d35e2fSjeremylt (const CeedScalar **) &impl->e_data[i]); 395e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 3961d102b48SJeremy L Thompson } 3971d102b48SJeremy L Thompson } 398e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 3991d102b48SJeremy L Thompson } 4001d102b48SJeremy L Thompson 401f10650afSjeremylt //------------------------------------------------------------------------------ 402f10650afSjeremylt // Operator Apply 403f10650afSjeremylt //------------------------------------------------------------------------------ 404d1d35e2fSjeremylt static int CeedOperatorApplyAdd_Ref(CeedOperator op, CeedVector in_vec, 405d1d35e2fSjeremylt CeedVector out_vec, CeedRequest *request) { 4061d102b48SJeremy L Thompson int ierr; 4071d102b48SJeremy L Thompson CeedOperator_Ref *impl; 408e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr); 4091d102b48SJeremy L Thompson CeedQFunction qf; 410e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr); 411d1d35e2fSjeremylt CeedInt Q, num_elem, num_input_fields, num_output_fields, size; 412e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChkBackend(ierr); 413d1d35e2fSjeremylt ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChkBackend(ierr); 414d1d35e2fSjeremylt ierr= CeedQFunctionGetNumArgs(qf, &num_input_fields, &num_output_fields); 415e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 416d1d35e2fSjeremylt CeedOperatorField *op_input_fields, *op_output_fields; 417d1d35e2fSjeremylt ierr = CeedOperatorGetFields(op, &op_input_fields, &op_output_fields); 418e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 419d1d35e2fSjeremylt CeedQFunctionField *qf_input_fields, *qf_output_fields; 420d1d35e2fSjeremylt ierr = CeedQFunctionGetFields(qf, &qf_input_fields, &qf_output_fields); 421e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 422d1d35e2fSjeremylt CeedEvalMode eval_mode; 4231d102b48SJeremy L Thompson CeedVector vec; 424d1d35e2fSjeremylt CeedElemRestriction elem_restr; 4251d102b48SJeremy L Thompson 4261d102b48SJeremy L Thompson // Setup 427e15f9bd0SJeremy L Thompson ierr = CeedOperatorSetup_Ref(op); CeedChkBackend(ierr); 4281d102b48SJeremy L Thompson 429*0b454692Sjeremylt // Restriction only operator 430*0b454692Sjeremylt if (impl->is_identity_restr_op) { 431*0b454692Sjeremylt ierr = CeedOperatorFieldGetElemRestriction(op_input_fields[0], &elem_restr); 432*0b454692Sjeremylt CeedChkBackend(ierr); 433*0b454692Sjeremylt ierr = CeedElemRestrictionApply(elem_restr, CEED_NOTRANSPOSE, in_vec, 434*0b454692Sjeremylt impl->e_vecs[0], request); CeedChkBackend(ierr); 435*0b454692Sjeremylt ierr = CeedOperatorFieldGetElemRestriction(op_output_fields[0], &elem_restr); 436*0b454692Sjeremylt CeedChkBackend(ierr); 437*0b454692Sjeremylt ierr = CeedElemRestrictionApply(elem_restr, CEED_TRANSPOSE, impl->e_vecs[0], 438*0b454692Sjeremylt out_vec, request); CeedChkBackend(ierr); 439*0b454692Sjeremylt return CEED_ERROR_SUCCESS; 440*0b454692Sjeremylt } 441*0b454692Sjeremylt 4421d102b48SJeremy L Thompson // Input Evecs and Restriction 443d1d35e2fSjeremylt ierr = CeedOperatorSetupInputs_Ref(num_input_fields, qf_input_fields, 444d1d35e2fSjeremylt op_input_fields, in_vec, false, impl, 445e15f9bd0SJeremy L Thompson request); CeedChkBackend(ierr); 4461d102b48SJeremy L Thompson 4471d102b48SJeremy L Thompson // Output Evecs 448d1d35e2fSjeremylt for (CeedInt i=0; i<num_output_fields; i++) { 449d1d35e2fSjeremylt ierr = CeedVectorGetArray(impl->e_vecs[i+impl->num_e_vecs_in], CEED_MEM_HOST, 450d1d35e2fSjeremylt &impl->e_data[i + num_input_fields]); CeedChkBackend(ierr); 4511d102b48SJeremy L Thompson } 4521d102b48SJeremy L Thompson 4531d102b48SJeremy L Thompson // Loop through elements 454d1d35e2fSjeremylt for (CeedInt e=0; e<num_elem; e++) { 4551d102b48SJeremy L Thompson // Output pointers 456d1d35e2fSjeremylt for (CeedInt i=0; i<num_output_fields; i++) { 457d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode); 458e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 459d1d35e2fSjeremylt if (eval_mode == CEED_EVAL_NONE) { 460d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetSize(qf_output_fields[i], &size); 461e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 462d1d35e2fSjeremylt ierr = CeedVectorSetArray(impl->q_vecs_out[i], CEED_MEM_HOST, 4631d102b48SJeremy L Thompson CEED_USE_POINTER, 464d1d35e2fSjeremylt &impl->e_data[i + num_input_fields][e*Q*size]); 465e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 4661d102b48SJeremy L Thompson } 4671d102b48SJeremy L Thompson } 4681d102b48SJeremy L Thompson 46916911fdaSjeremylt // Input basis apply 470d1d35e2fSjeremylt ierr = CeedOperatorInputBasis_Ref(e, Q, qf_input_fields, op_input_fields, 471d1d35e2fSjeremylt num_input_fields, false, impl); 472e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 47316911fdaSjeremylt 4741d102b48SJeremy L Thompson // Q function 475*0b454692Sjeremylt if (!impl->is_identity_qf) { 476d1d35e2fSjeremylt ierr = CeedQFunctionApply(qf, Q, impl->q_vecs_in, impl->q_vecs_out); 477e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 47816911fdaSjeremylt } 4791d102b48SJeremy L Thompson 4801d102b48SJeremy L Thompson // Output basis apply 481d1d35e2fSjeremylt ierr = CeedOperatorOutputBasis_Ref(e, Q, qf_output_fields, op_output_fields, 482d1d35e2fSjeremylt num_input_fields, num_output_fields, op, impl); 483e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 4841d102b48SJeremy L Thompson } 485885ac19cSjeremylt 486885ac19cSjeremylt // Output restriction 487d1d35e2fSjeremylt for (CeedInt i=0; i<num_output_fields; i++) { 488d1d35e2fSjeremylt // Restore Evec 489d1d35e2fSjeremylt ierr = CeedVectorRestoreArray(impl->e_vecs[i+impl->num_e_vecs_in], 490d1d35e2fSjeremylt &impl->e_data[i + num_input_fields]); 491e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 492d1bcdac9Sjeremylt // Get output vector 493d1d35e2fSjeremylt ierr = CeedOperatorFieldGetVector(op_output_fields[i], &vec); 494e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 495668048e2SJed Brown // Active 496d1bcdac9Sjeremylt if (vec == CEED_VECTOR_ACTIVE) 497d1d35e2fSjeremylt vec = out_vec; 4987ca8db16Sjeremylt // Restrict 499d1d35e2fSjeremylt ierr = CeedOperatorFieldGetElemRestriction(op_output_fields[i], &elem_restr); 500e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 501d1d35e2fSjeremylt ierr = CeedElemRestrictionApply(elem_restr, CEED_TRANSPOSE, 502d1d35e2fSjeremylt impl->e_vecs[i+impl->num_e_vecs_in], vec, request); 503e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 504885ac19cSjeremylt } 505885ac19cSjeremylt 5067ca8db16Sjeremylt // Restore input arrays 507d1d35e2fSjeremylt ierr = CeedOperatorRestoreInputs_Ref(num_input_fields, qf_input_fields, 508d1d35e2fSjeremylt op_input_fields, false, impl); 509e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 5107ca8db16Sjeremylt 511e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 51221617c04Sjeremylt } 51321617c04Sjeremylt 514f10650afSjeremylt //------------------------------------------------------------------------------ 5151d102b48SJeremy L Thompson // Assemble Linear QFunction 516f10650afSjeremylt //------------------------------------------------------------------------------ 51780ac2e43SJeremy L Thompson static int CeedOperatorLinearAssembleQFunction_Ref(CeedOperator op, 5181d102b48SJeremy L Thompson CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) { 5191d102b48SJeremy L Thompson int ierr; 5201d102b48SJeremy L Thompson CeedOperator_Ref *impl; 521e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr); 5221d102b48SJeremy L Thompson CeedQFunction qf; 523e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr); 524d1d35e2fSjeremylt CeedInt Q, num_elem, num_input_fields, num_output_fields, size; 525e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChkBackend(ierr); 526d1d35e2fSjeremylt ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChkBackend(ierr); 527d1d35e2fSjeremylt ierr= CeedQFunctionGetNumArgs(qf, &num_input_fields, &num_output_fields); 528e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 529d1d35e2fSjeremylt CeedOperatorField *op_input_fields, *op_output_fields; 530d1d35e2fSjeremylt ierr = CeedOperatorGetFields(op, &op_input_fields, &op_output_fields); 531e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 532d1d35e2fSjeremylt CeedQFunctionField *qf_input_fields, *qf_output_fields; 533d1d35e2fSjeremylt ierr = CeedQFunctionGetFields(qf, &qf_input_fields, &qf_output_fields); 534e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 5351d102b48SJeremy L Thompson CeedVector vec; 536d1d35e2fSjeremylt CeedInt num_active_in = 0, num_active_out = 0; 537d1d35e2fSjeremylt CeedVector *active_in = NULL; 5381d102b48SJeremy L Thompson CeedScalar *a, *tmp; 539d1d35e2fSjeremylt Ceed ceed, ceed_parent; 540e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 541d1d35e2fSjeremylt ierr = CeedGetOperatorFallbackParentCeed(ceed, &ceed_parent); 542e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 543d1d35e2fSjeremylt ceed_parent = ceed_parent ? ceed_parent : ceed; 5441d102b48SJeremy L Thompson 5451d102b48SJeremy L Thompson // Setup 546e15f9bd0SJeremy L Thompson ierr = CeedOperatorSetup_Ref(op); CeedChkBackend(ierr); 5471d102b48SJeremy L Thompson 54816911fdaSjeremylt // Check for identity 549*0b454692Sjeremylt if (impl->is_identity_qf) 55016911fdaSjeremylt // LCOV_EXCL_START 551e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 552e15f9bd0SJeremy L Thompson "Assembling identity QFunctions not supported"); 55316911fdaSjeremylt // LCOV_EXCL_STOP 55416911fdaSjeremylt 5551d102b48SJeremy L Thompson // Input Evecs and Restriction 556d1d35e2fSjeremylt ierr = CeedOperatorSetupInputs_Ref(num_input_fields, qf_input_fields, 557d1d35e2fSjeremylt op_input_fields, NULL, true, impl, request); 558e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 5591d102b48SJeremy L Thompson 5601d102b48SJeremy L Thompson // Count number of active input fields 561d1d35e2fSjeremylt for (CeedInt i=0; i<num_input_fields; i++) { 5621d102b48SJeremy L Thompson // Get input vector 563d1d35e2fSjeremylt ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec); 564d1d35e2fSjeremylt CeedChkBackend(ierr); 5651d102b48SJeremy L Thompson // Check if active input 5661d102b48SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 567d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetSize(qf_input_fields[i], &size); 568e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 569d1d35e2fSjeremylt ierr = CeedVectorSetValue(impl->q_vecs_in[i], 0.0); CeedChkBackend(ierr); 570d1d35e2fSjeremylt ierr = CeedVectorGetArray(impl->q_vecs_in[i], CEED_MEM_HOST, &tmp); 571d1d35e2fSjeremylt CeedChkBackend(ierr); 572d1d35e2fSjeremylt ierr = CeedRealloc(num_active_in + size, &active_in); CeedChkBackend(ierr); 5731d102b48SJeremy L Thompson for (CeedInt field=0; field<size; field++) { 574d1d35e2fSjeremylt ierr = CeedVectorCreate(ceed, Q, &active_in[num_active_in+field]); 575e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 576d1d35e2fSjeremylt ierr = CeedVectorSetArray(active_in[num_active_in+field], CEED_MEM_HOST, 57742ea3801Sjeremylt CEED_USE_POINTER, &tmp[field*Q]); 578e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 5791d102b48SJeremy L Thompson } 580d1d35e2fSjeremylt num_active_in += size; 581d1d35e2fSjeremylt ierr = CeedVectorRestoreArray(impl->q_vecs_in[i], &tmp); CeedChkBackend(ierr); 5821d102b48SJeremy L Thompson } 5831d102b48SJeremy L Thompson } 5841d102b48SJeremy L Thompson 5851d102b48SJeremy L Thompson // Count number of active output fields 586d1d35e2fSjeremylt for (CeedInt i=0; i<num_output_fields; i++) { 5871d102b48SJeremy L Thompson // Get output vector 588d1d35e2fSjeremylt ierr = CeedOperatorFieldGetVector(op_output_fields[i], &vec); 589e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 5901d102b48SJeremy L Thompson // Check if active output 5911d102b48SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 592d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetSize(qf_output_fields[i], &size); 593e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 594d1d35e2fSjeremylt num_active_out += size; 5951d102b48SJeremy L Thompson } 5961d102b48SJeremy L Thompson } 5971d102b48SJeremy L Thompson 5981d102b48SJeremy L Thompson // Check sizes 599d1d35e2fSjeremylt if (!num_active_in || !num_active_out) 600138d4072Sjeremylt // LCOV_EXCL_START 601e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 602e15f9bd0SJeremy L Thompson "Cannot assemble QFunction without active inputs " 603138d4072Sjeremylt "and outputs"); 604138d4072Sjeremylt // LCOV_EXCL_STOP 6051d102b48SJeremy L Thompson 6061d102b48SJeremy L Thompson // Create output restriction 607d1d35e2fSjeremylt CeedInt strides[3] = {1, Q, num_active_in*num_active_out*Q}; /* *NOPAD* */ 608d1d35e2fSjeremylt ierr = CeedElemRestrictionCreateStrided(ceed_parent, num_elem, Q, 609d1d35e2fSjeremylt num_active_in*num_active_out, 610d1d35e2fSjeremylt num_active_in*num_active_out*num_elem*Q, 611e15f9bd0SJeremy L Thompson strides, rstr); CeedChkBackend(ierr); 6121d102b48SJeremy L Thompson // Create assembled vector 613d1d35e2fSjeremylt ierr = CeedVectorCreate(ceed_parent, num_elem*Q*num_active_in*num_active_out, 614e15f9bd0SJeremy L Thompson assembled); CeedChkBackend(ierr); 615e15f9bd0SJeremy L Thompson ierr = CeedVectorSetValue(*assembled, 0.0); CeedChkBackend(ierr); 616e15f9bd0SJeremy L Thompson ierr = CeedVectorGetArray(*assembled, CEED_MEM_HOST, &a); CeedChkBackend(ierr); 6171d102b48SJeremy L Thompson 6181d102b48SJeremy L Thompson // Loop through elements 619d1d35e2fSjeremylt for (CeedInt e=0; e<num_elem; e++) { 6201d102b48SJeremy L Thompson // Input basis apply 621d1d35e2fSjeremylt ierr = CeedOperatorInputBasis_Ref(e, Q, qf_input_fields, op_input_fields, 622d1d35e2fSjeremylt num_input_fields, true, impl); 623e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 6241d102b48SJeremy L Thompson 6251d102b48SJeremy L Thompson // Assemble QFunction 626d1d35e2fSjeremylt for (CeedInt in=0; in<num_active_in; in++) { 6271d102b48SJeremy L Thompson // Set Inputs 628d1d35e2fSjeremylt ierr = CeedVectorSetValue(active_in[in], 1.0); CeedChkBackend(ierr); 629d1d35e2fSjeremylt if (num_active_in > 1) { 630d1d35e2fSjeremylt ierr = CeedVectorSetValue(active_in[(in+num_active_in-1)%num_active_in], 631e15f9bd0SJeremy L Thompson 0.0); CeedChkBackend(ierr); 63242ea3801Sjeremylt } 6331d102b48SJeremy L Thompson // Set Outputs 634d1d35e2fSjeremylt for (CeedInt out=0; out<num_output_fields; out++) { 6351d102b48SJeremy L Thompson // Get output vector 636d1d35e2fSjeremylt ierr = CeedOperatorFieldGetVector(op_output_fields[out], &vec); 637e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 6381d102b48SJeremy L Thompson // Check if active output 6391d102b48SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 640d1d35e2fSjeremylt CeedVectorSetArray(impl->q_vecs_out[out], CEED_MEM_HOST, 641e15f9bd0SJeremy L Thompson CEED_USE_POINTER, a); CeedChkBackend(ierr); 642d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetSize(qf_output_fields[out], &size); 643e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 6441d102b48SJeremy L Thompson a += size*Q; // Advance the pointer by the size of the output 6451d102b48SJeremy L Thompson } 6461d102b48SJeremy L Thompson } 6471d102b48SJeremy L Thompson // Apply QFunction 648d1d35e2fSjeremylt ierr = CeedQFunctionApply(qf, Q, impl->q_vecs_in, impl->q_vecs_out); 649e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 6501d102b48SJeremy L Thompson } 6511d102b48SJeremy L Thompson } 6521d102b48SJeremy L Thompson 6531d102b48SJeremy L Thompson // Un-set output Qvecs to prevent accidental overwrite of Assembled 654d1d35e2fSjeremylt for (CeedInt out=0; out<num_output_fields; out++) { 6551d102b48SJeremy L Thompson // Get output vector 656d1d35e2fSjeremylt ierr = CeedOperatorFieldGetVector(op_output_fields[out], &vec); 657e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 6581d102b48SJeremy L Thompson // Check if active output 6591d102b48SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 660d1d35e2fSjeremylt CeedVectorTakeArray(impl->q_vecs_out[out], CEED_MEM_HOST, NULL); 661e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 6621d102b48SJeremy L Thompson } 6631d102b48SJeremy L Thompson } 6641d102b48SJeremy L Thompson 6651d102b48SJeremy L Thompson // Restore input arrays 666d1d35e2fSjeremylt ierr = CeedOperatorRestoreInputs_Ref(num_input_fields, qf_input_fields, 667d1d35e2fSjeremylt op_input_fields, true, impl); 668e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 6691d102b48SJeremy L Thompson 6701d102b48SJeremy L Thompson // Restore output 671e15f9bd0SJeremy L Thompson ierr = CeedVectorRestoreArray(*assembled, &a); CeedChkBackend(ierr); 6721d102b48SJeremy L Thompson 6731d102b48SJeremy L Thompson // Cleanup 674d1d35e2fSjeremylt for (CeedInt i=0; i<num_active_in; i++) { 675d1d35e2fSjeremylt ierr = CeedVectorDestroy(&active_in[i]); CeedChkBackend(ierr); 67642ea3801Sjeremylt } 677d1d35e2fSjeremylt ierr = CeedFree(&active_in); CeedChkBackend(ierr); 6781d102b48SJeremy L Thompson 679e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 6801d102b48SJeremy L Thompson } 6811d102b48SJeremy L Thompson 682f10650afSjeremylt //------------------------------------------------------------------------------ 683dfffd467Sjeremylt // Get Basis Emode Pointer 684dfffd467Sjeremylt //------------------------------------------------------------------------------ 685d1d35e2fSjeremylt static inline void CeedOperatorGetBasisPointer_Ref(const CeedScalar **basis_ptr, 686d1d35e2fSjeremylt CeedEvalMode eval_mode, const CeedScalar *identity, const CeedScalar *interp, 6876c58de82SJeremy L Thompson const CeedScalar *grad) { 688d1d35e2fSjeremylt switch (eval_mode) { 689dfffd467Sjeremylt case CEED_EVAL_NONE: 690d1d35e2fSjeremylt *basis_ptr = identity; 691dfffd467Sjeremylt break; 692dfffd467Sjeremylt case CEED_EVAL_INTERP: 693d1d35e2fSjeremylt *basis_ptr = interp; 694dfffd467Sjeremylt break; 695dfffd467Sjeremylt case CEED_EVAL_GRAD: 696d1d35e2fSjeremylt *basis_ptr = grad; 697dfffd467Sjeremylt break; 698dfffd467Sjeremylt case CEED_EVAL_WEIGHT: 699dfffd467Sjeremylt case CEED_EVAL_DIV: 700dfffd467Sjeremylt case CEED_EVAL_CURL: 701dfffd467Sjeremylt break; // Caught by QF Assembly 702dfffd467Sjeremylt } 703dfffd467Sjeremylt } 704dfffd467Sjeremylt 705dfffd467Sjeremylt //------------------------------------------------------------------------------ 706d965c7a7SJeremy L Thompson // Create point block restriction 707d965c7a7SJeremy L Thompson //------------------------------------------------------------------------------ 708868092e3SJeremy L Thompson static int CreatePBRestriction_Ref(CeedElemRestriction rstr, 709d1d35e2fSjeremylt CeedElemRestriction *pb_rstr) { 710d965c7a7SJeremy L Thompson int ierr; 711d965c7a7SJeremy L Thompson Ceed ceed; 712e15f9bd0SJeremy L Thompson ierr = CeedElemRestrictionGetCeed(rstr, &ceed); CeedChkBackend(ierr); 713d965c7a7SJeremy L Thompson const CeedInt *offsets; 714d965c7a7SJeremy L Thompson ierr = CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets); 715e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 716d965c7a7SJeremy L Thompson 717d965c7a7SJeremy L Thompson // Expand offsets 718d1d35e2fSjeremylt CeedInt num_elem, num_comp, elem_size, comp_stride, max = 1, *pbOffsets; 719d1d35e2fSjeremylt ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChkBackend(ierr); 720d1d35e2fSjeremylt ierr = CeedElemRestrictionGetNumComponents(rstr, &num_comp); 721e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 722d1d35e2fSjeremylt ierr = CeedElemRestrictionGetElementSize(rstr, &elem_size); 723d1d35e2fSjeremylt CeedChkBackend(ierr); 724d1d35e2fSjeremylt ierr = CeedElemRestrictionGetCompStride(rstr, &comp_stride); 725d1d35e2fSjeremylt CeedChkBackend(ierr); 726d1d35e2fSjeremylt CeedInt shift = num_comp; 727d1d35e2fSjeremylt if (comp_stride != 1) 728d1d35e2fSjeremylt shift *= num_comp; 729d1d35e2fSjeremylt ierr = CeedCalloc(num_elem*elem_size, &pbOffsets); CeedChkBackend(ierr); 730d1d35e2fSjeremylt for (CeedInt i = 0; i < num_elem*elem_size; i++) { 731d965c7a7SJeremy L Thompson pbOffsets[i] = offsets[i]*shift; 732d965c7a7SJeremy L Thompson if (pbOffsets[i] > max) 733d965c7a7SJeremy L Thompson max = pbOffsets[i]; 734d965c7a7SJeremy L Thompson } 735d965c7a7SJeremy L Thompson 736d965c7a7SJeremy L Thompson // Create new restriction 737d1d35e2fSjeremylt ierr = CeedElemRestrictionCreate(ceed, num_elem, elem_size, num_comp*num_comp, 738d1d35e2fSjeremylt 1, 739d1d35e2fSjeremylt max + num_comp*num_comp, CEED_MEM_HOST, 740d1d35e2fSjeremylt CEED_OWN_POINTER, pbOffsets, pb_rstr); 741e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 742d965c7a7SJeremy L Thompson 743d965c7a7SJeremy L Thompson // Cleanup 744e15f9bd0SJeremy L Thompson ierr = CeedElemRestrictionRestoreOffsets(rstr, &offsets); CeedChkBackend(ierr); 745d965c7a7SJeremy L Thompson 746e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 747d965c7a7SJeremy L Thompson } 748d965c7a7SJeremy L Thompson 749d965c7a7SJeremy L Thompson //------------------------------------------------------------------------------ 750c04a41a7SJeremy L Thompson // Assemble diagonal common code 751f10650afSjeremylt //------------------------------------------------------------------------------ 75269af5e5fSJeremy L Thompson static inline int CeedOperatorAssembleAddDiagonalCore_Ref(CeedOperator op, 753d1d35e2fSjeremylt CeedVector assembled, CeedRequest *request, const bool is_pointblock) { 7547172caadSjeremylt int ierr; 755c04a41a7SJeremy L Thompson Ceed ceed; 756e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 7577172caadSjeremylt 7587172caadSjeremylt // Assemble QFunction 7597172caadSjeremylt CeedQFunction qf; 760e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr); 761d1d35e2fSjeremylt CeedInt num_input_fields, num_output_fields; 762d1d35e2fSjeremylt ierr= CeedQFunctionGetNumArgs(qf, &num_input_fields, &num_output_fields); 763e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 764d1d35e2fSjeremylt CeedVector assembled_qf; 7657172caadSjeremylt CeedElemRestriction rstr; 766d1d35e2fSjeremylt ierr = CeedOperatorLinearAssembleQFunction(op, &assembled_qf, &rstr, request); 767e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 768e15f9bd0SJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr); CeedChkBackend(ierr); 769d1d35e2fSjeremylt CeedScalar max_norm = 0; 770d1d35e2fSjeremylt ierr = CeedVectorNorm(assembled_qf, CEED_NORM_MAX, &max_norm); 771e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 7727172caadSjeremylt 7737172caadSjeremylt // Determine active input basis 774d1d35e2fSjeremylt CeedOperatorField *op_fields; 775d1d35e2fSjeremylt CeedQFunctionField *qf_fields; 776d1d35e2fSjeremylt ierr = CeedOperatorGetFields(op, &op_fields, NULL); CeedChkBackend(ierr); 777d1d35e2fSjeremylt ierr = CeedQFunctionGetFields(qf, &qf_fields, NULL); CeedChkBackend(ierr); 778d1d35e2fSjeremylt CeedInt num_eval_mode_in = 0, num_comp, dim = 1; 779d1d35e2fSjeremylt CeedEvalMode *eval_mode_in = NULL; 780d1d35e2fSjeremylt CeedBasis basis_in = NULL; 781d1d35e2fSjeremylt CeedElemRestriction rstr_in = NULL; 782d1d35e2fSjeremylt for (CeedInt i=0; i<num_input_fields; i++) { 7837172caadSjeremylt CeedVector vec; 784d1d35e2fSjeremylt ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChkBackend(ierr); 7857172caadSjeremylt if (vec == CEED_VECTOR_ACTIVE) { 786c04a41a7SJeremy L Thompson CeedElemRestriction rstr; 787d1d35e2fSjeremylt ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis_in); CeedChkBackend(ierr); 788d1d35e2fSjeremylt ierr = CeedBasisGetNumComponents(basis_in, &num_comp); CeedChkBackend(ierr); 789d1d35e2fSjeremylt ierr = CeedBasisGetDimension(basis_in, &dim); CeedChkBackend(ierr); 790d1d35e2fSjeremylt ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr); 791e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 792d1d35e2fSjeremylt if (rstr_in && rstr_in != rstr) 793c04a41a7SJeremy L Thompson // LCOV_EXCL_START 794e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 795c04a41a7SJeremy L Thompson "Multi-field non-composite operator diagonal assembly not supported"); 796c04a41a7SJeremy L Thompson // LCOV_EXCL_STOP 797d1d35e2fSjeremylt rstr_in = rstr; 798d1d35e2fSjeremylt CeedEvalMode eval_mode; 799d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); 800e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 801d1d35e2fSjeremylt switch (eval_mode) { 8027172caadSjeremylt case CEED_EVAL_NONE: 8037172caadSjeremylt case CEED_EVAL_INTERP: 804d1d35e2fSjeremylt ierr = CeedRealloc(num_eval_mode_in + 1, &eval_mode_in); CeedChkBackend(ierr); 805d1d35e2fSjeremylt eval_mode_in[num_eval_mode_in] = eval_mode; 806d1d35e2fSjeremylt num_eval_mode_in += 1; 8077172caadSjeremylt break; 8087172caadSjeremylt case CEED_EVAL_GRAD: 809d1d35e2fSjeremylt ierr = CeedRealloc(num_eval_mode_in + dim, &eval_mode_in); CeedChkBackend(ierr); 8107172caadSjeremylt for (CeedInt d=0; d<dim; d++) 811d1d35e2fSjeremylt eval_mode_in[num_eval_mode_in+d] = eval_mode; 812d1d35e2fSjeremylt num_eval_mode_in += dim; 8137172caadSjeremylt break; 8147172caadSjeremylt case CEED_EVAL_WEIGHT: 8157172caadSjeremylt case CEED_EVAL_DIV: 8167172caadSjeremylt case CEED_EVAL_CURL: 8177172caadSjeremylt break; // Caught by QF Assembly 8187172caadSjeremylt } 8197172caadSjeremylt } 8207172caadSjeremylt } 8217172caadSjeremylt 8227172caadSjeremylt // Determine active output basis 823d1d35e2fSjeremylt ierr = CeedOperatorGetFields(op, NULL, &op_fields); CeedChkBackend(ierr); 824d1d35e2fSjeremylt ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields); CeedChkBackend(ierr); 825d1d35e2fSjeremylt CeedInt num_eval_mode_out = 0; 826d1d35e2fSjeremylt CeedEvalMode *eval_mode_out = NULL; 827d1d35e2fSjeremylt CeedBasis basis_out = NULL; 828d1d35e2fSjeremylt CeedElemRestriction rstr_out = NULL; 829d1d35e2fSjeremylt for (CeedInt i=0; i<num_output_fields; i++) { 8307172caadSjeremylt CeedVector vec; 831d1d35e2fSjeremylt ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChkBackend(ierr); 8327172caadSjeremylt if (vec == CEED_VECTOR_ACTIVE) { 833c04a41a7SJeremy L Thompson CeedElemRestriction rstr; 834d1d35e2fSjeremylt ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis_out); 835e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 836d1d35e2fSjeremylt ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr); 837d1d35e2fSjeremylt CeedChkBackend(ierr); 838d1d35e2fSjeremylt if (rstr_out && rstr_out != rstr) 839c04a41a7SJeremy L Thompson // LCOV_EXCL_START 840e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 841c04a41a7SJeremy L Thompson "Multi-field non-composite operator diagonal assembly not supported"); 842c04a41a7SJeremy L Thompson // LCOV_EXCL_STOP 843d1d35e2fSjeremylt rstr_out = rstr; 844d1d35e2fSjeremylt CeedEvalMode eval_mode; 845d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); 846d1d35e2fSjeremylt CeedChkBackend(ierr); 847d1d35e2fSjeremylt switch (eval_mode) { 8487172caadSjeremylt case CEED_EVAL_NONE: 8497172caadSjeremylt case CEED_EVAL_INTERP: 850d1d35e2fSjeremylt ierr = CeedRealloc(num_eval_mode_out + 1, &eval_mode_out); CeedChkBackend(ierr); 851d1d35e2fSjeremylt eval_mode_out[num_eval_mode_out] = eval_mode; 852d1d35e2fSjeremylt num_eval_mode_out += 1; 8537172caadSjeremylt break; 8547172caadSjeremylt case CEED_EVAL_GRAD: 855d1d35e2fSjeremylt ierr = CeedRealloc(num_eval_mode_out + dim, &eval_mode_out); 856d1d35e2fSjeremylt CeedChkBackend(ierr); 8577172caadSjeremylt for (CeedInt d=0; d<dim; d++) 858d1d35e2fSjeremylt eval_mode_out[num_eval_mode_out+d] = eval_mode; 859d1d35e2fSjeremylt num_eval_mode_out += dim; 8607172caadSjeremylt break; 8617172caadSjeremylt case CEED_EVAL_WEIGHT: 8627172caadSjeremylt case CEED_EVAL_DIV: 8637172caadSjeremylt case CEED_EVAL_CURL: 8647172caadSjeremylt break; // Caught by QF Assembly 8657172caadSjeremylt } 8667172caadSjeremylt } 8677172caadSjeremylt } 8687172caadSjeremylt 869d965c7a7SJeremy L Thompson // Assemble point-block diagonal restriction, if needed 870d1d35e2fSjeremylt CeedElemRestriction diag_rstr = rstr_out; 871d1d35e2fSjeremylt if (is_pointblock) { 872d1d35e2fSjeremylt ierr = CreatePBRestriction_Ref(rstr_out, &diag_rstr); CeedChkBackend(ierr); 873d965c7a7SJeremy L Thompson } 874d965c7a7SJeremy L Thompson 8757172caadSjeremylt // Create diagonal vector 876d1d35e2fSjeremylt CeedVector elem_diag; 877d1d35e2fSjeremylt ierr = CeedElemRestrictionCreateVector(diag_rstr, NULL, &elem_diag); 878e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 8797172caadSjeremylt 8807172caadSjeremylt // Assemble element operator diagonals 881d1d35e2fSjeremylt CeedScalar *elem_diag_array, *assembled_qf_array; 882d1d35e2fSjeremylt ierr = CeedVectorSetValue(elem_diag, 0.0); CeedChkBackend(ierr); 883d1d35e2fSjeremylt ierr = CeedVectorGetArray(elem_diag, CEED_MEM_HOST, &elem_diag_array); 884e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 885d1d35e2fSjeremylt ierr = CeedVectorGetArray(assembled_qf, CEED_MEM_HOST, &assembled_qf_array); 886e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 887d1d35e2fSjeremylt CeedInt num_elem, num_nodes, num_qpts; 888d1d35e2fSjeremylt ierr = CeedElemRestrictionGetNumElements(diag_rstr, &num_elem); 889e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 890d1d35e2fSjeremylt ierr = CeedBasisGetNumNodes(basis_in, &num_nodes); CeedChkBackend(ierr); 891d1d35e2fSjeremylt ierr = CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts); 892d1d35e2fSjeremylt CeedChkBackend(ierr); 893dfffd467Sjeremylt // Basis matrices 894d1d35e2fSjeremylt const CeedScalar *interp_in, *interp_out, *grad_in, *grad_out; 8956c58de82SJeremy L Thompson CeedScalar *identity = NULL; 896dfffd467Sjeremylt bool evalNone = false; 897d1d35e2fSjeremylt for (CeedInt i=0; i<num_eval_mode_in; i++) 898d1d35e2fSjeremylt evalNone = evalNone || (eval_mode_in[i] == CEED_EVAL_NONE); 899d1d35e2fSjeremylt for (CeedInt i=0; i<num_eval_mode_out; i++) 900d1d35e2fSjeremylt evalNone = evalNone || (eval_mode_out[i] == CEED_EVAL_NONE); 901dfffd467Sjeremylt if (evalNone) { 902d1d35e2fSjeremylt ierr = CeedCalloc(num_qpts*num_nodes, &identity); CeedChkBackend(ierr); 903d1d35e2fSjeremylt for (CeedInt i=0; i<(num_nodes<num_qpts?num_nodes:num_qpts); i++) 904d1d35e2fSjeremylt identity[i*num_nodes+i] = 1.0; 905dfffd467Sjeremylt } 906d1d35e2fSjeremylt ierr = CeedBasisGetInterp(basis_in, &interp_in); CeedChkBackend(ierr); 907d1d35e2fSjeremylt ierr = CeedBasisGetInterp(basis_out, &interp_out); CeedChkBackend(ierr); 908d1d35e2fSjeremylt ierr = CeedBasisGetGrad(basis_in, &grad_in); CeedChkBackend(ierr); 909d1d35e2fSjeremylt ierr = CeedBasisGetGrad(basis_out, &grad_out); CeedChkBackend(ierr); 910dfffd467Sjeremylt // Compute the diagonal of B^T D B 911dfffd467Sjeremylt // Each element 912d1d35e2fSjeremylt const CeedScalar qf_value_bound = max_norm*1e-12; 913d1d35e2fSjeremylt for (CeedInt e=0; e<num_elem; e++) { 914d1d35e2fSjeremylt CeedInt d_out = -1; 9157172caadSjeremylt // Each basis eval mode pair 916d1d35e2fSjeremylt for (CeedInt e_out=0; e_out<num_eval_mode_out; e_out++) { 9176c58de82SJeremy L Thompson const CeedScalar *bt = NULL; 918d1d35e2fSjeremylt if (eval_mode_out[e_out] == CEED_EVAL_GRAD) 919d1d35e2fSjeremylt d_out += 1; 920d1d35e2fSjeremylt CeedOperatorGetBasisPointer_Ref(&bt, eval_mode_out[e_out], identity, interp_out, 921d1d35e2fSjeremylt &grad_out[d_out*num_qpts*num_nodes]); 922d1d35e2fSjeremylt CeedInt d_in = -1; 923d1d35e2fSjeremylt for (CeedInt e_in=0; e_in<num_eval_mode_in; e_in++) { 9246c58de82SJeremy L Thompson const CeedScalar *b = NULL; 925d1d35e2fSjeremylt if (eval_mode_in[e_in] == CEED_EVAL_GRAD) 926d1d35e2fSjeremylt d_in += 1; 927d1d35e2fSjeremylt CeedOperatorGetBasisPointer_Ref(&b, eval_mode_in[e_in], identity, interp_in, 928d1d35e2fSjeremylt &grad_in[d_in*num_qpts*num_nodes]); 929efcf4563Sjeremylt // Each component 930d1d35e2fSjeremylt for (CeedInt c_out=0; c_out<num_comp; c_out++) 931dfffd467Sjeremylt // Each qpoint/node pair 932d1d35e2fSjeremylt for (CeedInt q=0; q<num_qpts; q++) 933d1d35e2fSjeremylt if (is_pointblock) { 934d965c7a7SJeremy L Thompson // Point Block Diagonal 935d1d35e2fSjeremylt for (CeedInt c_in=0; c_in<num_comp; c_in++) { 936d1d35e2fSjeremylt const CeedScalar qf_value = 937d1d35e2fSjeremylt assembled_qf_array[((((e*num_eval_mode_in+e_in)*num_comp+c_in)* 938d1d35e2fSjeremylt num_eval_mode_out+e_out)*num_comp+c_out)*num_qpts+q]; 939d1d35e2fSjeremylt if (fabs(qf_value) > qf_value_bound) 940d1d35e2fSjeremylt for (CeedInt n=0; n<num_nodes; n++) 941d1d35e2fSjeremylt elem_diag_array[((e*num_comp+c_out)*num_comp+c_in)*num_nodes+n] += 942d1d35e2fSjeremylt bt[q*num_nodes+n] * qf_value * b[q*num_nodes+n]; 943d965c7a7SJeremy L Thompson } 944d965c7a7SJeremy L Thompson } else { 945d965c7a7SJeremy L Thompson // Diagonal Only 946d1d35e2fSjeremylt const CeedScalar qf_value = 947d1d35e2fSjeremylt assembled_qf_array[((((e*num_eval_mode_in+e_in)*num_comp+c_out)* 948d1d35e2fSjeremylt num_eval_mode_out+e_out)*num_comp+c_out)*num_qpts+q]; 949d1d35e2fSjeremylt if (fabs(qf_value) > qf_value_bound) 950d1d35e2fSjeremylt for (CeedInt n=0; n<num_nodes; n++) 951d1d35e2fSjeremylt elem_diag_array[(e*num_comp+c_out)*num_nodes+n] += 952d1d35e2fSjeremylt bt[q*num_nodes+n] * qf_value * b[q*num_nodes+n]; 9534ff7492eSjeremylt } 9547172caadSjeremylt } 9557172caadSjeremylt } 9567172caadSjeremylt } 957d1d35e2fSjeremylt ierr = CeedVectorRestoreArray(elem_diag, &elem_diag_array); 958d1d35e2fSjeremylt CeedChkBackend(ierr); 959d1d35e2fSjeremylt ierr = CeedVectorRestoreArray(assembled_qf, &assembled_qf_array); 960e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 9617172caadSjeremylt 9627172caadSjeremylt // Assemble local operator diagonal 963d1d35e2fSjeremylt ierr = CeedElemRestrictionApply(diag_rstr, CEED_TRANSPOSE, elem_diag, 964e15f9bd0SJeremy L Thompson assembled, request); CeedChkBackend(ierr); 9657172caadSjeremylt 9667172caadSjeremylt // Cleanup 967d1d35e2fSjeremylt if (is_pointblock) { 968d1d35e2fSjeremylt ierr = CeedElemRestrictionDestroy(&diag_rstr); CeedChkBackend(ierr); 969d965c7a7SJeremy L Thompson } 970d1d35e2fSjeremylt ierr = CeedVectorDestroy(&assembled_qf); CeedChkBackend(ierr); 971d1d35e2fSjeremylt ierr = CeedVectorDestroy(&elem_diag); CeedChkBackend(ierr); 972d1d35e2fSjeremylt ierr = CeedFree(&eval_mode_in); CeedChkBackend(ierr); 973d1d35e2fSjeremylt ierr = CeedFree(&eval_mode_out); CeedChkBackend(ierr); 974e15f9bd0SJeremy L Thompson ierr = CeedFree(&identity); CeedChkBackend(ierr); 9757172caadSjeremylt 976e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 9777172caadSjeremylt } 9787172caadSjeremylt 979f10650afSjeremylt //------------------------------------------------------------------------------ 980c04a41a7SJeremy L Thompson // Assemble composite diagonal common code 981c04a41a7SJeremy L Thompson //------------------------------------------------------------------------------ 98269af5e5fSJeremy L Thompson static inline int CeedOperatorLinearAssembleAddDiagonalCompositeCore_Ref( 9832bba3ffaSJeremy L Thompson CeedOperator op, CeedVector assembled, CeedRequest *request, 984d1d35e2fSjeremylt const bool is_pointblock) { 985c04a41a7SJeremy L Thompson int ierr; 986d1d35e2fSjeremylt CeedInt num_sub; 987d1d35e2fSjeremylt CeedOperator *suboperators; 988d1d35e2fSjeremylt ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChkBackend(ierr); 989d1d35e2fSjeremylt ierr = CeedOperatorGetSubList(op, &suboperators); CeedChkBackend(ierr); 990d1d35e2fSjeremylt for (CeedInt i = 0; i < num_sub; i++) { 991d1d35e2fSjeremylt ierr = CeedOperatorAssembleAddDiagonalCore_Ref(suboperators[i], assembled, 992d1d35e2fSjeremylt request, is_pointblock); CeedChkBackend(ierr); 993c04a41a7SJeremy L Thompson } 994e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 995c04a41a7SJeremy L Thompson } 996c04a41a7SJeremy L Thompson 997c04a41a7SJeremy L Thompson //------------------------------------------------------------------------------ 998d965c7a7SJeremy L Thompson // Assemble Linear Diagonal 999d965c7a7SJeremy L Thompson //------------------------------------------------------------------------------ 100069af5e5fSJeremy L Thompson static int CeedOperatorLinearAssembleAddDiagonal_Ref(CeedOperator op, 10012bba3ffaSJeremy L Thompson CeedVector assembled, CeedRequest *request) { 1002c04a41a7SJeremy L Thompson int ierr; 1003d1d35e2fSjeremylt bool is_composite; 1004d1d35e2fSjeremylt ierr = CeedOperatorIsComposite(op, &is_composite); CeedChkBackend(ierr); 1005d1d35e2fSjeremylt if (is_composite) { 100669af5e5fSJeremy L Thompson return CeedOperatorLinearAssembleAddDiagonalCompositeCore_Ref(op, assembled, 1007c04a41a7SJeremy L Thompson request, false); 1008c04a41a7SJeremy L Thompson } else { 100969af5e5fSJeremy L Thompson return CeedOperatorAssembleAddDiagonalCore_Ref(op, assembled, request, false); 1010c04a41a7SJeremy L Thompson } 1011d965c7a7SJeremy L Thompson } 1012d965c7a7SJeremy L Thompson 1013d965c7a7SJeremy L Thompson //------------------------------------------------------------------------------ 1014d965c7a7SJeremy L Thompson // Assemble Linear Point Block Diagonal 1015d965c7a7SJeremy L Thompson //------------------------------------------------------------------------------ 101669af5e5fSJeremy L Thompson static int CeedOperatorLinearAssembleAddPointBlockDiagonal_Ref(CeedOperator op, 10172bba3ffaSJeremy L Thompson CeedVector assembled, CeedRequest *request) { 1018c04a41a7SJeremy L Thompson int ierr; 1019d1d35e2fSjeremylt bool is_composite; 1020d1d35e2fSjeremylt ierr = CeedOperatorIsComposite(op, &is_composite); CeedChkBackend(ierr); 1021d1d35e2fSjeremylt if (is_composite) { 102269af5e5fSJeremy L Thompson return CeedOperatorLinearAssembleAddDiagonalCompositeCore_Ref(op, assembled, 1023c04a41a7SJeremy L Thompson request, true); 1024c04a41a7SJeremy L Thompson } else { 102569af5e5fSJeremy L Thompson return CeedOperatorAssembleAddDiagonalCore_Ref(op, assembled, request, true); 1026c04a41a7SJeremy L Thompson } 1027d965c7a7SJeremy L Thompson } 1028d965c7a7SJeremy L Thompson 1029d965c7a7SJeremy L Thompson //------------------------------------------------------------------------------ 1030713f43c3Sjeremylt // Create FDM Element Inverse 1031f10650afSjeremylt //------------------------------------------------------------------------------ 1032713f43c3Sjeremylt int CeedOperatorCreateFDMElementInverse_Ref(CeedOperator op, 1033d1d35e2fSjeremylt CeedOperator *fdm_inv, CeedRequest *request) { 1034713f43c3Sjeremylt int ierr; 1035d1d35e2fSjeremylt Ceed ceed, ceed_parent; 1036e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 1037d1d35e2fSjeremylt ierr = CeedGetOperatorFallbackParentCeed(ceed, &ceed_parent); 1038e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1039d1d35e2fSjeremylt ceed_parent = ceed_parent ? ceed_parent : ceed; 1040713f43c3Sjeremylt CeedQFunction qf; 1041e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr); 1042713f43c3Sjeremylt 1043713f43c3Sjeremylt // Determine active input basis 1044713f43c3Sjeremylt bool interp = false, grad = false; 1045713f43c3Sjeremylt CeedBasis basis = NULL; 1046713f43c3Sjeremylt CeedElemRestriction rstr = NULL; 1047d1d35e2fSjeremylt CeedOperatorField *op_fields; 1048d1d35e2fSjeremylt CeedQFunctionField *qf_fields; 1049d1d35e2fSjeremylt ierr = CeedOperatorGetFields(op, &op_fields, NULL); CeedChkBackend(ierr); 1050d1d35e2fSjeremylt ierr = CeedQFunctionGetFields(qf, &qf_fields, NULL); CeedChkBackend(ierr); 1051d1d35e2fSjeremylt CeedInt num_input_fields; 1052d1d35e2fSjeremylt ierr = CeedQFunctionGetNumArgs(qf, &num_input_fields, NULL); 1053d1d35e2fSjeremylt CeedChkBackend(ierr); 1054d1d35e2fSjeremylt for (CeedInt i=0; i<num_input_fields; i++) { 1055713f43c3Sjeremylt CeedVector vec; 1056d1d35e2fSjeremylt ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChkBackend(ierr); 1057713f43c3Sjeremylt if (vec == CEED_VECTOR_ACTIVE) { 1058d1d35e2fSjeremylt CeedEvalMode eval_mode; 1059d1d35e2fSjeremylt ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); 1060d1d35e2fSjeremylt CeedChkBackend(ierr); 1061d1d35e2fSjeremylt interp = interp || eval_mode == CEED_EVAL_INTERP; 1062d1d35e2fSjeremylt grad = grad || eval_mode == CEED_EVAL_GRAD; 1063d1d35e2fSjeremylt ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis); CeedChkBackend(ierr); 1064d1d35e2fSjeremylt ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr); 1065e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1066713f43c3Sjeremylt } 1067713f43c3Sjeremylt } 1068713f43c3Sjeremylt if (!basis) 1069d9995aecSjeremylt // LCOV_EXCL_START 1070e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "No active field set"); 1071d9995aecSjeremylt // LCOV_EXCL_STOP 1072d1d35e2fSjeremylt CeedInt P_1d, Q_1d, elem_size, num_qpts, dim, num_comp = 1, num_elem = 1, 1073d1d35e2fSjeremylt l_size = 1; 1074d1d35e2fSjeremylt ierr = CeedBasisGetNumNodes1D(basis, &P_1d); CeedChkBackend(ierr); 1075d1d35e2fSjeremylt ierr = CeedBasisGetNumNodes(basis, &elem_size); CeedChkBackend(ierr); 1076d1d35e2fSjeremylt ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d); CeedChkBackend(ierr); 1077d1d35e2fSjeremylt ierr = CeedBasisGetNumQuadraturePoints(basis, &num_qpts); CeedChkBackend(ierr); 1078e15f9bd0SJeremy L Thompson ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr); 1079d1d35e2fSjeremylt ierr = CeedBasisGetNumComponents(basis, &num_comp); CeedChkBackend(ierr); 1080d1d35e2fSjeremylt ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChkBackend(ierr); 1081d1d35e2fSjeremylt ierr = CeedElemRestrictionGetLVectorSize(rstr, &l_size); CeedChkBackend(ierr); 1082713f43c3Sjeremylt 1083713f43c3Sjeremylt // Build and diagonalize 1D Mass and Laplacian 1084d1d35e2fSjeremylt bool tensor_basis; 1085d1d35e2fSjeremylt ierr = CeedBasisIsTensor(basis, &tensor_basis); CeedChkBackend(ierr); 1086d1d35e2fSjeremylt if (!tensor_basis) 1087d9995aecSjeremylt // LCOV_EXCL_START 1088e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 1089e15f9bd0SJeremy L Thompson "FDMElementInverse only supported for tensor " 1090713f43c3Sjeremylt "bases"); 1091d9995aecSjeremylt // LCOV_EXCL_STOP 1092713f43c3Sjeremylt CeedScalar *work, *mass, *laplace, *x, *x2, *lambda; 1093d1d35e2fSjeremylt ierr = CeedMalloc(Q_1d*P_1d, &work); CeedChkBackend(ierr); 1094d1d35e2fSjeremylt ierr = CeedMalloc(P_1d*P_1d, &mass); CeedChkBackend(ierr); 1095d1d35e2fSjeremylt ierr = CeedMalloc(P_1d*P_1d, &laplace); CeedChkBackend(ierr); 1096d1d35e2fSjeremylt ierr = CeedMalloc(P_1d*P_1d, &x); CeedChkBackend(ierr); 1097d1d35e2fSjeremylt ierr = CeedMalloc(P_1d*P_1d, &x2); CeedChkBackend(ierr); 1098d1d35e2fSjeremylt ierr = CeedMalloc(P_1d, &lambda); CeedChkBackend(ierr); 1099713f43c3Sjeremylt // -- Mass 1100d1d35e2fSjeremylt const CeedScalar *interp_1d, *grad_1d, *q_weight_1d; 1101d1d35e2fSjeremylt ierr = CeedBasisGetInterp1D(basis, &interp_1d); CeedChkBackend(ierr); 1102d1d35e2fSjeremylt ierr = CeedBasisGetGrad1D(basis, &grad_1d); CeedChkBackend(ierr); 1103d1d35e2fSjeremylt ierr = CeedBasisGetQWeights(basis, &q_weight_1d); CeedChkBackend(ierr); 1104d1d35e2fSjeremylt for (CeedInt i=0; i<Q_1d; i++) 1105d1d35e2fSjeremylt for (CeedInt j=0; j<P_1d; j++) 1106d1d35e2fSjeremylt work[i+j*Q_1d] = interp_1d[i*P_1d+j]*q_weight_1d[i]; 11079289e5bfSjeremylt ierr = CeedMatrixMultiply(ceed, (const CeedScalar *)work, 1108d1d35e2fSjeremylt (const CeedScalar *)interp_1d, mass, P_1d, P_1d, Q_1d); 1109e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1110713f43c3Sjeremylt // -- Laplacian 1111d1d35e2fSjeremylt for (CeedInt i=0; i<Q_1d; i++) 1112d1d35e2fSjeremylt for (CeedInt j=0; j<P_1d; j++) 1113d1d35e2fSjeremylt work[i+j*Q_1d] = grad_1d[i*P_1d+j]*q_weight_1d[i]; 11149289e5bfSjeremylt ierr = CeedMatrixMultiply(ceed, (const CeedScalar *)work, 1115d1d35e2fSjeremylt (const CeedScalar *)grad_1d, laplace, P_1d, P_1d, Q_1d); 1116e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1117713f43c3Sjeremylt // -- Diagonalize 1118d1d35e2fSjeremylt ierr = CeedSimultaneousDiagonalization(ceed, laplace, mass, x, lambda, P_1d); 1119e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1120e15f9bd0SJeremy L Thompson ierr = CeedFree(&work); CeedChkBackend(ierr); 1121e15f9bd0SJeremy L Thompson ierr = CeedFree(&mass); CeedChkBackend(ierr); 1122e15f9bd0SJeremy L Thompson ierr = CeedFree(&laplace); CeedChkBackend(ierr); 1123d1d35e2fSjeremylt for (CeedInt i=0; i<P_1d; i++) 1124d1d35e2fSjeremylt for (CeedInt j=0; j<P_1d; j++) 1125d1d35e2fSjeremylt x2[i+j*P_1d] = x[j+i*P_1d]; 1126e15f9bd0SJeremy L Thompson ierr = CeedFree(&x); CeedChkBackend(ierr); 1127713f43c3Sjeremylt 1128713f43c3Sjeremylt // Assemble QFunction 1129713f43c3Sjeremylt CeedVector assembled; 1130713f43c3Sjeremylt CeedElemRestriction rstr_qf; 113180ac2e43SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunction(op, &assembled, &rstr_qf, 1132e15f9bd0SJeremy L Thompson request); CeedChkBackend(ierr); 1133e15f9bd0SJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr_qf); CeedChkBackend(ierr); 1134d1d35e2fSjeremylt CeedScalar max_norm = 0; 1135d1d35e2fSjeremylt ierr = CeedVectorNorm(assembled, CEED_NORM_MAX, &max_norm); 1136d1d35e2fSjeremylt CeedChkBackend(ierr); 1137713f43c3Sjeremylt 1138713f43c3Sjeremylt // Calculate element averages 1139d1d35e2fSjeremylt CeedInt num_fields = ((interp?1:0) + (grad?dim:0))*((interp?1:0) + 1140d1d35e2fSjeremylt (grad?dim:0)); 1141d1d35e2fSjeremylt CeedScalar *elem_avg; 1142d1d35e2fSjeremylt const CeedScalar *assembledarray, *q_weight_array; 1143d1d35e2fSjeremylt CeedVector q_weight; 1144d1d35e2fSjeremylt ierr = CeedVectorCreate(ceed_parent, num_qpts, &q_weight); CeedChkBackend(ierr); 1145713f43c3Sjeremylt ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, 1146d1d35e2fSjeremylt CEED_VECTOR_NONE, q_weight); CeedChkBackend(ierr); 1147713f43c3Sjeremylt ierr = CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembledarray); 1148e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1149d1d35e2fSjeremylt ierr = CeedVectorGetArrayRead(q_weight, CEED_MEM_HOST, &q_weight_array); 1150e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1151d1d35e2fSjeremylt ierr = CeedCalloc(num_elem, &elem_avg); CeedChkBackend(ierr); 1152d1d35e2fSjeremylt for (CeedInt e=0; e<num_elem; e++) { 1153713f43c3Sjeremylt CeedInt count = 0; 1154d1d35e2fSjeremylt for (CeedInt q=0; q<num_qpts; q++) 1155d1d35e2fSjeremylt for (CeedInt i=0; i<num_comp*num_comp*num_fields; i++) 1156d1d35e2fSjeremylt if (fabs(assembledarray[e*num_elem*num_qpts*num_comp*num_comp*num_fields + 1157d1d35e2fSjeremylt i*num_qpts + q]) > max_norm*1e-12) { 1158d1d35e2fSjeremylt elem_avg[e] += assembledarray[e*num_elem*num_qpts*num_comp*num_comp*num_fields + 1159d1d35e2fSjeremylt i*num_qpts + q] / q_weight_array[q]; 1160713f43c3Sjeremylt count++; 1161713f43c3Sjeremylt } 1162713f43c3Sjeremylt if (count) 1163d1d35e2fSjeremylt elem_avg[e] /= count; 1164713f43c3Sjeremylt } 1165e15f9bd0SJeremy L Thompson ierr = CeedVectorRestoreArrayRead(assembled, &assembledarray); 1166e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1167e15f9bd0SJeremy L Thompson ierr = CeedVectorDestroy(&assembled); CeedChkBackend(ierr); 1168d1d35e2fSjeremylt ierr = CeedVectorRestoreArrayRead(q_weight, &q_weight_array); 1169e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1170d1d35e2fSjeremylt ierr = CeedVectorDestroy(&q_weight); CeedChkBackend(ierr); 1171713f43c3Sjeremylt 1172713f43c3Sjeremylt // Build FDM diagonal 1173d1d35e2fSjeremylt CeedVector q_data; 1174d1d35e2fSjeremylt CeedScalar *q_data_array; 1175d1d35e2fSjeremylt ierr = CeedVectorCreate(ceed_parent, num_elem*num_comp*l_size, &q_data); 1176e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1177d1d35e2fSjeremylt ierr = CeedVectorSetArray(q_data, CEED_MEM_HOST, CEED_COPY_VALUES, NULL); 1178e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1179d1d35e2fSjeremylt ierr = CeedVectorGetArray(q_data, CEED_MEM_HOST, &q_data_array); 1180e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1181d1d35e2fSjeremylt for (CeedInt e=0; e<num_elem; e++) 1182d1d35e2fSjeremylt for (CeedInt c=0; c<num_comp; c++) 1183d1d35e2fSjeremylt for (CeedInt n=0; n<l_size; n++) { 1184713f43c3Sjeremylt if (interp) 1185d1d35e2fSjeremylt q_data_array[(e*num_comp+c)*l_size+n] = 1; 1186713f43c3Sjeremylt if (grad) 1187713f43c3Sjeremylt for (CeedInt d=0; d<dim; d++) { 1188d1d35e2fSjeremylt CeedInt i = (n / CeedIntPow(P_1d, d)) % P_1d; 1189d1d35e2fSjeremylt q_data_array[(e*num_comp+c)*l_size+n] += lambda[i]; 1190713f43c3Sjeremylt } 1191d1d35e2fSjeremylt q_data_array[(e*num_comp+c)*l_size+n] = 1 / (elem_avg[e] * 1192d1d35e2fSjeremylt q_data_array[(e*num_comp+c)*l_size+n]); 1193713f43c3Sjeremylt } 1194d1d35e2fSjeremylt ierr = CeedFree(&elem_avg); CeedChkBackend(ierr); 1195d1d35e2fSjeremylt ierr = CeedVectorRestoreArray(q_data, &q_data_array); CeedChkBackend(ierr); 1196713f43c3Sjeremylt 1197713f43c3Sjeremylt // Setup FDM operator 1198713f43c3Sjeremylt // -- Basis 1199713f43c3Sjeremylt CeedBasis fdm_basis; 1200d1d35e2fSjeremylt CeedScalar *grad_dummy, *q_ref_dummy, *q_weight_dummy; 1201d1d35e2fSjeremylt ierr = CeedCalloc(P_1d*P_1d, &grad_dummy); CeedChkBackend(ierr); 1202d1d35e2fSjeremylt ierr = CeedCalloc(P_1d, &q_ref_dummy); CeedChkBackend(ierr); 1203d1d35e2fSjeremylt ierr = CeedCalloc(P_1d, &q_weight_dummy); CeedChkBackend(ierr); 1204d1d35e2fSjeremylt ierr = CeedBasisCreateTensorH1(ceed_parent, dim, num_comp, P_1d, P_1d, x2, 1205d1d35e2fSjeremylt grad_dummy, q_ref_dummy, q_weight_dummy, 1206e15f9bd0SJeremy L Thompson &fdm_basis); CeedChkBackend(ierr); 1207d1d35e2fSjeremylt ierr = CeedFree(&grad_dummy); CeedChkBackend(ierr); 1208d1d35e2fSjeremylt ierr = CeedFree(&q_ref_dummy); CeedChkBackend(ierr); 1209d1d35e2fSjeremylt ierr = CeedFree(&q_weight_dummy); CeedChkBackend(ierr); 1210e15f9bd0SJeremy L Thompson ierr = CeedFree(&x2); CeedChkBackend(ierr); 1211e15f9bd0SJeremy L Thompson ierr = CeedFree(&lambda); CeedChkBackend(ierr); 1212713f43c3Sjeremylt 1213713f43c3Sjeremylt // -- Restriction 1214713f43c3Sjeremylt CeedElemRestriction rstr_i; 1215d1d35e2fSjeremylt CeedInt strides[3] = {1, l_size, l_size*num_comp}; 1216d1d35e2fSjeremylt ierr = CeedElemRestrictionCreateStrided(ceed_parent, num_elem, l_size, num_comp, 1217d1d35e2fSjeremylt l_size*num_elem*num_comp, strides, &rstr_i); 1218e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1219713f43c3Sjeremylt // -- QFunction 1220713f43c3Sjeremylt CeedQFunction mass_qf; 1221d1d35e2fSjeremylt ierr = CeedQFunctionCreateInteriorByName(ceed_parent, "MassApply", &mass_qf); 1222e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1223713f43c3Sjeremylt // -- Operator 1224d1d35e2fSjeremylt ierr = CeedOperatorCreate(ceed_parent, mass_qf, NULL, NULL, fdm_inv); 1225e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1226d1d35e2fSjeremylt CeedOperatorSetField(*fdm_inv, "u", rstr_i, fdm_basis, CEED_VECTOR_ACTIVE); 1227e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1228d1d35e2fSjeremylt CeedOperatorSetField(*fdm_inv, "qdata", rstr_i, CEED_BASIS_COLLOCATED, q_data); 1229e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1230d1d35e2fSjeremylt CeedOperatorSetField(*fdm_inv, "v", rstr_i, fdm_basis, CEED_VECTOR_ACTIVE); 1231e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1232713f43c3Sjeremylt 1233713f43c3Sjeremylt // Cleanup 1234d1d35e2fSjeremylt ierr = CeedVectorDestroy(&q_data); CeedChkBackend(ierr); 1235e15f9bd0SJeremy L Thompson ierr = CeedBasisDestroy(&fdm_basis); CeedChkBackend(ierr); 1236e15f9bd0SJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr_i); CeedChkBackend(ierr); 1237e15f9bd0SJeremy L Thompson ierr = CeedQFunctionDestroy(&mass_qf); CeedChkBackend(ierr); 1238713f43c3Sjeremylt 1239e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 1240713f43c3Sjeremylt } 1241713f43c3Sjeremylt 1242f10650afSjeremylt //------------------------------------------------------------------------------ 1243f10650afSjeremylt // Operator Destroy 1244f10650afSjeremylt //------------------------------------------------------------------------------ 1245f10650afSjeremylt static int CeedOperatorDestroy_Ref(CeedOperator op) { 1246f10650afSjeremylt int ierr; 1247f10650afSjeremylt CeedOperator_Ref *impl; 1248e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr); 1249f10650afSjeremylt 1250d1d35e2fSjeremylt for (CeedInt i=0; i<impl->num_e_vecs_in+impl->num_e_vecs_out; i++) { 1251d1d35e2fSjeremylt ierr = CeedVectorDestroy(&impl->e_vecs[i]); CeedChkBackend(ierr); 1252f10650afSjeremylt } 1253d1d35e2fSjeremylt ierr = CeedFree(&impl->e_vecs); CeedChkBackend(ierr); 1254d1d35e2fSjeremylt ierr = CeedFree(&impl->e_data); CeedChkBackend(ierr); 1255d1d35e2fSjeremylt ierr = CeedFree(&impl->input_state); CeedChkBackend(ierr); 1256f10650afSjeremylt 1257d1d35e2fSjeremylt for (CeedInt i=0; i<impl->num_e_vecs_in; i++) { 1258d1d35e2fSjeremylt ierr = CeedVectorDestroy(&impl->e_vecs_in[i]); CeedChkBackend(ierr); 1259d1d35e2fSjeremylt ierr = CeedVectorDestroy(&impl->q_vecs_in[i]); CeedChkBackend(ierr); 1260f10650afSjeremylt } 1261d1d35e2fSjeremylt ierr = CeedFree(&impl->e_vecs_in); CeedChkBackend(ierr); 1262d1d35e2fSjeremylt ierr = CeedFree(&impl->q_vecs_in); CeedChkBackend(ierr); 1263f10650afSjeremylt 1264d1d35e2fSjeremylt for (CeedInt i=0; i<impl->num_e_vecs_out; i++) { 1265d1d35e2fSjeremylt ierr = CeedVectorDestroy(&impl->e_vecs_out[i]); CeedChkBackend(ierr); 1266d1d35e2fSjeremylt ierr = CeedVectorDestroy(&impl->q_vecs_out[i]); CeedChkBackend(ierr); 1267f10650afSjeremylt } 1268d1d35e2fSjeremylt ierr = CeedFree(&impl->e_vecs_out); CeedChkBackend(ierr); 1269d1d35e2fSjeremylt ierr = CeedFree(&impl->q_vecs_out); CeedChkBackend(ierr); 1270f10650afSjeremylt 1271e15f9bd0SJeremy L Thompson ierr = CeedFree(&impl); CeedChkBackend(ierr); 1272e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 1273f10650afSjeremylt } 1274f10650afSjeremylt 1275f10650afSjeremylt //------------------------------------------------------------------------------ 1276713f43c3Sjeremylt // Operator Create 1277f10650afSjeremylt //------------------------------------------------------------------------------ 127821617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) { 127921617c04Sjeremylt int ierr; 1280fe2413ffSjeremylt Ceed ceed; 1281e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 12824ce2993fSjeremylt CeedOperator_Ref *impl; 128321617c04Sjeremylt 1284e15f9bd0SJeremy L Thompson ierr = CeedCalloc(1, &impl); CeedChkBackend(ierr); 1285e15f9bd0SJeremy L Thompson ierr = CeedOperatorSetData(op, impl); CeedChkBackend(ierr); 1286fe2413ffSjeremylt 128780ac2e43SJeremy L Thompson ierr = CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleQFunction", 128880ac2e43SJeremy L Thompson CeedOperatorLinearAssembleQFunction_Ref); 1289e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 12909e9210b8SJeremy L Thompson ierr = CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleAddDiagonal", 129169af5e5fSJeremy L Thompson CeedOperatorLinearAssembleAddDiagonal_Ref); 1292e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1293d965c7a7SJeremy L Thompson ierr = CeedSetBackendFunction(ceed, "Operator", op, 12949e9210b8SJeremy L Thompson "LinearAssembleAddPointBlockDiagonal", 129569af5e5fSJeremy L Thompson CeedOperatorLinearAssembleAddPointBlockDiagonal_Ref); 1296e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1297713f43c3Sjeremylt ierr = CeedSetBackendFunction(ceed, "Operator", op, "CreateFDMElementInverse", 1298713f43c3Sjeremylt CeedOperatorCreateFDMElementInverse_Ref); 1299e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1300cae8b89aSjeremylt ierr = CeedSetBackendFunction(ceed, "Operator", op, "ApplyAdd", 1301e15f9bd0SJeremy L Thompson CeedOperatorApplyAdd_Ref); CeedChkBackend(ierr); 1302fe2413ffSjeremylt ierr = CeedSetBackendFunction(ceed, "Operator", op, "Destroy", 1303e15f9bd0SJeremy L Thompson CeedOperatorDestroy_Ref); CeedChkBackend(ierr); 1304e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 130521617c04Sjeremylt } 1306c04a41a7SJeremy L Thompson 1307c04a41a7SJeremy L Thompson //------------------------------------------------------------------------------ 1308c04a41a7SJeremy L Thompson // Composite Operator Create 1309c04a41a7SJeremy L Thompson //------------------------------------------------------------------------------ 1310c04a41a7SJeremy L Thompson int CeedCompositeOperatorCreate_Ref(CeedOperator op) { 1311c04a41a7SJeremy L Thompson int ierr; 1312c04a41a7SJeremy L Thompson Ceed ceed; 1313e15f9bd0SJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 13149e9210b8SJeremy L Thompson ierr = CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleAddDiagonal", 131569af5e5fSJeremy L Thompson CeedOperatorLinearAssembleAddDiagonal_Ref); 1316e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1317c04a41a7SJeremy L Thompson ierr = CeedSetBackendFunction(ceed, "Operator", op, 13189e9210b8SJeremy L Thompson "LinearAssembleAddPointBlockDiagonal", 131969af5e5fSJeremy L Thompson CeedOperatorLinearAssembleAddPointBlockDiagonal_Ref); 1320e15f9bd0SJeremy L Thompson CeedChkBackend(ierr); 1321e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 1322c04a41a7SJeremy L Thompson } 1323f10650afSjeremylt //------------------------------------------------------------------------------ 1324