1eaf62fffSJeremy L Thompson // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2eaf62fffSJeremy L Thompson // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3eaf62fffSJeremy L Thompson // reserved. See files LICENSE and NOTICE for details. 4eaf62fffSJeremy L Thompson // 5eaf62fffSJeremy L Thompson // This file is part of CEED, a collection of benchmarks, miniapps, software 6eaf62fffSJeremy L Thompson // libraries and APIs for efficient high-order finite element and spectral 7eaf62fffSJeremy L Thompson // element discretizations for exascale applications. For more information and 8eaf62fffSJeremy L Thompson // source code availability see http://github.com/ceed. 9eaf62fffSJeremy L Thompson // 10eaf62fffSJeremy L Thompson // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11eaf62fffSJeremy L Thompson // a collaborative effort of two U.S. Department of Energy organizations (Office 12eaf62fffSJeremy L Thompson // of Science and the National Nuclear Security Administration) responsible for 13eaf62fffSJeremy L Thompson // the planning and preparation of a capable exascale ecosystem, including 14eaf62fffSJeremy L Thompson // software, applications, hardware, advanced system engineering and early 15eaf62fffSJeremy L Thompson // testbed platforms, in support of the nation's exascale computing imperative. 16eaf62fffSJeremy L Thompson 17eaf62fffSJeremy L Thompson #include <ceed/ceed.h> 18eaf62fffSJeremy L Thompson #include <ceed/backend.h> 19eaf62fffSJeremy L Thompson #include <ceed-impl.h> 20eaf62fffSJeremy L Thompson #include <math.h> 21eaf62fffSJeremy L Thompson #include <stdbool.h> 22eaf62fffSJeremy L Thompson #include <stdio.h> 23eaf62fffSJeremy L Thompson #include <string.h> 24eaf62fffSJeremy L Thompson 25eaf62fffSJeremy L Thompson /// @file 26eaf62fffSJeremy L Thompson /// Implementation of CeedOperator preconditioning interfaces 27eaf62fffSJeremy L Thompson 28eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 29eaf62fffSJeremy L Thompson /// CeedOperator Library Internal Preconditioning Functions 30eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 31eaf62fffSJeremy L Thompson /// @addtogroup CeedOperatorDeveloper 32eaf62fffSJeremy L Thompson /// @{ 33eaf62fffSJeremy L Thompson 34eaf62fffSJeremy L Thompson /** 35eaf62fffSJeremy L Thompson @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced 36eaf62fffSJeremy L Thompson CeedOperator functionality 37eaf62fffSJeremy L Thompson 38eaf62fffSJeremy L Thompson @param op CeedOperator to create fallback for 39eaf62fffSJeremy L Thompson 40eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 41eaf62fffSJeremy L Thompson 42eaf62fffSJeremy L Thompson @ref Developer 43eaf62fffSJeremy L Thompson **/ 44eaf62fffSJeremy L Thompson int CeedOperatorCreateFallback(CeedOperator op) { 45eaf62fffSJeremy L Thompson int ierr; 46eaf62fffSJeremy L Thompson 47eaf62fffSJeremy L Thompson // Fallback Ceed 48eaf62fffSJeremy L Thompson const char *resource, *fallback_resource; 49eaf62fffSJeremy L Thompson ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr); 50eaf62fffSJeremy L Thompson ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource); 51eaf62fffSJeremy L Thompson CeedChk(ierr); 52eaf62fffSJeremy L Thompson if (!strcmp(resource, fallback_resource)) 53eaf62fffSJeremy L Thompson // LCOV_EXCL_START 54eaf62fffSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 55eaf62fffSJeremy L Thompson "Backend %s cannot create an operator" 56eaf62fffSJeremy L Thompson "fallback to resource %s", resource, fallback_resource); 57eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 58eaf62fffSJeremy L Thompson 59eaf62fffSJeremy L Thompson // Fallback Ceed 60eaf62fffSJeremy L Thompson Ceed ceed_ref; 61eaf62fffSJeremy L Thompson if (!op->ceed->op_fallback_ceed) { 62eaf62fffSJeremy L Thompson ierr = CeedInit(fallback_resource, &ceed_ref); CeedChk(ierr); 63eaf62fffSJeremy L Thompson ceed_ref->op_fallback_parent = op->ceed; 64eaf62fffSJeremy L Thompson ceed_ref->Error = op->ceed->Error; 65eaf62fffSJeremy L Thompson op->ceed->op_fallback_ceed = ceed_ref; 66eaf62fffSJeremy L Thompson } 67eaf62fffSJeremy L Thompson ceed_ref = op->ceed->op_fallback_ceed; 68eaf62fffSJeremy L Thompson 69eaf62fffSJeremy L Thompson // Clone Op 70eaf62fffSJeremy L Thompson CeedOperator op_ref; 71eaf62fffSJeremy L Thompson ierr = CeedCalloc(1, &op_ref); CeedChk(ierr); 72eaf62fffSJeremy L Thompson memcpy(op_ref, op, sizeof(*op_ref)); 73eaf62fffSJeremy L Thompson op_ref->data = NULL; 74f04ea552SJeremy L Thompson op_ref->is_interface_setup = false; 75f04ea552SJeremy L Thompson op_ref->is_backend_setup = false; 76eaf62fffSJeremy L Thompson op_ref->ceed = ceed_ref; 77eaf62fffSJeremy L Thompson ierr = ceed_ref->OperatorCreate(op_ref); CeedChk(ierr); 78eaf62fffSJeremy L Thompson op->op_fallback = op_ref; 79eaf62fffSJeremy L Thompson 80eaf62fffSJeremy L Thompson // Clone QF 81eaf62fffSJeremy L Thompson CeedQFunction qf_ref; 82eaf62fffSJeremy L Thompson ierr = CeedCalloc(1, &qf_ref); CeedChk(ierr); 83eaf62fffSJeremy L Thompson memcpy(qf_ref, (op->qf), sizeof(*qf_ref)); 84eaf62fffSJeremy L Thompson qf_ref->data = NULL; 85eaf62fffSJeremy L Thompson qf_ref->ceed = ceed_ref; 86eaf62fffSJeremy L Thompson ierr = ceed_ref->QFunctionCreate(qf_ref); CeedChk(ierr); 87eaf62fffSJeremy L Thompson op_ref->qf = qf_ref; 88eaf62fffSJeremy L Thompson op->qf_fallback = qf_ref; 89eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 90eaf62fffSJeremy L Thompson } 91eaf62fffSJeremy L Thompson 92eaf62fffSJeremy L Thompson /** 93eaf62fffSJeremy L Thompson @brief Select correct basis matrix pointer based on CeedEvalMode 94eaf62fffSJeremy L Thompson 95eaf62fffSJeremy L Thompson @param[in] eval_mode Current basis evaluation mode 96eaf62fffSJeremy L Thompson @param[in] identity Pointer to identity matrix 97eaf62fffSJeremy L Thompson @param[in] interp Pointer to interpolation matrix 98eaf62fffSJeremy L Thompson @param[in] grad Pointer to gradient matrix 99eaf62fffSJeremy L Thompson @param[out] basis_ptr Basis pointer to set 100eaf62fffSJeremy L Thompson 101eaf62fffSJeremy L Thompson @return none 102eaf62fffSJeremy L Thompson 103eaf62fffSJeremy L Thompson @ref Developer 104eaf62fffSJeremy L Thompson **/ 105eaf62fffSJeremy L Thompson static inline void CeedOperatorGetBasisPointer(CeedEvalMode eval_mode, 106eaf62fffSJeremy L Thompson const CeedScalar *identity, const CeedScalar *interp, 107eaf62fffSJeremy L Thompson const CeedScalar *grad, const CeedScalar **basis_ptr) { 108eaf62fffSJeremy L Thompson switch (eval_mode) { 109eaf62fffSJeremy L Thompson case CEED_EVAL_NONE: 110eaf62fffSJeremy L Thompson *basis_ptr = identity; 111eaf62fffSJeremy L Thompson break; 112eaf62fffSJeremy L Thompson case CEED_EVAL_INTERP: 113eaf62fffSJeremy L Thompson *basis_ptr = interp; 114eaf62fffSJeremy L Thompson break; 115eaf62fffSJeremy L Thompson case CEED_EVAL_GRAD: 116eaf62fffSJeremy L Thompson *basis_ptr = grad; 117eaf62fffSJeremy L Thompson break; 118eaf62fffSJeremy L Thompson case CEED_EVAL_WEIGHT: 119eaf62fffSJeremy L Thompson case CEED_EVAL_DIV: 120eaf62fffSJeremy L Thompson case CEED_EVAL_CURL: 121eaf62fffSJeremy L Thompson break; // Caught by QF Assembly 122eaf62fffSJeremy L Thompson } 123eaf62fffSJeremy L Thompson } 124eaf62fffSJeremy L Thompson 125eaf62fffSJeremy L Thompson /** 126eaf62fffSJeremy L Thompson @brief Create point block restriction for active operator field 127eaf62fffSJeremy L Thompson 128eaf62fffSJeremy L Thompson @param[in] rstr Original CeedElemRestriction for active field 129eaf62fffSJeremy L Thompson @param[out] pointblock_rstr Address of the variable where the newly created 130eaf62fffSJeremy L Thompson CeedElemRestriction will be stored 131eaf62fffSJeremy L Thompson 132eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 133eaf62fffSJeremy L Thompson 134eaf62fffSJeremy L Thompson @ref Developer 135eaf62fffSJeremy L Thompson **/ 136eaf62fffSJeremy L Thompson static int CeedOperatorCreateActivePointBlockRestriction( 137eaf62fffSJeremy L Thompson CeedElemRestriction rstr, 138eaf62fffSJeremy L Thompson CeedElemRestriction *pointblock_rstr) { 139eaf62fffSJeremy L Thompson int ierr; 140eaf62fffSJeremy L Thompson Ceed ceed; 141eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetCeed(rstr, &ceed); CeedChk(ierr); 142eaf62fffSJeremy L Thompson const CeedInt *offsets; 143eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets); 144eaf62fffSJeremy L Thompson CeedChk(ierr); 145eaf62fffSJeremy L Thompson 146eaf62fffSJeremy L Thompson // Expand offsets 147eaf62fffSJeremy L Thompson CeedInt num_elem, num_comp, elem_size, comp_stride, max = 1, 148eaf62fffSJeremy L Thompson *pointblock_offsets; 149eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr); 150eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumComponents(rstr, &num_comp); CeedChk(ierr); 151eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr, &elem_size); CeedChk(ierr); 152eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetCompStride(rstr, &comp_stride); CeedChk(ierr); 153eaf62fffSJeremy L Thompson CeedInt shift = num_comp; 154eaf62fffSJeremy L Thompson if (comp_stride != 1) 155eaf62fffSJeremy L Thompson shift *= num_comp; 156eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_elem*elem_size, &pointblock_offsets); 157eaf62fffSJeremy L Thompson CeedChk(ierr); 158eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_elem*elem_size; i++) { 159eaf62fffSJeremy L Thompson pointblock_offsets[i] = offsets[i]*shift; 160eaf62fffSJeremy L Thompson if (pointblock_offsets[i] > max) 161eaf62fffSJeremy L Thompson max = pointblock_offsets[i]; 162eaf62fffSJeremy L Thompson } 163eaf62fffSJeremy L Thompson 164eaf62fffSJeremy L Thompson // Create new restriction 165eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionCreate(ceed, num_elem, elem_size, num_comp*num_comp, 166eaf62fffSJeremy L Thompson 1, max + num_comp*num_comp, CEED_MEM_HOST, 167eaf62fffSJeremy L Thompson CEED_OWN_POINTER, pointblock_offsets, pointblock_rstr); 168eaf62fffSJeremy L Thompson CeedChk(ierr); 169eaf62fffSJeremy L Thompson 170eaf62fffSJeremy L Thompson // Cleanup 171eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionRestoreOffsets(rstr, &offsets); CeedChk(ierr); 172eaf62fffSJeremy L Thompson 173eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 174eaf62fffSJeremy L Thompson } 175eaf62fffSJeremy L Thompson 176eaf62fffSJeremy L Thompson /** 177eaf62fffSJeremy L Thompson @brief Core logic for assembling operator diagonal or point block diagonal 178eaf62fffSJeremy L Thompson 179eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble point block diagonal 180eaf62fffSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else 181eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 182eaf62fffSJeremy L Thompson @param[in] is_pointblock Boolean flag to assemble diagonal or point block diagonal 183eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled diagonal 184eaf62fffSJeremy L Thompson 185eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 186eaf62fffSJeremy L Thompson 187eaf62fffSJeremy L Thompson @ref Developer 188eaf62fffSJeremy L Thompson **/ 189eaf62fffSJeremy L Thompson static inline int CeedSingleOperatorAssembleAddDiagonal(CeedOperator op, 190eaf62fffSJeremy L Thompson CeedRequest *request, const bool is_pointblock, CeedVector assembled) { 191eaf62fffSJeremy L Thompson int ierr; 192eaf62fffSJeremy L Thompson Ceed ceed; 193eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 194eaf62fffSJeremy L Thompson 195eaf62fffSJeremy L Thompson // Assemble QFunction 196eaf62fffSJeremy L Thompson CeedQFunction qf; 197eaf62fffSJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr); 198eaf62fffSJeremy L Thompson CeedInt num_input_fields, num_output_fields; 199eaf62fffSJeremy L Thompson ierr= CeedQFunctionGetNumArgs(qf, &num_input_fields, &num_output_fields); 200eaf62fffSJeremy L Thompson CeedChk(ierr); 201eaf62fffSJeremy L Thompson CeedVector assembled_qf; 202eaf62fffSJeremy L Thompson CeedElemRestriction rstr; 203*70a7ffb3SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled_qf, 204*70a7ffb3SJeremy L Thompson &rstr, request); CeedChk(ierr); 205eaf62fffSJeremy L Thompson CeedInt layout[3]; 206eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetELayout(rstr, &layout); CeedChk(ierr); 207eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr); 208eaf62fffSJeremy L Thompson CeedScalar max_norm = 0; 209eaf62fffSJeremy L Thompson ierr = CeedVectorNorm(assembled_qf, CEED_NORM_MAX, &max_norm); CeedChk(ierr); 210eaf62fffSJeremy L Thompson 211eaf62fffSJeremy L Thompson // Determine active input basis 212eaf62fffSJeremy L Thompson CeedOperatorField *op_fields; 213eaf62fffSJeremy L Thompson CeedQFunctionField *qf_fields; 2147e7773b5SJeremy L Thompson ierr = CeedOperatorGetFields(op, NULL, &op_fields, NULL, NULL); CeedChk(ierr); 2157e7773b5SJeremy L Thompson ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL); CeedChk(ierr); 216eaf62fffSJeremy L Thompson CeedInt num_eval_mode_in = 0, num_comp, dim = 1; 217eaf62fffSJeremy L Thompson CeedEvalMode *eval_mode_in = NULL; 218eaf62fffSJeremy L Thompson CeedBasis basis_in = NULL; 219eaf62fffSJeremy L Thompson CeedElemRestriction rstr_in = NULL; 220eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_input_fields; i++) { 221eaf62fffSJeremy L Thompson CeedVector vec; 222eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChk(ierr); 223eaf62fffSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 224eaf62fffSJeremy L Thompson CeedElemRestriction rstr; 225eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis_in); CeedChk(ierr); 226eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis_in, &num_comp); CeedChk(ierr); 227eaf62fffSJeremy L Thompson ierr = CeedBasisGetDimension(basis_in, &dim); CeedChk(ierr); 228eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr); CeedChk(ierr); 229eaf62fffSJeremy L Thompson if (rstr_in && rstr_in != rstr) 230eaf62fffSJeremy L Thompson // LCOV_EXCL_START 231eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 232eaf62fffSJeremy L Thompson "Multi-field non-composite operator diagonal assembly not supported"); 233eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 234eaf62fffSJeremy L Thompson rstr_in = rstr; 235eaf62fffSJeremy L Thompson CeedEvalMode eval_mode; 236eaf62fffSJeremy L Thompson ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); CeedChk(ierr); 237eaf62fffSJeremy L Thompson switch (eval_mode) { 238eaf62fffSJeremy L Thompson case CEED_EVAL_NONE: 239eaf62fffSJeremy L Thompson case CEED_EVAL_INTERP: 240eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_in + 1, &eval_mode_in); CeedChk(ierr); 241eaf62fffSJeremy L Thompson eval_mode_in[num_eval_mode_in] = eval_mode; 242eaf62fffSJeremy L Thompson num_eval_mode_in += 1; 243eaf62fffSJeremy L Thompson break; 244eaf62fffSJeremy L Thompson case CEED_EVAL_GRAD: 245eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_in + dim, &eval_mode_in); CeedChk(ierr); 246eaf62fffSJeremy L Thompson for (CeedInt d=0; d<dim; d++) 247eaf62fffSJeremy L Thompson eval_mode_in[num_eval_mode_in+d] = eval_mode; 248eaf62fffSJeremy L Thompson num_eval_mode_in += dim; 249eaf62fffSJeremy L Thompson break; 250eaf62fffSJeremy L Thompson case CEED_EVAL_WEIGHT: 251eaf62fffSJeremy L Thompson case CEED_EVAL_DIV: 252eaf62fffSJeremy L Thompson case CEED_EVAL_CURL: 253eaf62fffSJeremy L Thompson break; // Caught by QF Assembly 254eaf62fffSJeremy L Thompson } 255eaf62fffSJeremy L Thompson } 256eaf62fffSJeremy L Thompson } 257eaf62fffSJeremy L Thompson 258eaf62fffSJeremy L Thompson // Determine active output basis 2597e7773b5SJeremy L Thompson ierr = CeedOperatorGetFields(op, NULL, NULL, NULL, &op_fields); CeedChk(ierr); 2607e7773b5SJeremy L Thompson ierr = CeedQFunctionGetFields(qf, NULL, NULL, NULL, &qf_fields); CeedChk(ierr); 261eaf62fffSJeremy L Thompson CeedInt num_eval_mode_out = 0; 262eaf62fffSJeremy L Thompson CeedEvalMode *eval_mode_out = NULL; 263eaf62fffSJeremy L Thompson CeedBasis basis_out = NULL; 264eaf62fffSJeremy L Thompson CeedElemRestriction rstr_out = NULL; 265eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_output_fields; i++) { 266eaf62fffSJeremy L Thompson CeedVector vec; 267eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChk(ierr); 268eaf62fffSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 269eaf62fffSJeremy L Thompson CeedElemRestriction rstr; 270eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis_out); CeedChk(ierr); 271eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr); CeedChk(ierr); 272eaf62fffSJeremy L Thompson if (rstr_out && rstr_out != rstr) 273eaf62fffSJeremy L Thompson // LCOV_EXCL_START 274eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 275eaf62fffSJeremy L Thompson "Multi-field non-composite operator diagonal assembly not supported"); 276eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 277eaf62fffSJeremy L Thompson rstr_out = rstr; 278eaf62fffSJeremy L Thompson CeedEvalMode eval_mode; 279eaf62fffSJeremy L Thompson ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); CeedChk(ierr); 280eaf62fffSJeremy L Thompson switch (eval_mode) { 281eaf62fffSJeremy L Thompson case CEED_EVAL_NONE: 282eaf62fffSJeremy L Thompson case CEED_EVAL_INTERP: 283eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_out + 1, &eval_mode_out); CeedChk(ierr); 284eaf62fffSJeremy L Thompson eval_mode_out[num_eval_mode_out] = eval_mode; 285eaf62fffSJeremy L Thompson num_eval_mode_out += 1; 286eaf62fffSJeremy L Thompson break; 287eaf62fffSJeremy L Thompson case CEED_EVAL_GRAD: 288eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_out + dim, &eval_mode_out); CeedChk(ierr); 289eaf62fffSJeremy L Thompson for (CeedInt d=0; d<dim; d++) 290eaf62fffSJeremy L Thompson eval_mode_out[num_eval_mode_out+d] = eval_mode; 291eaf62fffSJeremy L Thompson num_eval_mode_out += dim; 292eaf62fffSJeremy L Thompson break; 293eaf62fffSJeremy L Thompson case CEED_EVAL_WEIGHT: 294eaf62fffSJeremy L Thompson case CEED_EVAL_DIV: 295eaf62fffSJeremy L Thompson case CEED_EVAL_CURL: 296eaf62fffSJeremy L Thompson break; // Caught by QF Assembly 297eaf62fffSJeremy L Thompson } 298eaf62fffSJeremy L Thompson } 299eaf62fffSJeremy L Thompson } 300eaf62fffSJeremy L Thompson 301eaf62fffSJeremy L Thompson // Assemble point block diagonal restriction, if needed 302eaf62fffSJeremy L Thompson CeedElemRestriction diag_rstr = rstr_out; 303eaf62fffSJeremy L Thompson if (is_pointblock) { 304eaf62fffSJeremy L Thompson ierr = CeedOperatorCreateActivePointBlockRestriction(rstr_out, &diag_rstr); 305eaf62fffSJeremy L Thompson CeedChk(ierr); 306eaf62fffSJeremy L Thompson } 307eaf62fffSJeremy L Thompson 308eaf62fffSJeremy L Thompson // Create diagonal vector 309eaf62fffSJeremy L Thompson CeedVector elem_diag; 310eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionCreateVector(diag_rstr, NULL, &elem_diag); 311eaf62fffSJeremy L Thompson CeedChk(ierr); 312eaf62fffSJeremy L Thompson 313eaf62fffSJeremy L Thompson // Assemble element operator diagonals 314eaf62fffSJeremy L Thompson CeedScalar *elem_diag_array, *assembled_qf_array; 315eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(elem_diag, 0.0); CeedChk(ierr); 316eaf62fffSJeremy L Thompson ierr = CeedVectorGetArray(elem_diag, CEED_MEM_HOST, &elem_diag_array); 317eaf62fffSJeremy L Thompson CeedChk(ierr); 318eaf62fffSJeremy L Thompson ierr = CeedVectorGetArray(assembled_qf, CEED_MEM_HOST, &assembled_qf_array); 319eaf62fffSJeremy L Thompson CeedChk(ierr); 320eaf62fffSJeremy L Thompson CeedInt num_elem, num_nodes, num_qpts; 321eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(diag_rstr, &num_elem); CeedChk(ierr); 322eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis_in, &num_nodes); CeedChk(ierr); 323eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts); CeedChk(ierr); 324eaf62fffSJeremy L Thompson // Basis matrices 325eaf62fffSJeremy L Thompson const CeedScalar *interp_in, *interp_out, *grad_in, *grad_out; 326eaf62fffSJeremy L Thompson CeedScalar *identity = NULL; 327eaf62fffSJeremy L Thompson bool evalNone = false; 328eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_eval_mode_in; i++) 329eaf62fffSJeremy L Thompson evalNone = evalNone || (eval_mode_in[i] == CEED_EVAL_NONE); 330eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_eval_mode_out; i++) 331eaf62fffSJeremy L Thompson evalNone = evalNone || (eval_mode_out[i] == CEED_EVAL_NONE); 332eaf62fffSJeremy L Thompson if (evalNone) { 333eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_qpts*num_nodes, &identity); CeedChk(ierr); 334eaf62fffSJeremy L Thompson for (CeedInt i=0; i<(num_nodes<num_qpts?num_nodes:num_qpts); i++) 335eaf62fffSJeremy L Thompson identity[i*num_nodes+i] = 1.0; 336eaf62fffSJeremy L Thompson } 337eaf62fffSJeremy L Thompson ierr = CeedBasisGetInterp(basis_in, &interp_in); CeedChk(ierr); 338eaf62fffSJeremy L Thompson ierr = CeedBasisGetInterp(basis_out, &interp_out); CeedChk(ierr); 339eaf62fffSJeremy L Thompson ierr = CeedBasisGetGrad(basis_in, &grad_in); CeedChk(ierr); 340eaf62fffSJeremy L Thompson ierr = CeedBasisGetGrad(basis_out, &grad_out); CeedChk(ierr); 341eaf62fffSJeremy L Thompson // Compute the diagonal of B^T D B 342eaf62fffSJeremy L Thompson // Each element 343eaf62fffSJeremy L Thompson const CeedScalar qf_value_bound = max_norm*100*CEED_EPSILON; 344eaf62fffSJeremy L Thompson for (CeedInt e=0; e<num_elem; e++) { 345eaf62fffSJeremy L Thompson CeedInt d_out = -1; 346eaf62fffSJeremy L Thompson // Each basis eval mode pair 347eaf62fffSJeremy L Thompson for (CeedInt e_out=0; e_out<num_eval_mode_out; e_out++) { 348eaf62fffSJeremy L Thompson const CeedScalar *bt = NULL; 349eaf62fffSJeremy L Thompson if (eval_mode_out[e_out] == CEED_EVAL_GRAD) 350eaf62fffSJeremy L Thompson d_out += 1; 351eaf62fffSJeremy L Thompson CeedOperatorGetBasisPointer(eval_mode_out[e_out], identity, interp_out, 352eaf62fffSJeremy L Thompson &grad_out[d_out*num_qpts*num_nodes], &bt); 353eaf62fffSJeremy L Thompson CeedInt d_in = -1; 354eaf62fffSJeremy L Thompson for (CeedInt e_in=0; e_in<num_eval_mode_in; e_in++) { 355eaf62fffSJeremy L Thompson const CeedScalar *b = NULL; 356eaf62fffSJeremy L Thompson if (eval_mode_in[e_in] == CEED_EVAL_GRAD) 357eaf62fffSJeremy L Thompson d_in += 1; 358eaf62fffSJeremy L Thompson CeedOperatorGetBasisPointer(eval_mode_in[e_in], identity, interp_in, 359eaf62fffSJeremy L Thompson &grad_in[d_in*num_qpts*num_nodes], &b); 360eaf62fffSJeremy L Thompson // Each component 361eaf62fffSJeremy L Thompson for (CeedInt c_out=0; c_out<num_comp; c_out++) 362eaf62fffSJeremy L Thompson // Each qpoint/node pair 363eaf62fffSJeremy L Thompson for (CeedInt q=0; q<num_qpts; q++) 364eaf62fffSJeremy L Thompson if (is_pointblock) { 365eaf62fffSJeremy L Thompson // Point Block Diagonal 366eaf62fffSJeremy L Thompson for (CeedInt c_in=0; c_in<num_comp; c_in++) { 367eaf62fffSJeremy L Thompson const CeedScalar qf_value = 368eaf62fffSJeremy L Thompson assembled_qf_array[q*layout[0] + (((e_in*num_comp+c_in)* 369eaf62fffSJeremy L Thompson num_eval_mode_out+e_out)*num_comp+c_out)*layout[1] + e*layout[2]]; 370eaf62fffSJeremy L Thompson if (fabs(qf_value) > qf_value_bound) 371eaf62fffSJeremy L Thompson for (CeedInt n=0; n<num_nodes; n++) 372eaf62fffSJeremy L Thompson elem_diag_array[((e*num_comp+c_out)*num_comp+c_in)*num_nodes+n] += 373eaf62fffSJeremy L Thompson bt[q*num_nodes+n] * qf_value * b[q*num_nodes+n]; 374eaf62fffSJeremy L Thompson } 375eaf62fffSJeremy L Thompson } else { 376eaf62fffSJeremy L Thompson // Diagonal Only 377eaf62fffSJeremy L Thompson const CeedScalar qf_value = 378eaf62fffSJeremy L Thompson assembled_qf_array[q*layout[0] + (((e_in*num_comp+c_out)* 379eaf62fffSJeremy L Thompson num_eval_mode_out+e_out)*num_comp+c_out)*layout[1] + e*layout[2]]; 380eaf62fffSJeremy L Thompson if (fabs(qf_value) > qf_value_bound) 381eaf62fffSJeremy L Thompson for (CeedInt n=0; n<num_nodes; n++) 382eaf62fffSJeremy L Thompson elem_diag_array[(e*num_comp+c_out)*num_nodes+n] += 383eaf62fffSJeremy L Thompson bt[q*num_nodes+n] * qf_value * b[q*num_nodes+n]; 384eaf62fffSJeremy L Thompson } 385eaf62fffSJeremy L Thompson } 386eaf62fffSJeremy L Thompson } 387eaf62fffSJeremy L Thompson } 388eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArray(elem_diag, &elem_diag_array); CeedChk(ierr); 389eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArray(assembled_qf, &assembled_qf_array); CeedChk(ierr); 390eaf62fffSJeremy L Thompson 391eaf62fffSJeremy L Thompson // Assemble local operator diagonal 392eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionApply(diag_rstr, CEED_TRANSPOSE, elem_diag, 393eaf62fffSJeremy L Thompson assembled, request); CeedChk(ierr); 394eaf62fffSJeremy L Thompson 395eaf62fffSJeremy L Thompson // Cleanup 396eaf62fffSJeremy L Thompson if (is_pointblock) { 397eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&diag_rstr); CeedChk(ierr); 398eaf62fffSJeremy L Thompson } 399eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&assembled_qf); CeedChk(ierr); 400eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&elem_diag); CeedChk(ierr); 401eaf62fffSJeremy L Thompson ierr = CeedFree(&eval_mode_in); CeedChk(ierr); 402eaf62fffSJeremy L Thompson ierr = CeedFree(&eval_mode_out); CeedChk(ierr); 403eaf62fffSJeremy L Thompson ierr = CeedFree(&identity); CeedChk(ierr); 404eaf62fffSJeremy L Thompson 405eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 406eaf62fffSJeremy L Thompson } 407eaf62fffSJeremy L Thompson 408eaf62fffSJeremy L Thompson /** 409eaf62fffSJeremy L Thompson @brief Core logic for assembling composite operator diagonal 410eaf62fffSJeremy L Thompson 411eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble point block diagonal 412eaf62fffSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else 413eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 414eaf62fffSJeremy L Thompson @param[in] is_pointblock Boolean flag to assemble diagonal or point block diagonal 415eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled diagonal 416eaf62fffSJeremy L Thompson 417eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 418eaf62fffSJeremy L Thompson 419eaf62fffSJeremy L Thompson @ref Developer 420eaf62fffSJeremy L Thompson **/ 421eaf62fffSJeremy L Thompson static inline int CeedCompositeOperatorLinearAssembleAddDiagonal( 422eaf62fffSJeremy L Thompson CeedOperator op, CeedRequest *request, const bool is_pointblock, 423eaf62fffSJeremy L Thompson CeedVector assembled) { 424eaf62fffSJeremy L Thompson int ierr; 425eaf62fffSJeremy L Thompson CeedInt num_sub; 426eaf62fffSJeremy L Thompson CeedOperator *suboperators; 427eaf62fffSJeremy L Thompson ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr); 428eaf62fffSJeremy L Thompson ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr); 429eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_sub; i++) { 430eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssembleAddDiagonal(suboperators[i], request, 431eaf62fffSJeremy L Thompson is_pointblock, assembled); CeedChk(ierr); 432eaf62fffSJeremy L Thompson } 433eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 434eaf62fffSJeremy L Thompson } 435eaf62fffSJeremy L Thompson 436eaf62fffSJeremy L Thompson /** 437eaf62fffSJeremy L Thompson @brief Build nonzero pattern for non-composite operator 438eaf62fffSJeremy L Thompson 439eaf62fffSJeremy L Thompson Users should generally use CeedOperatorLinearAssembleSymbolic() 440eaf62fffSJeremy L Thompson 441eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble nonzero pattern 442eaf62fffSJeremy L Thompson @param[in] offset Offset for number of entries 443eaf62fffSJeremy L Thompson @param[out] rows Row number for each entry 444eaf62fffSJeremy L Thompson @param[out] cols Column number for each entry 445eaf62fffSJeremy L Thompson 446eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 447eaf62fffSJeremy L Thompson 448eaf62fffSJeremy L Thompson @ref Developer 449eaf62fffSJeremy L Thompson **/ 450eaf62fffSJeremy L Thompson static int CeedSingleOperatorAssembleSymbolic(CeedOperator op, CeedInt offset, 451eaf62fffSJeremy L Thompson CeedInt *rows, CeedInt *cols) { 452eaf62fffSJeremy L Thompson int ierr; 453eaf62fffSJeremy L Thompson Ceed ceed = op->ceed; 454f04ea552SJeremy L Thompson if (op->is_composite) 455eaf62fffSJeremy L Thompson // LCOV_EXCL_START 456eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 457eaf62fffSJeremy L Thompson "Composite operator not supported"); 458eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 459eaf62fffSJeremy L Thompson 460eaf62fffSJeremy L Thompson CeedElemRestriction rstr_in; 461eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveElemRestriction(op, &rstr_in); CeedChk(ierr); 462eaf62fffSJeremy L Thompson CeedInt num_elem, elem_size, num_nodes, num_comp; 463eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(rstr_in, &num_elem); CeedChk(ierr); 464eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr_in, &elem_size); CeedChk(ierr); 465eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetLVectorSize(rstr_in, &num_nodes); CeedChk(ierr); 466eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumComponents(rstr_in, &num_comp); CeedChk(ierr); 467eaf62fffSJeremy L Thompson CeedInt layout_er[3]; 468eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetELayout(rstr_in, &layout_er); CeedChk(ierr); 469eaf62fffSJeremy L Thompson 470eaf62fffSJeremy L Thompson CeedInt local_num_entries = elem_size*num_comp * elem_size*num_comp * num_elem; 471eaf62fffSJeremy L Thompson 472eaf62fffSJeremy L Thompson // Determine elem_dof relation 473eaf62fffSJeremy L Thompson CeedVector index_vec; 474eaf62fffSJeremy L Thompson ierr = CeedVectorCreate(ceed, num_nodes, &index_vec); CeedChk(ierr); 475eaf62fffSJeremy L Thompson CeedScalar *array; 476eaf62fffSJeremy L Thompson ierr = CeedVectorGetArray(index_vec, CEED_MEM_HOST, &array); CeedChk(ierr); 477eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_nodes; ++i) { 478eaf62fffSJeremy L Thompson array[i] = i; 479eaf62fffSJeremy L Thompson } 480eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArray(index_vec, &array); CeedChk(ierr); 481eaf62fffSJeremy L Thompson CeedVector elem_dof; 482eaf62fffSJeremy L Thompson ierr = CeedVectorCreate(ceed, num_elem * elem_size * num_comp, &elem_dof); 483eaf62fffSJeremy L Thompson CeedChk(ierr); 484eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(elem_dof, 0.0); CeedChk(ierr); 485eaf62fffSJeremy L Thompson CeedElemRestrictionApply(rstr_in, CEED_NOTRANSPOSE, index_vec, 486eaf62fffSJeremy L Thompson elem_dof, CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 487eaf62fffSJeremy L Thompson const CeedScalar *elem_dof_a; 488eaf62fffSJeremy L Thompson ierr = CeedVectorGetArrayRead(elem_dof, CEED_MEM_HOST, &elem_dof_a); 489eaf62fffSJeremy L Thompson CeedChk(ierr); 490eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&index_vec); CeedChk(ierr); 491eaf62fffSJeremy L Thompson 492eaf62fffSJeremy L Thompson // Determine i, j locations for element matrices 493eaf62fffSJeremy L Thompson CeedInt count = 0; 494eaf62fffSJeremy L Thompson for (int e = 0; e < num_elem; ++e) { 495eaf62fffSJeremy L Thompson for (int comp_in = 0; comp_in < num_comp; ++comp_in) { 496eaf62fffSJeremy L Thompson for (int comp_out = 0; comp_out < num_comp; ++comp_out) { 497eaf62fffSJeremy L Thompson for (int i = 0; i < elem_size; ++i) { 498eaf62fffSJeremy L Thompson for (int j = 0; j < elem_size; ++j) { 499eaf62fffSJeremy L Thompson const CeedInt elem_dof_index_row = (i)*layout_er[0] + 500eaf62fffSJeremy L Thompson (comp_out)*layout_er[1] + e*layout_er[2]; 501eaf62fffSJeremy L Thompson const CeedInt elem_dof_index_col = (j)*layout_er[0] + 502eaf62fffSJeremy L Thompson (comp_in)*layout_er[1] + e*layout_er[2]; 503eaf62fffSJeremy L Thompson 504eaf62fffSJeremy L Thompson const CeedInt row = elem_dof_a[elem_dof_index_row]; 505eaf62fffSJeremy L Thompson const CeedInt col = elem_dof_a[elem_dof_index_col]; 506eaf62fffSJeremy L Thompson 507eaf62fffSJeremy L Thompson rows[offset + count] = row; 508eaf62fffSJeremy L Thompson cols[offset + count] = col; 509eaf62fffSJeremy L Thompson count++; 510eaf62fffSJeremy L Thompson } 511eaf62fffSJeremy L Thompson } 512eaf62fffSJeremy L Thompson } 513eaf62fffSJeremy L Thompson } 514eaf62fffSJeremy L Thompson } 515eaf62fffSJeremy L Thompson if (count != local_num_entries) 516eaf62fffSJeremy L Thompson // LCOV_EXCL_START 517eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing assembled entries"); 518eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 519eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArrayRead(elem_dof, &elem_dof_a); CeedChk(ierr); 520eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&elem_dof); CeedChk(ierr); 521eaf62fffSJeremy L Thompson 522eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 523eaf62fffSJeremy L Thompson } 524eaf62fffSJeremy L Thompson 525eaf62fffSJeremy L Thompson /** 526eaf62fffSJeremy L Thompson @brief Assemble nonzero entries for non-composite operator 527eaf62fffSJeremy L Thompson 528eaf62fffSJeremy L Thompson Users should generally use CeedOperatorLinearAssemble() 529eaf62fffSJeremy L Thompson 530eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 531eaf62fffSJeremy L Thompson @param[out] offset Offest for number of entries 532eaf62fffSJeremy L Thompson @param[out] values Values to assemble into matrix 533eaf62fffSJeremy L Thompson 534eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 535eaf62fffSJeremy L Thompson 536eaf62fffSJeremy L Thompson @ref Developer 537eaf62fffSJeremy L Thompson **/ 538eaf62fffSJeremy L Thompson static int CeedSingleOperatorAssemble(CeedOperator op, CeedInt offset, 539eaf62fffSJeremy L Thompson CeedVector values) { 540eaf62fffSJeremy L Thompson int ierr; 541eaf62fffSJeremy L Thompson Ceed ceed = op->ceed; 542f04ea552SJeremy L Thompson if (op->is_composite) 543eaf62fffSJeremy L Thompson // LCOV_EXCL_START 544eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 545eaf62fffSJeremy L Thompson "Composite operator not supported"); 546eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 547eaf62fffSJeremy L Thompson 548eaf62fffSJeremy L Thompson // Assemble QFunction 549eaf62fffSJeremy L Thompson CeedQFunction qf; 550eaf62fffSJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr); 551eaf62fffSJeremy L Thompson CeedVector assembled_qf; 552eaf62fffSJeremy L Thompson CeedElemRestriction rstr_q; 553*70a7ffb3SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate( 554eaf62fffSJeremy L Thompson op, &assembled_qf, &rstr_q, CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 555eaf62fffSJeremy L Thompson 556eaf62fffSJeremy L Thompson CeedInt qf_length; 557eaf62fffSJeremy L Thompson ierr = CeedVectorGetLength(assembled_qf, &qf_length); CeedChk(ierr); 558eaf62fffSJeremy L Thompson 5597e7773b5SJeremy L Thompson CeedInt num_input_fields, num_output_fields; 560eaf62fffSJeremy L Thompson CeedOperatorField *input_fields; 561eaf62fffSJeremy L Thompson CeedOperatorField *output_fields; 5627e7773b5SJeremy L Thompson ierr = CeedOperatorGetFields(op, &num_input_fields, &input_fields, 5637e7773b5SJeremy L Thompson &num_output_fields, &output_fields); CeedChk(ierr); 564eaf62fffSJeremy L Thompson 565eaf62fffSJeremy L Thompson // Determine active input basis 566eaf62fffSJeremy L Thompson CeedQFunctionField *qf_fields; 5677e7773b5SJeremy L Thompson ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL); CeedChk(ierr); 568eaf62fffSJeremy L Thompson CeedInt num_eval_mode_in = 0, dim = 1; 569eaf62fffSJeremy L Thompson CeedEvalMode *eval_mode_in = NULL; 570eaf62fffSJeremy L Thompson CeedBasis basis_in = NULL; 571eaf62fffSJeremy L Thompson CeedElemRestriction rstr_in = NULL; 572eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_input_fields; i++) { 573eaf62fffSJeremy L Thompson CeedVector vec; 574eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetVector(input_fields[i], &vec); CeedChk(ierr); 575eaf62fffSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 576eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetBasis(input_fields[i], &basis_in); 577eaf62fffSJeremy L Thompson CeedChk(ierr); 578eaf62fffSJeremy L Thompson ierr = CeedBasisGetDimension(basis_in, &dim); CeedChk(ierr); 579eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetElemRestriction(input_fields[i], &rstr_in); 580eaf62fffSJeremy L Thompson CeedChk(ierr); 581eaf62fffSJeremy L Thompson CeedEvalMode eval_mode; 582eaf62fffSJeremy L Thompson ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); 583eaf62fffSJeremy L Thompson CeedChk(ierr); 584eaf62fffSJeremy L Thompson switch (eval_mode) { 585eaf62fffSJeremy L Thompson case CEED_EVAL_NONE: 586eaf62fffSJeremy L Thompson case CEED_EVAL_INTERP: 587eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_in + 1, &eval_mode_in); CeedChk(ierr); 588eaf62fffSJeremy L Thompson eval_mode_in[num_eval_mode_in] = eval_mode; 589eaf62fffSJeremy L Thompson num_eval_mode_in += 1; 590eaf62fffSJeremy L Thompson break; 591eaf62fffSJeremy L Thompson case CEED_EVAL_GRAD: 592eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_in + dim, &eval_mode_in); CeedChk(ierr); 593eaf62fffSJeremy L Thompson for (CeedInt d=0; d<dim; d++) { 594eaf62fffSJeremy L Thompson eval_mode_in[num_eval_mode_in+d] = eval_mode; 595eaf62fffSJeremy L Thompson } 596eaf62fffSJeremy L Thompson num_eval_mode_in += dim; 597eaf62fffSJeremy L Thompson break; 598eaf62fffSJeremy L Thompson case CEED_EVAL_WEIGHT: 599eaf62fffSJeremy L Thompson case CEED_EVAL_DIV: 600eaf62fffSJeremy L Thompson case CEED_EVAL_CURL: 601eaf62fffSJeremy L Thompson break; // Caught by QF Assembly 602eaf62fffSJeremy L Thompson } 603eaf62fffSJeremy L Thompson } 604eaf62fffSJeremy L Thompson } 605eaf62fffSJeremy L Thompson 606eaf62fffSJeremy L Thompson // Determine active output basis 6077e7773b5SJeremy L Thompson ierr = CeedQFunctionGetFields(qf, NULL, NULL, NULL, &qf_fields); CeedChk(ierr); 608eaf62fffSJeremy L Thompson CeedInt num_eval_mode_out = 0; 609eaf62fffSJeremy L Thompson CeedEvalMode *eval_mode_out = NULL; 610eaf62fffSJeremy L Thompson CeedBasis basis_out = NULL; 611eaf62fffSJeremy L Thompson CeedElemRestriction rstr_out = NULL; 612eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_output_fields; i++) { 613eaf62fffSJeremy L Thompson CeedVector vec; 614eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetVector(output_fields[i], &vec); CeedChk(ierr); 615eaf62fffSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 616eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetBasis(output_fields[i], &basis_out); 617eaf62fffSJeremy L Thompson CeedChk(ierr); 618eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetElemRestriction(output_fields[i], &rstr_out); 619eaf62fffSJeremy L Thompson CeedChk(ierr); 620eaf62fffSJeremy L Thompson CeedEvalMode eval_mode; 621eaf62fffSJeremy L Thompson ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); 622eaf62fffSJeremy L Thompson CeedChk(ierr); 623eaf62fffSJeremy L Thompson switch (eval_mode) { 624eaf62fffSJeremy L Thompson case CEED_EVAL_NONE: 625eaf62fffSJeremy L Thompson case CEED_EVAL_INTERP: 626eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_out + 1, &eval_mode_out); CeedChk(ierr); 627eaf62fffSJeremy L Thompson eval_mode_out[num_eval_mode_out] = eval_mode; 628eaf62fffSJeremy L Thompson num_eval_mode_out += 1; 629eaf62fffSJeremy L Thompson break; 630eaf62fffSJeremy L Thompson case CEED_EVAL_GRAD: 631eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_out + dim, &eval_mode_out); CeedChk(ierr); 632eaf62fffSJeremy L Thompson for (CeedInt d=0; d<dim; d++) { 633eaf62fffSJeremy L Thompson eval_mode_out[num_eval_mode_out+d] = eval_mode; 634eaf62fffSJeremy L Thompson } 635eaf62fffSJeremy L Thompson num_eval_mode_out += dim; 636eaf62fffSJeremy L Thompson break; 637eaf62fffSJeremy L Thompson case CEED_EVAL_WEIGHT: 638eaf62fffSJeremy L Thompson case CEED_EVAL_DIV: 639eaf62fffSJeremy L Thompson case CEED_EVAL_CURL: 640eaf62fffSJeremy L Thompson break; // Caught by QF Assembly 641eaf62fffSJeremy L Thompson } 642eaf62fffSJeremy L Thompson } 643eaf62fffSJeremy L Thompson } 644eaf62fffSJeremy L Thompson 645eaf62fffSJeremy L Thompson if (num_eval_mode_in == 0 || num_eval_mode_out == 0) 646eaf62fffSJeremy L Thompson // LCOV_EXCL_START 647eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 648eaf62fffSJeremy L Thompson "Cannot assemble operator with out inputs/outputs"); 649eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 650eaf62fffSJeremy L Thompson 651eaf62fffSJeremy L Thompson CeedInt num_elem, elem_size, num_qpts, num_comp; 652eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(rstr_in, &num_elem); CeedChk(ierr); 653eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr_in, &elem_size); CeedChk(ierr); 654eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumComponents(rstr_in, &num_comp); CeedChk(ierr); 655eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts); CeedChk(ierr); 656eaf62fffSJeremy L Thompson 657eaf62fffSJeremy L Thompson CeedInt local_num_entries = elem_size*num_comp * elem_size*num_comp * num_elem; 658eaf62fffSJeremy L Thompson 659eaf62fffSJeremy L Thompson // loop over elements and put in data structure 660eaf62fffSJeremy L Thompson const CeedScalar *interp_in, *grad_in; 661eaf62fffSJeremy L Thompson ierr = CeedBasisGetInterp(basis_in, &interp_in); CeedChk(ierr); 662eaf62fffSJeremy L Thompson ierr = CeedBasisGetGrad(basis_in, &grad_in); CeedChk(ierr); 663eaf62fffSJeremy L Thompson 664eaf62fffSJeremy L Thompson const CeedScalar *assembled_qf_array; 665eaf62fffSJeremy L Thompson ierr = CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array); 666eaf62fffSJeremy L Thompson CeedChk(ierr); 667eaf62fffSJeremy L Thompson 668eaf62fffSJeremy L Thompson CeedInt layout_qf[3]; 669eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetELayout(rstr_q, &layout_qf); CeedChk(ierr); 670eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr_q); CeedChk(ierr); 671eaf62fffSJeremy L Thompson 672eaf62fffSJeremy L Thompson // we store B_mat_in, B_mat_out, BTD, elem_mat in row-major order 673eaf62fffSJeremy L Thompson CeedScalar B_mat_in[(num_qpts * num_eval_mode_in) * elem_size]; 674eaf62fffSJeremy L Thompson CeedScalar B_mat_out[(num_qpts * num_eval_mode_out) * elem_size]; 675eaf62fffSJeremy L Thompson CeedScalar D_mat[num_eval_mode_out * num_eval_mode_in * 676eaf62fffSJeremy L Thompson num_qpts]; // logically 3-tensor 677eaf62fffSJeremy L Thompson CeedScalar BTD[elem_size * num_qpts*num_eval_mode_in]; 678eaf62fffSJeremy L Thompson CeedScalar elem_mat[elem_size * elem_size]; 679eaf62fffSJeremy L Thompson int count = 0; 680eaf62fffSJeremy L Thompson CeedScalar *vals; 681eaf62fffSJeremy L Thompson ierr = CeedVectorGetArray(values, CEED_MEM_HOST, &vals); CeedChk(ierr); 682eaf62fffSJeremy L Thompson for (int e = 0; e < num_elem; ++e) { 683eaf62fffSJeremy L Thompson for (int comp_in = 0; comp_in < num_comp; ++comp_in) { 684eaf62fffSJeremy L Thompson for (int comp_out = 0; comp_out < num_comp; ++comp_out) { 685eaf62fffSJeremy L Thompson for (int ell = 0; ell < (num_qpts * num_eval_mode_in) * elem_size; ++ell) { 686eaf62fffSJeremy L Thompson B_mat_in[ell] = 0.0; 687eaf62fffSJeremy L Thompson } 688eaf62fffSJeremy L Thompson for (int ell = 0; ell < (num_qpts * num_eval_mode_out) * elem_size; ++ell) { 689eaf62fffSJeremy L Thompson B_mat_out[ell] = 0.0; 690eaf62fffSJeremy L Thompson } 691eaf62fffSJeremy L Thompson // Store block-diagonal D matrix as collection of small dense blocks 692eaf62fffSJeremy L Thompson for (int ell = 0; ell < num_eval_mode_in*num_eval_mode_out*num_qpts; ++ell) { 693eaf62fffSJeremy L Thompson D_mat[ell] = 0.0; 694eaf62fffSJeremy L Thompson } 695eaf62fffSJeremy L Thompson // form element matrix itself (for each block component) 696eaf62fffSJeremy L Thompson for (int ell = 0; ell < elem_size*elem_size; ++ell) { 697eaf62fffSJeremy L Thompson elem_mat[ell] = 0.0; 698eaf62fffSJeremy L Thompson } 699eaf62fffSJeremy L Thompson for (int q = 0; q < num_qpts; ++q) { 700eaf62fffSJeremy L Thompson for (int n = 0; n < elem_size; ++n) { 701eaf62fffSJeremy L Thompson CeedInt d_in = -1; 702eaf62fffSJeremy L Thompson for (int e_in = 0; e_in < num_eval_mode_in; ++e_in) { 703eaf62fffSJeremy L Thompson const int qq = num_eval_mode_in*q; 704eaf62fffSJeremy L Thompson if (eval_mode_in[e_in] == CEED_EVAL_INTERP) { 705eaf62fffSJeremy L Thompson B_mat_in[(qq+e_in)*elem_size + n] += interp_in[q * elem_size + n]; 706eaf62fffSJeremy L Thompson } else if (eval_mode_in[e_in] == CEED_EVAL_GRAD) { 707eaf62fffSJeremy L Thompson d_in += 1; 708eaf62fffSJeremy L Thompson B_mat_in[(qq+e_in)*elem_size + n] += 709eaf62fffSJeremy L Thompson grad_in[(d_in*num_qpts+q) * elem_size + n]; 710eaf62fffSJeremy L Thompson } else { 711eaf62fffSJeremy L Thompson // LCOV_EXCL_START 712eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!"); 713eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 714eaf62fffSJeremy L Thompson } 715eaf62fffSJeremy L Thompson } 716eaf62fffSJeremy L Thompson CeedInt d_out = -1; 717eaf62fffSJeremy L Thompson for (int e_out = 0; e_out < num_eval_mode_out; ++e_out) { 718eaf62fffSJeremy L Thompson const int qq = num_eval_mode_out*q; 719eaf62fffSJeremy L Thompson if (eval_mode_out[e_out] == CEED_EVAL_INTERP) { 720eaf62fffSJeremy L Thompson B_mat_out[(qq+e_out)*elem_size + n] += interp_in[q * elem_size + n]; 721eaf62fffSJeremy L Thompson } else if (eval_mode_out[e_out] == CEED_EVAL_GRAD) { 722eaf62fffSJeremy L Thompson d_out += 1; 723eaf62fffSJeremy L Thompson B_mat_out[(qq+e_out)*elem_size + n] += 724eaf62fffSJeremy L Thompson grad_in[(d_out*num_qpts+q) * elem_size + n]; 725eaf62fffSJeremy L Thompson } else { 726eaf62fffSJeremy L Thompson // LCOV_EXCL_START 727eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!"); 728eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 729eaf62fffSJeremy L Thompson } 730eaf62fffSJeremy L Thompson } 731eaf62fffSJeremy L Thompson } 732eaf62fffSJeremy L Thompson for (int ei = 0; ei < num_eval_mode_out; ++ei) { 733eaf62fffSJeremy L Thompson for (int ej = 0; ej < num_eval_mode_in; ++ej) { 734eaf62fffSJeremy L Thompson const int eval_mode_index = ((ei*num_comp+comp_in)*num_eval_mode_in+ej)*num_comp 735eaf62fffSJeremy L Thompson +comp_out; 736eaf62fffSJeremy L Thompson const int index = q*layout_qf[0] + eval_mode_index*layout_qf[1] + 737eaf62fffSJeremy L Thompson e*layout_qf[2]; 738eaf62fffSJeremy L Thompson D_mat[(ei*num_eval_mode_in+ej)*num_qpts + q] += assembled_qf_array[index]; 739eaf62fffSJeremy L Thompson } 740eaf62fffSJeremy L Thompson } 741eaf62fffSJeremy L Thompson } 742eaf62fffSJeremy L Thompson // Compute B^T*D 743eaf62fffSJeremy L Thompson for (int ell = 0; ell < elem_size*num_qpts*num_eval_mode_in; ++ell) { 744eaf62fffSJeremy L Thompson BTD[ell] = 0.0; 745eaf62fffSJeremy L Thompson } 746eaf62fffSJeremy L Thompson for (int j = 0; j<elem_size; ++j) { 747eaf62fffSJeremy L Thompson for (int q = 0; q<num_qpts; ++q) { 748eaf62fffSJeremy L Thompson int qq = num_eval_mode_out*q; 749eaf62fffSJeremy L Thompson for (int ei = 0; ei < num_eval_mode_in; ++ei) { 750eaf62fffSJeremy L Thompson for (int ej = 0; ej < num_eval_mode_out; ++ej) { 751eaf62fffSJeremy L Thompson BTD[j*(num_qpts*num_eval_mode_in) + (qq+ei)] += 752eaf62fffSJeremy L Thompson B_mat_out[(qq+ej)*elem_size + j] * D_mat[(ei*num_eval_mode_in+ej)*num_qpts + q]; 753eaf62fffSJeremy L Thompson } 754eaf62fffSJeremy L Thompson } 755eaf62fffSJeremy L Thompson } 756eaf62fffSJeremy L Thompson } 757eaf62fffSJeremy L Thompson 758eaf62fffSJeremy L Thompson ierr = CeedMatrixMultiply(ceed, BTD, B_mat_in, elem_mat, elem_size, 759eaf62fffSJeremy L Thompson elem_size, num_qpts*num_eval_mode_in); CeedChk(ierr); 760eaf62fffSJeremy L Thompson 761eaf62fffSJeremy L Thompson // put element matrix in coordinate data structure 762eaf62fffSJeremy L Thompson for (int i = 0; i < elem_size; ++i) { 763eaf62fffSJeremy L Thompson for (int j = 0; j < elem_size; ++j) { 764eaf62fffSJeremy L Thompson vals[offset + count] = elem_mat[i*elem_size + j]; 765eaf62fffSJeremy L Thompson count++; 766eaf62fffSJeremy L Thompson } 767eaf62fffSJeremy L Thompson } 768eaf62fffSJeremy L Thompson } 769eaf62fffSJeremy L Thompson } 770eaf62fffSJeremy L Thompson } 771eaf62fffSJeremy L Thompson if (count != local_num_entries) 772eaf62fffSJeremy L Thompson // LCOV_EXCL_START 773eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing entries"); 774eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 775eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArray(values, &vals); CeedChk(ierr); 776eaf62fffSJeremy L Thompson 777eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array); 778eaf62fffSJeremy L Thompson CeedChk(ierr); 779eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&assembled_qf); CeedChk(ierr); 780eaf62fffSJeremy L Thompson ierr = CeedFree(&eval_mode_in); CeedChk(ierr); 781eaf62fffSJeremy L Thompson ierr = CeedFree(&eval_mode_out); CeedChk(ierr); 782eaf62fffSJeremy L Thompson 783eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 784eaf62fffSJeremy L Thompson } 785eaf62fffSJeremy L Thompson 786eaf62fffSJeremy L Thompson /** 787eaf62fffSJeremy L Thompson @brief Count number of entries for assembled CeedOperator 788eaf62fffSJeremy L Thompson 789eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 790eaf62fffSJeremy L Thompson @param[out] num_entries Number of entries in assembled representation 791eaf62fffSJeremy L Thompson 792eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 793eaf62fffSJeremy L Thompson 794eaf62fffSJeremy L Thompson @ref Utility 795eaf62fffSJeremy L Thompson **/ 796eaf62fffSJeremy L Thompson static int CeedSingleOperatorAssemblyCountEntries(CeedOperator op, 797eaf62fffSJeremy L Thompson CeedInt *num_entries) { 798eaf62fffSJeremy L Thompson int ierr; 799eaf62fffSJeremy L Thompson CeedElemRestriction rstr; 800eaf62fffSJeremy L Thompson CeedInt num_elem, elem_size, num_comp; 801eaf62fffSJeremy L Thompson 802f04ea552SJeremy L Thompson if (op->is_composite) 803eaf62fffSJeremy L Thompson // LCOV_EXCL_START 804eaf62fffSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 805eaf62fffSJeremy L Thompson "Composite operator not supported"); 806eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 807eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveElemRestriction(op, &rstr); CeedChk(ierr); 808eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr); 809eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr, &elem_size); CeedChk(ierr); 810eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumComponents(rstr, &num_comp); CeedChk(ierr); 811eaf62fffSJeremy L Thompson *num_entries = elem_size*num_comp * elem_size*num_comp * num_elem; 812eaf62fffSJeremy L Thompson 813eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 814eaf62fffSJeremy L Thompson } 815eaf62fffSJeremy L Thompson 816eaf62fffSJeremy L Thompson /** 817eaf62fffSJeremy L Thompson @brief Common code for creating a multigrid coarse operator and level 818eaf62fffSJeremy L Thompson transfer operators for a CeedOperator 819eaf62fffSJeremy L Thompson 820eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 821eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 822eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 823eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 824eaf62fffSJeremy L Thompson @param[in] basis_c_to_f Basis for coarse to fine interpolation 825eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 826eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 827eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 828eaf62fffSJeremy L Thompson 829eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 830eaf62fffSJeremy L Thompson 831eaf62fffSJeremy L Thompson @ref Developer 832eaf62fffSJeremy L Thompson **/ 833eaf62fffSJeremy L Thompson static int CeedSingleOperatorMultigridLevel(CeedOperator op_fine, 834eaf62fffSJeremy L Thompson CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 835eaf62fffSJeremy L Thompson CeedBasis basis_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong, 836eaf62fffSJeremy L Thompson CeedOperator *op_restrict) { 837eaf62fffSJeremy L Thompson int ierr; 838eaf62fffSJeremy L Thompson Ceed ceed; 839eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr); 840eaf62fffSJeremy L Thompson 841eaf62fffSJeremy L Thompson // Check for composite operator 842eaf62fffSJeremy L Thompson bool is_composite; 843eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op_fine, &is_composite); CeedChk(ierr); 844eaf62fffSJeremy L Thompson if (is_composite) 845eaf62fffSJeremy L Thompson // LCOV_EXCL_START 846eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 847eaf62fffSJeremy L Thompson "Automatic multigrid setup for composite operators not supported"); 848eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 849eaf62fffSJeremy L Thompson 850eaf62fffSJeremy L Thompson // Coarse Grid 851eaf62fffSJeremy L Thompson ierr = CeedOperatorCreate(ceed, op_fine->qf, op_fine->dqf, op_fine->dqfT, 852eaf62fffSJeremy L Thompson op_coarse); CeedChk(ierr); 853eaf62fffSJeremy L Thompson CeedElemRestriction rstr_fine = NULL; 854eaf62fffSJeremy L Thompson // -- Clone input fields 855eaf62fffSJeremy L Thompson for (int i = 0; i < op_fine->qf->num_input_fields; i++) { 856eaf62fffSJeremy L Thompson if (op_fine->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 857eaf62fffSJeremy L Thompson rstr_fine = op_fine->input_fields[i]->elem_restr; 858eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name, 859eaf62fffSJeremy L Thompson rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE); 860eaf62fffSJeremy L Thompson CeedChk(ierr); 861eaf62fffSJeremy L Thompson } else { 862eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name, 863eaf62fffSJeremy L Thompson op_fine->input_fields[i]->elem_restr, 864eaf62fffSJeremy L Thompson op_fine->input_fields[i]->basis, 865eaf62fffSJeremy L Thompson op_fine->input_fields[i]->vec); CeedChk(ierr); 866eaf62fffSJeremy L Thompson } 867eaf62fffSJeremy L Thompson } 868eaf62fffSJeremy L Thompson // -- Clone output fields 869eaf62fffSJeremy L Thompson for (int i = 0; i < op_fine->qf->num_output_fields; i++) { 870eaf62fffSJeremy L Thompson if (op_fine->output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 871eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name, 872eaf62fffSJeremy L Thompson rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE); 873eaf62fffSJeremy L Thompson CeedChk(ierr); 874eaf62fffSJeremy L Thompson } else { 875eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name, 876eaf62fffSJeremy L Thompson op_fine->output_fields[i]->elem_restr, 877eaf62fffSJeremy L Thompson op_fine->output_fields[i]->basis, 878eaf62fffSJeremy L Thompson op_fine->output_fields[i]->vec); CeedChk(ierr); 879eaf62fffSJeremy L Thompson } 880eaf62fffSJeremy L Thompson } 881eaf62fffSJeremy L Thompson 882eaf62fffSJeremy L Thompson // Multiplicity vector 883eaf62fffSJeremy L Thompson CeedVector mult_vec, mult_e_vec; 884eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionCreateVector(rstr_fine, &mult_vec, &mult_e_vec); 885eaf62fffSJeremy L Thompson CeedChk(ierr); 886eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(mult_e_vec, 0.0); CeedChk(ierr); 887eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionApply(rstr_fine, CEED_NOTRANSPOSE, p_mult_fine, 888eaf62fffSJeremy L Thompson mult_e_vec, CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 889eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(mult_vec, 0.0); CeedChk(ierr); 890eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionApply(rstr_fine, CEED_TRANSPOSE, mult_e_vec, mult_vec, 891eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 892eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&mult_e_vec); CeedChk(ierr); 893eaf62fffSJeremy L Thompson ierr = CeedVectorReciprocal(mult_vec); CeedChk(ierr); 894eaf62fffSJeremy L Thompson 895eaf62fffSJeremy L Thompson // Restriction 896eaf62fffSJeremy L Thompson CeedInt num_comp; 897eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis_coarse, &num_comp); CeedChk(ierr); 898eaf62fffSJeremy L Thompson CeedQFunction qf_restrict; 899eaf62fffSJeremy L Thompson ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_restrict); 900eaf62fffSJeremy L Thompson CeedChk(ierr); 901eaf62fffSJeremy L Thompson CeedInt *num_comp_r_data; 902eaf62fffSJeremy L Thompson ierr = CeedCalloc(1, &num_comp_r_data); CeedChk(ierr); 903eaf62fffSJeremy L Thompson num_comp_r_data[0] = num_comp; 904eaf62fffSJeremy L Thompson CeedQFunctionContext ctx_r; 905eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextCreate(ceed, &ctx_r); CeedChk(ierr); 906eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextSetData(ctx_r, CEED_MEM_HOST, CEED_OWN_POINTER, 907eaf62fffSJeremy L Thompson sizeof(*num_comp_r_data), num_comp_r_data); 908eaf62fffSJeremy L Thompson CeedChk(ierr); 909eaf62fffSJeremy L Thompson ierr = CeedQFunctionSetContext(qf_restrict, ctx_r); CeedChk(ierr); 910eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextDestroy(&ctx_r); CeedChk(ierr); 911eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_restrict, "input", num_comp, CEED_EVAL_NONE); 912eaf62fffSJeremy L Thompson CeedChk(ierr); 913eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_restrict, "scale", num_comp, CEED_EVAL_NONE); 914eaf62fffSJeremy L Thompson CeedChk(ierr); 915eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddOutput(qf_restrict, "output", num_comp, 916eaf62fffSJeremy L Thompson CEED_EVAL_INTERP); CeedChk(ierr); 917eaf62fffSJeremy L Thompson 918eaf62fffSJeremy L Thompson ierr = CeedOperatorCreate(ceed, qf_restrict, CEED_QFUNCTION_NONE, 919eaf62fffSJeremy L Thompson CEED_QFUNCTION_NONE, op_restrict); 920eaf62fffSJeremy L Thompson CeedChk(ierr); 921eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_restrict, "input", rstr_fine, 922eaf62fffSJeremy L Thompson CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 923eaf62fffSJeremy L Thompson CeedChk(ierr); 924eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_restrict, "scale", rstr_fine, 925eaf62fffSJeremy L Thompson CEED_BASIS_COLLOCATED, mult_vec); 926eaf62fffSJeremy L Thompson CeedChk(ierr); 927eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_restrict, "output", rstr_coarse, basis_c_to_f, 928eaf62fffSJeremy L Thompson CEED_VECTOR_ACTIVE); CeedChk(ierr); 929eaf62fffSJeremy L Thompson 930eaf62fffSJeremy L Thompson // Prolongation 931eaf62fffSJeremy L Thompson CeedQFunction qf_prolong; 932eaf62fffSJeremy L Thompson ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_prolong); 933eaf62fffSJeremy L Thompson CeedChk(ierr); 934eaf62fffSJeremy L Thompson CeedInt *num_comp_p_data; 935eaf62fffSJeremy L Thompson ierr = CeedCalloc(1, &num_comp_p_data); CeedChk(ierr); 936eaf62fffSJeremy L Thompson num_comp_p_data[0] = num_comp; 937eaf62fffSJeremy L Thompson CeedQFunctionContext ctx_p; 938eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextCreate(ceed, &ctx_p); CeedChk(ierr); 939eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextSetData(ctx_p, CEED_MEM_HOST, CEED_OWN_POINTER, 940eaf62fffSJeremy L Thompson sizeof(*num_comp_p_data), num_comp_p_data); 941eaf62fffSJeremy L Thompson CeedChk(ierr); 942eaf62fffSJeremy L Thompson ierr = CeedQFunctionSetContext(qf_prolong, ctx_p); CeedChk(ierr); 943eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextDestroy(&ctx_p); CeedChk(ierr); 944eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_prolong, "input", num_comp, CEED_EVAL_INTERP); 945eaf62fffSJeremy L Thompson CeedChk(ierr); 946eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_prolong, "scale", num_comp, CEED_EVAL_NONE); 947eaf62fffSJeremy L Thompson CeedChk(ierr); 948eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddOutput(qf_prolong, "output", num_comp, CEED_EVAL_NONE); 949eaf62fffSJeremy L Thompson CeedChk(ierr); 950eaf62fffSJeremy L Thompson 951eaf62fffSJeremy L Thompson ierr = CeedOperatorCreate(ceed, qf_prolong, CEED_QFUNCTION_NONE, 952eaf62fffSJeremy L Thompson CEED_QFUNCTION_NONE, op_prolong); 953eaf62fffSJeremy L Thompson CeedChk(ierr); 954eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_prolong, "input", rstr_coarse, basis_c_to_f, 955eaf62fffSJeremy L Thompson CEED_VECTOR_ACTIVE); CeedChk(ierr); 956eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_prolong, "scale", rstr_fine, 957eaf62fffSJeremy L Thompson CEED_BASIS_COLLOCATED, mult_vec); 958eaf62fffSJeremy L Thompson CeedChk(ierr); 959eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_prolong, "output", rstr_fine, 960eaf62fffSJeremy L Thompson CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 961eaf62fffSJeremy L Thompson CeedChk(ierr); 962eaf62fffSJeremy L Thompson 963eaf62fffSJeremy L Thompson // Cleanup 964eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&mult_vec); CeedChk(ierr); 965eaf62fffSJeremy L Thompson ierr = CeedBasisDestroy(&basis_c_to_f); CeedChk(ierr); 966eaf62fffSJeremy L Thompson ierr = CeedQFunctionDestroy(&qf_restrict); CeedChk(ierr); 967eaf62fffSJeremy L Thompson ierr = CeedQFunctionDestroy(&qf_prolong); CeedChk(ierr); 968eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 969eaf62fffSJeremy L Thompson } 970eaf62fffSJeremy L Thompson 971eaf62fffSJeremy L Thompson /** 972eaf62fffSJeremy L Thompson @brief Build 1D mass matrix and Laplacian with perturbation 973eaf62fffSJeremy L Thompson 974eaf62fffSJeremy L Thompson @param[in] interp_1d Interpolation matrix in one dimension 975eaf62fffSJeremy L Thompson @param[in] grad_1d Gradient matrix in one dimension 976eaf62fffSJeremy L Thompson @param[in] q_weight_1d Quadrature weights in one dimension 977eaf62fffSJeremy L Thompson @param[in] P_1d Number of basis nodes in one dimension 978eaf62fffSJeremy L Thompson @param[in] Q_1d Number of quadrature points in one dimension 979eaf62fffSJeremy L Thompson @param[in] dim Dimension of basis 980eaf62fffSJeremy L Thompson @param[out] mass Assembled mass matrix in one dimension 981eaf62fffSJeremy L Thompson @param[out] laplace Assembled perturbed Laplacian in one dimension 982eaf62fffSJeremy L Thompson 983eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 984eaf62fffSJeremy L Thompson 985eaf62fffSJeremy L Thompson @ref Developer 986eaf62fffSJeremy L Thompson **/ 987eaf62fffSJeremy L Thompson CeedPragmaOptimizeOff 988eaf62fffSJeremy L Thompson static int CeedBuildMassLaplace(const CeedScalar *interp_1d, 989eaf62fffSJeremy L Thompson const CeedScalar *grad_1d, 990eaf62fffSJeremy L Thompson const CeedScalar *q_weight_1d, CeedInt P_1d, 991eaf62fffSJeremy L Thompson CeedInt Q_1d, CeedInt dim, 992eaf62fffSJeremy L Thompson CeedScalar *mass, CeedScalar *laplace) { 993eaf62fffSJeremy L Thompson 994eaf62fffSJeremy L Thompson for (CeedInt i=0; i<P_1d; i++) 995eaf62fffSJeremy L Thompson for (CeedInt j=0; j<P_1d; j++) { 996eaf62fffSJeremy L Thompson CeedScalar sum = 0.0; 997eaf62fffSJeremy L Thompson for (CeedInt k=0; k<Q_1d; k++) 998eaf62fffSJeremy L Thompson sum += interp_1d[k*P_1d+i]*q_weight_1d[k]*interp_1d[k*P_1d+j]; 999eaf62fffSJeremy L Thompson mass[i+j*P_1d] = sum; 1000eaf62fffSJeremy L Thompson } 1001eaf62fffSJeremy L Thompson // -- Laplacian 1002eaf62fffSJeremy L Thompson for (CeedInt i=0; i<P_1d; i++) 1003eaf62fffSJeremy L Thompson for (CeedInt j=0; j<P_1d; j++) { 1004eaf62fffSJeremy L Thompson CeedScalar sum = 0.0; 1005eaf62fffSJeremy L Thompson for (CeedInt k=0; k<Q_1d; k++) 1006eaf62fffSJeremy L Thompson sum += grad_1d[k*P_1d+i]*q_weight_1d[k]*grad_1d[k*P_1d+j]; 1007eaf62fffSJeremy L Thompson laplace[i+j*P_1d] = sum; 1008eaf62fffSJeremy L Thompson } 1009eaf62fffSJeremy L Thompson CeedScalar perturbation = dim>2 ? 1e-6 : 1e-4; 1010eaf62fffSJeremy L Thompson for (CeedInt i=0; i<P_1d; i++) 1011eaf62fffSJeremy L Thompson laplace[i+P_1d*i] += perturbation; 1012eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1013eaf62fffSJeremy L Thompson } 1014eaf62fffSJeremy L Thompson CeedPragmaOptimizeOn 1015eaf62fffSJeremy L Thompson 1016eaf62fffSJeremy L Thompson /// @} 1017eaf62fffSJeremy L Thompson 1018eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 1019eaf62fffSJeremy L Thompson /// CeedOperator Public API 1020eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 1021eaf62fffSJeremy L Thompson /// @addtogroup CeedOperatorUser 1022eaf62fffSJeremy L Thompson /// @{ 1023eaf62fffSJeremy L Thompson 1024eaf62fffSJeremy L Thompson /** 1025eaf62fffSJeremy L Thompson @brief Assemble a linear CeedQFunction associated with a CeedOperator 1026eaf62fffSJeremy L Thompson 1027eaf62fffSJeremy L Thompson This returns a CeedVector containing a matrix at each quadrature point 1028eaf62fffSJeremy L Thompson providing the action of the CeedQFunction associated with the CeedOperator. 1029eaf62fffSJeremy L Thompson The vector 'assembled' is of shape 1030eaf62fffSJeremy L Thompson [num_elements, num_input_fields, num_output_fields, num_quad_points] 1031eaf62fffSJeremy L Thompson and contains column-major matrices representing the action of the 1032eaf62fffSJeremy L Thompson CeedQFunction for a corresponding quadrature point on an element. Inputs and 1033eaf62fffSJeremy L Thompson outputs are in the order provided by the user when adding CeedOperator fields. 1034eaf62fffSJeremy L Thompson For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and 1035eaf62fffSJeremy L Thompson 'v', provided in that order, would result in an assembled QFunction that 1036eaf62fffSJeremy L Thompson consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting 1037eaf62fffSJeremy L Thompson on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v]. 1038eaf62fffSJeremy L Thompson 1039f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1040f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1041f04ea552SJeremy L Thompson 1042eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1043eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedQFunction at 1044eaf62fffSJeremy L Thompson quadrature points 1045eaf62fffSJeremy L Thompson @param[out] rstr CeedElemRestriction for CeedVector containing assembled 1046eaf62fffSJeremy L Thompson CeedQFunction 1047eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1048eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1049eaf62fffSJeremy L Thompson 1050eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1051eaf62fffSJeremy L Thompson 1052eaf62fffSJeremy L Thompson @ref User 1053eaf62fffSJeremy L Thompson **/ 1054eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled, 1055eaf62fffSJeremy L Thompson CeedElemRestriction *rstr, 1056eaf62fffSJeremy L Thompson CeedRequest *request) { 1057eaf62fffSJeremy L Thompson int ierr; 1058eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1059eaf62fffSJeremy L Thompson 1060eaf62fffSJeremy L Thompson // Backend version 1061eaf62fffSJeremy L Thompson if (op->LinearAssembleQFunction) { 1062*70a7ffb3SJeremy L Thompson ierr = op->LinearAssembleQFunction(op, assembled, rstr, request); 1063*70a7ffb3SJeremy L Thompson CeedChk(ierr); 1064eaf62fffSJeremy L Thompson } else { 1065eaf62fffSJeremy L Thompson // Fallback to reference Ceed 1066eaf62fffSJeremy L Thompson if (!op->op_fallback) { 1067eaf62fffSJeremy L Thompson ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1068eaf62fffSJeremy L Thompson } 1069eaf62fffSJeremy L Thompson // Assemble 1070eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunction(op->op_fallback, assembled, 1071eaf62fffSJeremy L Thompson rstr, request); CeedChk(ierr); 1072*70a7ffb3SJeremy L Thompson } 1073eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1074eaf62fffSJeremy L Thompson } 1075*70a7ffb3SJeremy L Thompson 1076*70a7ffb3SJeremy L Thompson /** 1077*70a7ffb3SJeremy L Thompson @brief Assemble CeedQFunction and store result internall. Return copied 1078*70a7ffb3SJeremy L Thompson references of stored data to the caller. Caller is responsible for 1079*70a7ffb3SJeremy L Thompson ownership and destruction of the copied references. See also 1080*70a7ffb3SJeremy L Thompson @ref CeedOperatorLinearAssembleQFunction 1081*70a7ffb3SJeremy L Thompson 1082*70a7ffb3SJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1083*70a7ffb3SJeremy L Thompson @param assembled CeedVector to store assembled CeedQFunction at 1084*70a7ffb3SJeremy L Thompson quadrature points 1085*70a7ffb3SJeremy L Thompson @param rstr CeedElemRestriction for CeedVector containing assembled 1086*70a7ffb3SJeremy L Thompson CeedQFunction 1087*70a7ffb3SJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1088*70a7ffb3SJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1089*70a7ffb3SJeremy L Thompson 1090*70a7ffb3SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1091*70a7ffb3SJeremy L Thompson 1092*70a7ffb3SJeremy L Thompson @ref User 1093*70a7ffb3SJeremy L Thompson **/ 1094*70a7ffb3SJeremy L Thompson int CeedOperatorLinearAssembleQFunctionBuildOrUpdate(CeedOperator op, 1095*70a7ffb3SJeremy L Thompson CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) { 1096*70a7ffb3SJeremy L Thompson int ierr; 1097*70a7ffb3SJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1098*70a7ffb3SJeremy L Thompson 1099*70a7ffb3SJeremy L Thompson // Backend version 1100*70a7ffb3SJeremy L Thompson if (op->LinearAssembleQFunctionUpdate) { 1101*70a7ffb3SJeremy L Thompson if (op->has_qf_assembled) { 1102*70a7ffb3SJeremy L Thompson ierr = op->LinearAssembleQFunctionUpdate(op, op->qf_assembled, 1103*70a7ffb3SJeremy L Thompson op->qf_assembled_rstr, request); 1104*70a7ffb3SJeremy L Thompson } else { 1105*70a7ffb3SJeremy L Thompson ierr = op->LinearAssembleQFunction(op, &op->qf_assembled, 1106*70a7ffb3SJeremy L Thompson &op->qf_assembled_rstr, request); 1107*70a7ffb3SJeremy L Thompson } 1108*70a7ffb3SJeremy L Thompson CeedChk(ierr); 1109*70a7ffb3SJeremy L Thompson op->has_qf_assembled = true; 1110*70a7ffb3SJeremy L Thompson // Copy reference to internally held copy 1111*70a7ffb3SJeremy L Thompson *assembled = NULL; 1112*70a7ffb3SJeremy L Thompson *rstr = NULL; 1113*70a7ffb3SJeremy L Thompson ierr = CeedVectorReferenceCopy(op->qf_assembled, assembled); CeedChk(ierr); 1114*70a7ffb3SJeremy L Thompson ierr = CeedElemRestrictionReferenceCopy(op->qf_assembled_rstr, rstr); 1115*70a7ffb3SJeremy L Thompson } else { 1116*70a7ffb3SJeremy L Thompson // Fallback to reference Ceed 1117*70a7ffb3SJeremy L Thompson if (!op->op_fallback) { 1118*70a7ffb3SJeremy L Thompson ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1119*70a7ffb3SJeremy L Thompson } 1120*70a7ffb3SJeremy L Thompson // Assemble 1121*70a7ffb3SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op->op_fallback, 1122*70a7ffb3SJeremy L Thompson assembled, rstr, request); CeedChk(ierr); 1123*70a7ffb3SJeremy L Thompson } 1124*70a7ffb3SJeremy L Thompson CeedChk(ierr); 1125*70a7ffb3SJeremy L Thompson 1126*70a7ffb3SJeremy L Thompson return CEED_ERROR_SUCCESS; 1127eaf62fffSJeremy L Thompson } 1128eaf62fffSJeremy L Thompson 1129eaf62fffSJeremy L Thompson /** 1130eaf62fffSJeremy L Thompson @brief Assemble the diagonal of a square linear CeedOperator 1131eaf62fffSJeremy L Thompson 1132eaf62fffSJeremy L Thompson This overwrites a CeedVector with the diagonal of a linear CeedOperator. 1133eaf62fffSJeremy L Thompson 1134eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1135eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1136eaf62fffSJeremy L Thompson 1137f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1138f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1139f04ea552SJeremy L Thompson 1140eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1141eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator diagonal 1142eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1143eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1144eaf62fffSJeremy L Thompson 1145eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1146eaf62fffSJeremy L Thompson 1147eaf62fffSJeremy L Thompson @ref User 1148eaf62fffSJeremy L Thompson **/ 1149eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled, 1150eaf62fffSJeremy L Thompson CeedRequest *request) { 1151eaf62fffSJeremy L Thompson int ierr; 1152eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1153eaf62fffSJeremy L Thompson 1154eaf62fffSJeremy L Thompson // Use backend version, if available 1155eaf62fffSJeremy L Thompson if (op->LinearAssembleDiagonal) { 1156eaf62fffSJeremy L Thompson ierr = op->LinearAssembleDiagonal(op, assembled, request); CeedChk(ierr); 1157eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1158eaf62fffSJeremy L Thompson } else if (op->LinearAssembleAddDiagonal) { 1159eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1160eaf62fffSJeremy L Thompson ierr = op->LinearAssembleAddDiagonal(op, assembled, request); CeedChk(ierr); 1161eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1162eaf62fffSJeremy L Thompson } else { 1163eaf62fffSJeremy L Thompson // Check for valid fallback resource 1164eaf62fffSJeremy L Thompson const char *resource, *fallback_resource; 1165eaf62fffSJeremy L Thompson ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr); 1166eaf62fffSJeremy L Thompson ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource); 1167eaf62fffSJeremy L Thompson CeedChk(ierr); 1168eaf62fffSJeremy L Thompson if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) { 1169eaf62fffSJeremy L Thompson // Fallback to reference Ceed 1170eaf62fffSJeremy L Thompson if (!op->op_fallback) { 1171eaf62fffSJeremy L Thompson ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1172eaf62fffSJeremy L Thompson } 1173eaf62fffSJeremy L Thompson // Assemble 1174eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssembleDiagonal(op->op_fallback, assembled, request); 1175eaf62fffSJeremy L Thompson CeedChk(ierr); 1176eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1177eaf62fffSJeremy L Thompson } 1178eaf62fffSJeremy L Thompson } 1179eaf62fffSJeremy L Thompson 1180eaf62fffSJeremy L Thompson // Default interface implementation 1181eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1182eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssembleAddDiagonal(op, assembled, request); 1183eaf62fffSJeremy L Thompson CeedChk(ierr); 1184eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1185eaf62fffSJeremy L Thompson } 1186eaf62fffSJeremy L Thompson 1187eaf62fffSJeremy L Thompson /** 1188eaf62fffSJeremy L Thompson @brief Assemble the diagonal of a square linear CeedOperator 1189eaf62fffSJeremy L Thompson 1190eaf62fffSJeremy L Thompson This sums into a CeedVector the diagonal of a linear CeedOperator. 1191eaf62fffSJeremy L Thompson 1192eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1193eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1194eaf62fffSJeremy L Thompson 1195f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1196f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1197f04ea552SJeremy L Thompson 1198eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1199eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator diagonal 1200eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1201eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1202eaf62fffSJeremy L Thompson 1203eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1204eaf62fffSJeremy L Thompson 1205eaf62fffSJeremy L Thompson @ref User 1206eaf62fffSJeremy L Thompson **/ 1207eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled, 1208eaf62fffSJeremy L Thompson CeedRequest *request) { 1209eaf62fffSJeremy L Thompson int ierr; 1210eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1211eaf62fffSJeremy L Thompson 1212eaf62fffSJeremy L Thompson // Use backend version, if available 1213eaf62fffSJeremy L Thompson if (op->LinearAssembleAddDiagonal) { 1214eaf62fffSJeremy L Thompson ierr = op->LinearAssembleAddDiagonal(op, assembled, request); CeedChk(ierr); 1215eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1216eaf62fffSJeremy L Thompson } else { 1217eaf62fffSJeremy L Thompson // Check for valid fallback resource 1218eaf62fffSJeremy L Thompson const char *resource, *fallback_resource; 1219eaf62fffSJeremy L Thompson ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr); 1220eaf62fffSJeremy L Thompson ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource); 1221eaf62fffSJeremy L Thompson CeedChk(ierr); 1222eaf62fffSJeremy L Thompson if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) { 1223eaf62fffSJeremy L Thompson // Fallback to reference Ceed 1224eaf62fffSJeremy L Thompson if (!op->op_fallback) { 1225eaf62fffSJeremy L Thompson ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1226eaf62fffSJeremy L Thompson } 1227eaf62fffSJeremy L Thompson // Assemble 1228eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssembleAddDiagonal(op->op_fallback, assembled, 1229eaf62fffSJeremy L Thompson request); CeedChk(ierr); 1230eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1231eaf62fffSJeremy L Thompson } 1232eaf62fffSJeremy L Thompson } 1233eaf62fffSJeremy L Thompson 1234eaf62fffSJeremy L Thompson // Default interface implementation 1235eaf62fffSJeremy L Thompson bool is_composite; 1236eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1237eaf62fffSJeremy L Thompson if (is_composite) { 1238eaf62fffSJeremy L Thompson ierr = CeedCompositeOperatorLinearAssembleAddDiagonal(op, request, 1239eaf62fffSJeremy L Thompson false, assembled); CeedChk(ierr); 1240eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1241eaf62fffSJeremy L Thompson } else { 1242eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssembleAddDiagonal(op, request, false, assembled); 1243eaf62fffSJeremy L Thompson CeedChk(ierr); 1244eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1245eaf62fffSJeremy L Thompson } 1246eaf62fffSJeremy L Thompson } 1247eaf62fffSJeremy L Thompson 1248eaf62fffSJeremy L Thompson /** 1249eaf62fffSJeremy L Thompson @brief Assemble the point block diagonal of a square linear CeedOperator 1250eaf62fffSJeremy L Thompson 1251eaf62fffSJeremy L Thompson This overwrites a CeedVector with the point block diagonal of a linear 1252eaf62fffSJeremy L Thompson CeedOperator. 1253eaf62fffSJeremy L Thompson 1254eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1255eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1256eaf62fffSJeremy L Thompson 1257f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1258f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1259f04ea552SJeremy L Thompson 1260eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1261eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator point block 1262eaf62fffSJeremy L Thompson diagonal, provided in row-major form with an 1263eaf62fffSJeremy L Thompson @a num_comp * @a num_comp block at each node. The dimensions 1264eaf62fffSJeremy L Thompson of this vector are derived from the active vector 1265eaf62fffSJeremy L Thompson for the CeedOperator. The array has shape 1266eaf62fffSJeremy L Thompson [nodes, component out, component in]. 1267eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1268eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 1269eaf62fffSJeremy L Thompson 1270eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1271eaf62fffSJeremy L Thompson 1272eaf62fffSJeremy L Thompson @ref User 1273eaf62fffSJeremy L Thompson **/ 1274eaf62fffSJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op, 1275eaf62fffSJeremy L Thompson CeedVector assembled, CeedRequest *request) { 1276eaf62fffSJeremy L Thompson int ierr; 1277eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1278eaf62fffSJeremy L Thompson 1279eaf62fffSJeremy L Thompson // Use backend version, if available 1280eaf62fffSJeremy L Thompson if (op->LinearAssemblePointBlockDiagonal) { 1281eaf62fffSJeremy L Thompson ierr = op->LinearAssemblePointBlockDiagonal(op, assembled, request); 1282eaf62fffSJeremy L Thompson CeedChk(ierr); 1283eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1284eaf62fffSJeremy L Thompson } else if (op->LinearAssembleAddPointBlockDiagonal) { 1285eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1286eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, 1287eaf62fffSJeremy L Thompson request); CeedChk(ierr); 1288eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1289eaf62fffSJeremy L Thompson } else { 1290eaf62fffSJeremy L Thompson // Check for valid fallback resource 1291eaf62fffSJeremy L Thompson const char *resource, *fallback_resource; 1292eaf62fffSJeremy L Thompson ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr); 1293eaf62fffSJeremy L Thompson ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource); 1294eaf62fffSJeremy L Thompson CeedChk(ierr); 1295eaf62fffSJeremy L Thompson if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) { 1296eaf62fffSJeremy L Thompson // Fallback to reference Ceed 1297eaf62fffSJeremy L Thompson if (!op->op_fallback) { 1298eaf62fffSJeremy L Thompson ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1299eaf62fffSJeremy L Thompson } 1300eaf62fffSJeremy L Thompson // Assemble 1301eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssemblePointBlockDiagonal(op->op_fallback, 1302eaf62fffSJeremy L Thompson assembled, request); CeedChk(ierr); 1303eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1304eaf62fffSJeremy L Thompson } 1305eaf62fffSJeremy L Thompson } 1306eaf62fffSJeremy L Thompson 1307eaf62fffSJeremy L Thompson // Default interface implementation 1308eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1309eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, request); 1310eaf62fffSJeremy L Thompson CeedChk(ierr); 1311eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1312eaf62fffSJeremy L Thompson } 1313eaf62fffSJeremy L Thompson 1314eaf62fffSJeremy L Thompson /** 1315eaf62fffSJeremy L Thompson @brief Assemble the point block diagonal of a square linear CeedOperator 1316eaf62fffSJeremy L Thompson 1317eaf62fffSJeremy L Thompson This sums into a CeedVector with the point block diagonal of a linear 1318eaf62fffSJeremy L Thompson CeedOperator. 1319eaf62fffSJeremy L Thompson 1320eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1321eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1322eaf62fffSJeremy L Thompson 1323f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1324f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1325f04ea552SJeremy L Thompson 1326eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1327eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator point block 1328eaf62fffSJeremy L Thompson diagonal, provided in row-major form with an 1329eaf62fffSJeremy L Thompson @a num_comp * @a num_comp block at each node. The dimensions 1330eaf62fffSJeremy L Thompson of this vector are derived from the active vector 1331eaf62fffSJeremy L Thompson for the CeedOperator. The array has shape 1332eaf62fffSJeremy L Thompson [nodes, component out, component in]. 1333eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1334eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 1335eaf62fffSJeremy L Thompson 1336eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1337eaf62fffSJeremy L Thompson 1338eaf62fffSJeremy L Thompson @ref User 1339eaf62fffSJeremy L Thompson **/ 1340eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op, 1341eaf62fffSJeremy L Thompson CeedVector assembled, CeedRequest *request) { 1342eaf62fffSJeremy L Thompson int ierr; 1343eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1344eaf62fffSJeremy L Thompson 1345eaf62fffSJeremy L Thompson // Use backend version, if available 1346eaf62fffSJeremy L Thompson if (op->LinearAssembleAddPointBlockDiagonal) { 1347eaf62fffSJeremy L Thompson ierr = op->LinearAssembleAddPointBlockDiagonal(op, assembled, request); 1348eaf62fffSJeremy L Thompson CeedChk(ierr); 1349eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1350eaf62fffSJeremy L Thompson } else { 1351eaf62fffSJeremy L Thompson // Check for valid fallback resource 1352eaf62fffSJeremy L Thompson const char *resource, *fallback_resource; 1353eaf62fffSJeremy L Thompson ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr); 1354eaf62fffSJeremy L Thompson ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource); 1355eaf62fffSJeremy L Thompson CeedChk(ierr); 1356eaf62fffSJeremy L Thompson if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) { 1357eaf62fffSJeremy L Thompson // Fallback to reference Ceed 1358eaf62fffSJeremy L Thompson if (!op->op_fallback) { 1359eaf62fffSJeremy L Thompson ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1360eaf62fffSJeremy L Thompson } 1361eaf62fffSJeremy L Thompson // Assemble 1362eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssembleAddPointBlockDiagonal(op->op_fallback, 1363eaf62fffSJeremy L Thompson assembled, request); CeedChk(ierr); 1364eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1365eaf62fffSJeremy L Thompson } 1366eaf62fffSJeremy L Thompson } 1367eaf62fffSJeremy L Thompson 1368eaf62fffSJeremy L Thompson // Default interface implemenation 1369eaf62fffSJeremy L Thompson bool is_composite; 1370eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1371eaf62fffSJeremy L Thompson if (is_composite) { 1372eaf62fffSJeremy L Thompson ierr = CeedCompositeOperatorLinearAssembleAddDiagonal(op, request, 1373eaf62fffSJeremy L Thompson true, assembled); CeedChk(ierr); 1374eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1375eaf62fffSJeremy L Thompson } else { 1376eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssembleAddDiagonal(op, request, true, assembled); 1377eaf62fffSJeremy L Thompson CeedChk(ierr); 1378eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1379eaf62fffSJeremy L Thompson } 1380eaf62fffSJeremy L Thompson } 1381eaf62fffSJeremy L Thompson 1382eaf62fffSJeremy L Thompson /** 1383eaf62fffSJeremy L Thompson @brief Fully assemble the nonzero pattern of a linear operator. 1384eaf62fffSJeremy L Thompson 1385eaf62fffSJeremy L Thompson Expected to be used in conjunction with CeedOperatorLinearAssemble() 1386eaf62fffSJeremy L Thompson 1387eaf62fffSJeremy L Thompson The assembly routines use coordinate format, with num_entries tuples of the 1388eaf62fffSJeremy L Thompson form (i, j, value) which indicate that value should be added to the matrix 1389eaf62fffSJeremy L Thompson in entry (i, j). Note that the (i, j) pairs are not unique and may repeat. 1390eaf62fffSJeremy L Thompson This function returns the number of entries and their (i, j) locations, 1391eaf62fffSJeremy L Thompson while CeedOperatorLinearAssemble() provides the values in the same 1392eaf62fffSJeremy L Thompson ordering. 1393eaf62fffSJeremy L Thompson 1394eaf62fffSJeremy L Thompson This will generally be slow unless your operator is low-order. 1395eaf62fffSJeremy L Thompson 1396f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1397f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1398f04ea552SJeremy L Thompson 1399eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 1400eaf62fffSJeremy L Thompson @param[out] num_entries Number of entries in coordinate nonzero pattern 1401eaf62fffSJeremy L Thompson @param[out] rows Row number for each entry 1402eaf62fffSJeremy L Thompson @param[out] cols Column number for each entry 1403eaf62fffSJeremy L Thompson 1404eaf62fffSJeremy L Thompson @ref User 1405eaf62fffSJeremy L Thompson **/ 1406eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleSymbolic(CeedOperator op, CeedInt *num_entries, 1407eaf62fffSJeremy L Thompson CeedInt **rows, CeedInt **cols) { 1408eaf62fffSJeremy L Thompson int ierr; 1409eaf62fffSJeremy L Thompson CeedInt num_suboperators, single_entries; 1410eaf62fffSJeremy L Thompson CeedOperator *sub_operators; 1411eaf62fffSJeremy L Thompson bool is_composite; 1412eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1413eaf62fffSJeremy L Thompson 1414eaf62fffSJeremy L Thompson // Use backend version, if available 1415eaf62fffSJeremy L Thompson if (op->LinearAssembleSymbolic) { 1416eaf62fffSJeremy L Thompson ierr = op->LinearAssembleSymbolic(op, num_entries, rows, cols); CeedChk(ierr); 1417eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1418eaf62fffSJeremy L Thompson } else { 1419eaf62fffSJeremy L Thompson // Check for valid fallback resource 1420eaf62fffSJeremy L Thompson const char *resource, *fallback_resource; 1421eaf62fffSJeremy L Thompson ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr); 1422eaf62fffSJeremy L Thompson ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource); 1423eaf62fffSJeremy L Thompson CeedChk(ierr); 1424eaf62fffSJeremy L Thompson if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) { 1425eaf62fffSJeremy L Thompson // Fallback to reference Ceed 1426eaf62fffSJeremy L Thompson if (!op->op_fallback) { 1427eaf62fffSJeremy L Thompson ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1428eaf62fffSJeremy L Thompson } 1429eaf62fffSJeremy L Thompson // Assemble 1430eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssembleSymbolic(op->op_fallback, num_entries, rows, 1431eaf62fffSJeremy L Thompson cols); CeedChk(ierr); 1432eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1433eaf62fffSJeremy L Thompson } 1434eaf62fffSJeremy L Thompson } 1435eaf62fffSJeremy L Thompson 1436eaf62fffSJeremy L Thompson // Default interface implementation 1437eaf62fffSJeremy L Thompson 1438eaf62fffSJeremy L Thompson // count entries and allocate rows, cols arrays 1439eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1440eaf62fffSJeremy L Thompson *num_entries = 0; 1441eaf62fffSJeremy L Thompson if (is_composite) { 1442eaf62fffSJeremy L Thompson ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1443eaf62fffSJeremy L Thompson ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1444eaf62fffSJeremy L Thompson for (int k = 0; k < num_suboperators; ++k) { 1445eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k], 1446eaf62fffSJeremy L Thompson &single_entries); CeedChk(ierr); 1447eaf62fffSJeremy L Thompson *num_entries += single_entries; 1448eaf62fffSJeremy L Thompson } 1449eaf62fffSJeremy L Thompson } else { 1450eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemblyCountEntries(op, 1451eaf62fffSJeremy L Thompson &single_entries); CeedChk(ierr); 1452eaf62fffSJeremy L Thompson *num_entries += single_entries; 1453eaf62fffSJeremy L Thompson } 1454eaf62fffSJeremy L Thompson ierr = CeedCalloc(*num_entries, rows); CeedChk(ierr); 1455eaf62fffSJeremy L Thompson ierr = CeedCalloc(*num_entries, cols); CeedChk(ierr); 1456eaf62fffSJeremy L Thompson 1457eaf62fffSJeremy L Thompson // assemble nonzero locations 1458eaf62fffSJeremy L Thompson CeedInt offset = 0; 1459eaf62fffSJeremy L Thompson if (is_composite) { 1460eaf62fffSJeremy L Thompson ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1461eaf62fffSJeremy L Thompson ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1462eaf62fffSJeremy L Thompson for (int k = 0; k < num_suboperators; ++k) { 1463eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssembleSymbolic(sub_operators[k], offset, *rows, 1464eaf62fffSJeremy L Thompson *cols); CeedChk(ierr); 1465eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k], 1466eaf62fffSJeremy L Thompson &single_entries); 1467eaf62fffSJeremy L Thompson CeedChk(ierr); 1468eaf62fffSJeremy L Thompson offset += single_entries; 1469eaf62fffSJeremy L Thompson } 1470eaf62fffSJeremy L Thompson } else { 1471eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssembleSymbolic(op, offset, *rows, *cols); 1472eaf62fffSJeremy L Thompson CeedChk(ierr); 1473eaf62fffSJeremy L Thompson } 1474eaf62fffSJeremy L Thompson 1475eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1476eaf62fffSJeremy L Thompson } 1477eaf62fffSJeremy L Thompson 1478eaf62fffSJeremy L Thompson /** 1479eaf62fffSJeremy L Thompson @brief Fully assemble the nonzero entries of a linear operator. 1480eaf62fffSJeremy L Thompson 1481eaf62fffSJeremy L Thompson Expected to be used in conjunction with CeedOperatorLinearAssembleSymbolic() 1482eaf62fffSJeremy L Thompson 1483eaf62fffSJeremy L Thompson The assembly routines use coordinate format, with num_entries tuples of the 1484eaf62fffSJeremy L Thompson form (i, j, value) which indicate that value should be added to the matrix 1485eaf62fffSJeremy L Thompson in entry (i, j). Note that the (i, j) pairs are not unique and may repeat. 1486eaf62fffSJeremy L Thompson This function returns the values of the nonzero entries to be added, their 1487eaf62fffSJeremy L Thompson (i, j) locations are provided by CeedOperatorLinearAssembleSymbolic() 1488eaf62fffSJeremy L Thompson 1489eaf62fffSJeremy L Thompson This will generally be slow unless your operator is low-order. 1490eaf62fffSJeremy L Thompson 1491f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1492f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1493f04ea552SJeremy L Thompson 1494eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 1495eaf62fffSJeremy L Thompson @param[out] values Values to assemble into matrix 1496eaf62fffSJeremy L Thompson 1497eaf62fffSJeremy L Thompson @ref User 1498eaf62fffSJeremy L Thompson **/ 1499eaf62fffSJeremy L Thompson int CeedOperatorLinearAssemble(CeedOperator op, CeedVector values) { 1500eaf62fffSJeremy L Thompson int ierr; 1501eaf62fffSJeremy L Thompson CeedInt num_suboperators, single_entries = 0; 1502eaf62fffSJeremy L Thompson CeedOperator *sub_operators; 1503eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1504eaf62fffSJeremy L Thompson 1505eaf62fffSJeremy L Thompson // Use backend version, if available 1506eaf62fffSJeremy L Thompson if (op->LinearAssemble) { 1507eaf62fffSJeremy L Thompson ierr = op->LinearAssemble(op, values); CeedChk(ierr); 1508eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1509eaf62fffSJeremy L Thompson } else { 1510eaf62fffSJeremy L Thompson // Check for valid fallback resource 1511eaf62fffSJeremy L Thompson const char *resource, *fallback_resource; 1512eaf62fffSJeremy L Thompson ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr); 1513eaf62fffSJeremy L Thompson ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource); 1514eaf62fffSJeremy L Thompson CeedChk(ierr); 1515eaf62fffSJeremy L Thompson if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) { 1516eaf62fffSJeremy L Thompson // Fallback to reference Ceed 1517eaf62fffSJeremy L Thompson if (!op->op_fallback) { 1518eaf62fffSJeremy L Thompson ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1519eaf62fffSJeremy L Thompson } 1520eaf62fffSJeremy L Thompson // Assemble 1521eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssemble(op->op_fallback, values); CeedChk(ierr); 1522eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1523eaf62fffSJeremy L Thompson } 1524eaf62fffSJeremy L Thompson } 1525eaf62fffSJeremy L Thompson 1526eaf62fffSJeremy L Thompson // Default interface implementation 1527eaf62fffSJeremy L Thompson bool is_composite; 1528eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1529eaf62fffSJeremy L Thompson 1530eaf62fffSJeremy L Thompson CeedInt offset = 0; 1531eaf62fffSJeremy L Thompson if (is_composite) { 1532eaf62fffSJeremy L Thompson ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1533eaf62fffSJeremy L Thompson ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1534eaf62fffSJeremy L Thompson for (int k = 0; k < num_suboperators; ++k) { 1535eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemble(sub_operators[k], offset, values); 1536eaf62fffSJeremy L Thompson CeedChk(ierr); 1537eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k], 1538eaf62fffSJeremy L Thompson &single_entries); 1539eaf62fffSJeremy L Thompson CeedChk(ierr); 1540eaf62fffSJeremy L Thompson offset += single_entries; 1541eaf62fffSJeremy L Thompson } 1542eaf62fffSJeremy L Thompson } else { 1543eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemble(op, offset, values); CeedChk(ierr); 1544eaf62fffSJeremy L Thompson } 1545eaf62fffSJeremy L Thompson 1546eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1547eaf62fffSJeremy L Thompson } 1548eaf62fffSJeremy L Thompson 1549eaf62fffSJeremy L Thompson /** 1550eaf62fffSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators 1551eaf62fffSJeremy L Thompson for a CeedOperator, creating the prolongation basis from the 1552eaf62fffSJeremy L Thompson fine and coarse grid interpolation 1553eaf62fffSJeremy L Thompson 1554f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1555f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1556f04ea552SJeremy L Thompson 1557eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 1558eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 1559eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 1560eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 1561eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 1562eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 1563eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 1564eaf62fffSJeremy L Thompson 1565eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1566eaf62fffSJeremy L Thompson 1567eaf62fffSJeremy L Thompson @ref User 1568eaf62fffSJeremy L Thompson **/ 1569eaf62fffSJeremy L Thompson int CeedOperatorMultigridLevelCreate(CeedOperator op_fine, 1570eaf62fffSJeremy L Thompson CeedVector p_mult_fine, 1571eaf62fffSJeremy L Thompson CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 1572eaf62fffSJeremy L Thompson CeedOperator *op_coarse, CeedOperator *op_prolong, 1573eaf62fffSJeremy L Thompson CeedOperator *op_restrict) { 1574eaf62fffSJeremy L Thompson int ierr; 1575f04ea552SJeremy L Thompson ierr = CeedOperatorCheckReady(op_fine); CeedChk(ierr); 1576eaf62fffSJeremy L Thompson Ceed ceed; 1577eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr); 1578eaf62fffSJeremy L Thompson 1579eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 1580eaf62fffSJeremy L Thompson CeedBasis basis_fine; 1581eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr); 1582eaf62fffSJeremy L Thompson CeedInt Q_f, Q_c; 1583eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr); 1584eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr); 1585eaf62fffSJeremy L Thompson if (Q_f != Q_c) 1586eaf62fffSJeremy L Thompson // LCOV_EXCL_START 1587eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, 1588eaf62fffSJeremy L Thompson "Bases must have compatible quadrature spaces"); 1589eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 1590eaf62fffSJeremy L Thompson 1591eaf62fffSJeremy L Thompson // Coarse to fine basis 1592eaf62fffSJeremy L Thompson CeedInt P_f, P_c, Q = Q_f; 1593eaf62fffSJeremy L Thompson bool is_tensor_f, is_tensor_c; 1594eaf62fffSJeremy L Thompson ierr = CeedBasisIsTensor(basis_fine, &is_tensor_f); CeedChk(ierr); 1595eaf62fffSJeremy L Thompson ierr = CeedBasisIsTensor(basis_coarse, &is_tensor_c); CeedChk(ierr); 1596eaf62fffSJeremy L Thompson CeedScalar *interp_c, *interp_f, *interp_c_to_f, *tau; 1597eaf62fffSJeremy L Thompson if (is_tensor_f && is_tensor_c) { 1598eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes1D(basis_fine, &P_f); CeedChk(ierr); 1599eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes1D(basis_coarse, &P_c); CeedChk(ierr); 1600eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints1D(basis_coarse, &Q); CeedChk(ierr); 1601eaf62fffSJeremy L Thompson } else if (!is_tensor_f && !is_tensor_c) { 1602eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis_fine, &P_f); CeedChk(ierr); 1603eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis_coarse, &P_c); CeedChk(ierr); 1604eaf62fffSJeremy L Thompson } else { 1605eaf62fffSJeremy L Thompson // LCOV_EXCL_START 1606eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_MINOR, 1607eaf62fffSJeremy L Thompson "Bases must both be tensor or non-tensor"); 1608eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 1609eaf62fffSJeremy L Thompson } 1610eaf62fffSJeremy L Thompson 1611eaf62fffSJeremy L Thompson ierr = CeedMalloc(Q*P_f, &interp_f); CeedChk(ierr); 1612eaf62fffSJeremy L Thompson ierr = CeedMalloc(Q*P_c, &interp_c); CeedChk(ierr); 1613eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_c*P_f, &interp_c_to_f); CeedChk(ierr); 1614eaf62fffSJeremy L Thompson ierr = CeedMalloc(Q, &tau); CeedChk(ierr); 1615eaf62fffSJeremy L Thompson if (is_tensor_f) { 1616eaf62fffSJeremy L Thompson memcpy(interp_f, basis_fine->interp_1d, Q*P_f*sizeof basis_fine->interp_1d[0]); 1617eaf62fffSJeremy L Thompson memcpy(interp_c, basis_coarse->interp_1d, 1618eaf62fffSJeremy L Thompson Q*P_c*sizeof basis_coarse->interp_1d[0]); 1619eaf62fffSJeremy L Thompson } else { 1620eaf62fffSJeremy L Thompson memcpy(interp_f, basis_fine->interp, Q*P_f*sizeof basis_fine->interp[0]); 1621eaf62fffSJeremy L Thompson memcpy(interp_c, basis_coarse->interp, Q*P_c*sizeof basis_coarse->interp[0]); 1622eaf62fffSJeremy L Thompson } 1623eaf62fffSJeremy L Thompson 1624eaf62fffSJeremy L Thompson // -- QR Factorization, interp_f = Q R 1625eaf62fffSJeremy L Thompson ierr = CeedQRFactorization(ceed, interp_f, tau, Q, P_f); CeedChk(ierr); 1626eaf62fffSJeremy L Thompson 1627eaf62fffSJeremy L Thompson // -- Apply Qtranspose, interp_c = Qtranspose interp_c 1628eaf62fffSJeremy L Thompson ierr = CeedHouseholderApplyQ(interp_c, interp_f, tau, CEED_TRANSPOSE, 1629eaf62fffSJeremy L Thompson Q, P_c, P_f, P_c, 1); CeedChk(ierr); 1630eaf62fffSJeremy L Thompson 1631eaf62fffSJeremy L Thompson // -- Apply Rinv, interp_c_to_f = Rinv interp_c 1632eaf62fffSJeremy L Thompson for (CeedInt j=0; j<P_c; j++) { // Column j 1633eaf62fffSJeremy L Thompson interp_c_to_f[j+P_c*(P_f-1)] = interp_c[j+P_c*(P_f-1)]/interp_f[P_f*P_f-1]; 1634eaf62fffSJeremy L Thompson for (CeedInt i=P_f-2; i>=0; i--) { // Row i 1635eaf62fffSJeremy L Thompson interp_c_to_f[j+P_c*i] = interp_c[j+P_c*i]; 1636eaf62fffSJeremy L Thompson for (CeedInt k=i+1; k<P_f; k++) 1637eaf62fffSJeremy L Thompson interp_c_to_f[j+P_c*i] -= interp_f[k+P_f*i]*interp_c_to_f[j+P_c*k]; 1638eaf62fffSJeremy L Thompson interp_c_to_f[j+P_c*i] /= interp_f[i+P_f*i]; 1639eaf62fffSJeremy L Thompson } 1640eaf62fffSJeremy L Thompson } 1641eaf62fffSJeremy L Thompson ierr = CeedFree(&tau); CeedChk(ierr); 1642eaf62fffSJeremy L Thompson ierr = CeedFree(&interp_c); CeedChk(ierr); 1643eaf62fffSJeremy L Thompson ierr = CeedFree(&interp_f); CeedChk(ierr); 1644eaf62fffSJeremy L Thompson 1645eaf62fffSJeremy L Thompson // Complete with interp_c_to_f versions of code 1646eaf62fffSJeremy L Thompson if (is_tensor_f) { 1647eaf62fffSJeremy L Thompson ierr = CeedOperatorMultigridLevelCreateTensorH1(op_fine, p_mult_fine, 1648eaf62fffSJeremy L Thompson rstr_coarse, basis_coarse, interp_c_to_f, op_coarse, op_prolong, op_restrict); 1649eaf62fffSJeremy L Thompson CeedChk(ierr); 1650eaf62fffSJeremy L Thompson } else { 1651eaf62fffSJeremy L Thompson ierr = CeedOperatorMultigridLevelCreateH1(op_fine, p_mult_fine, 1652eaf62fffSJeremy L Thompson rstr_coarse, basis_coarse, interp_c_to_f, op_coarse, op_prolong, op_restrict); 1653eaf62fffSJeremy L Thompson CeedChk(ierr); 1654eaf62fffSJeremy L Thompson } 1655eaf62fffSJeremy L Thompson 1656eaf62fffSJeremy L Thompson // Cleanup 1657eaf62fffSJeremy L Thompson ierr = CeedFree(&interp_c_to_f); CeedChk(ierr); 1658eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1659eaf62fffSJeremy L Thompson } 1660eaf62fffSJeremy L Thompson 1661eaf62fffSJeremy L Thompson /** 1662eaf62fffSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators 1663eaf62fffSJeremy L Thompson for a CeedOperator with a tensor basis for the active basis 1664eaf62fffSJeremy L Thompson 1665f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1666f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1667f04ea552SJeremy L Thompson 1668eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 1669eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 1670eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 1671eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 1672eaf62fffSJeremy L Thompson @param[in] interp_c_to_f Matrix for coarse to fine interpolation 1673eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 1674eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 1675eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 1676eaf62fffSJeremy L Thompson 1677eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1678eaf62fffSJeremy L Thompson 1679eaf62fffSJeremy L Thompson @ref User 1680eaf62fffSJeremy L Thompson **/ 1681eaf62fffSJeremy L Thompson int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator op_fine, 1682eaf62fffSJeremy L Thompson CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 1683eaf62fffSJeremy L Thompson const CeedScalar *interp_c_to_f, CeedOperator *op_coarse, 1684eaf62fffSJeremy L Thompson CeedOperator *op_prolong, CeedOperator *op_restrict) { 1685eaf62fffSJeremy L Thompson int ierr; 1686f04ea552SJeremy L Thompson ierr = CeedOperatorCheckReady(op_fine); CeedChk(ierr); 1687eaf62fffSJeremy L Thompson Ceed ceed; 1688eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr); 1689eaf62fffSJeremy L Thompson 1690eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 1691eaf62fffSJeremy L Thompson CeedBasis basis_fine; 1692eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr); 1693eaf62fffSJeremy L Thompson CeedInt Q_f, Q_c; 1694eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr); 1695eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr); 1696eaf62fffSJeremy L Thompson if (Q_f != Q_c) 1697eaf62fffSJeremy L Thompson // LCOV_EXCL_START 1698eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, 1699eaf62fffSJeremy L Thompson "Bases must have compatible quadrature spaces"); 1700eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 1701eaf62fffSJeremy L Thompson 1702eaf62fffSJeremy L Thompson // Coarse to fine basis 1703eaf62fffSJeremy L Thompson CeedInt dim, num_comp, num_nodes_c, P_1d_f, P_1d_c; 1704eaf62fffSJeremy L Thompson ierr = CeedBasisGetDimension(basis_fine, &dim); CeedChk(ierr); 1705eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis_fine, &num_comp); CeedChk(ierr); 1706eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes1D(basis_fine, &P_1d_f); CeedChk(ierr); 1707eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c); 1708eaf62fffSJeremy L Thompson CeedChk(ierr); 1709eaf62fffSJeremy L Thompson P_1d_c = dim == 1 ? num_nodes_c : 1710eaf62fffSJeremy L Thompson dim == 2 ? sqrt(num_nodes_c) : 1711eaf62fffSJeremy L Thompson cbrt(num_nodes_c); 1712eaf62fffSJeremy L Thompson CeedScalar *q_ref, *q_weight, *grad; 1713eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d_f, &q_ref); CeedChk(ierr); 1714eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d_f, &q_weight); CeedChk(ierr); 1715eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d_f*P_1d_c*dim, &grad); CeedChk(ierr); 1716eaf62fffSJeremy L Thompson CeedBasis basis_c_to_f; 1717eaf62fffSJeremy L Thompson ierr = CeedBasisCreateTensorH1(ceed, dim, num_comp, P_1d_c, P_1d_f, 1718eaf62fffSJeremy L Thompson interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f); 1719eaf62fffSJeremy L Thompson CeedChk(ierr); 1720eaf62fffSJeremy L Thompson ierr = CeedFree(&q_ref); CeedChk(ierr); 1721eaf62fffSJeremy L Thompson ierr = CeedFree(&q_weight); CeedChk(ierr); 1722eaf62fffSJeremy L Thompson ierr = CeedFree(&grad); CeedChk(ierr); 1723eaf62fffSJeremy L Thompson 1724eaf62fffSJeremy L Thompson // Core code 1725eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, 1726eaf62fffSJeremy L Thompson basis_coarse, basis_c_to_f, op_coarse, 1727eaf62fffSJeremy L Thompson op_prolong, op_restrict); 1728eaf62fffSJeremy L Thompson CeedChk(ierr); 1729eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1730eaf62fffSJeremy L Thompson } 1731eaf62fffSJeremy L Thompson 1732eaf62fffSJeremy L Thompson /** 1733eaf62fffSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators 1734eaf62fffSJeremy L Thompson for a CeedOperator with a non-tensor basis for the active vector 1735eaf62fffSJeremy L Thompson 1736f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1737f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1738f04ea552SJeremy L Thompson 1739eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 1740eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 1741eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 1742eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 1743eaf62fffSJeremy L Thompson @param[in] interp_c_to_f Matrix for coarse to fine interpolation 1744eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 1745eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 1746eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 1747eaf62fffSJeremy L Thompson 1748eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1749eaf62fffSJeremy L Thompson 1750eaf62fffSJeremy L Thompson @ref User 1751eaf62fffSJeremy L Thompson **/ 1752eaf62fffSJeremy L Thompson int CeedOperatorMultigridLevelCreateH1(CeedOperator op_fine, 1753eaf62fffSJeremy L Thompson CeedVector p_mult_fine, 1754eaf62fffSJeremy L Thompson CeedElemRestriction rstr_coarse, 1755eaf62fffSJeremy L Thompson CeedBasis basis_coarse, 1756eaf62fffSJeremy L Thompson const CeedScalar *interp_c_to_f, 1757eaf62fffSJeremy L Thompson CeedOperator *op_coarse, 1758eaf62fffSJeremy L Thompson CeedOperator *op_prolong, 1759eaf62fffSJeremy L Thompson CeedOperator *op_restrict) { 1760eaf62fffSJeremy L Thompson int ierr; 1761f04ea552SJeremy L Thompson ierr = CeedOperatorCheckReady(op_fine); CeedChk(ierr); 1762eaf62fffSJeremy L Thompson Ceed ceed; 1763eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr); 1764eaf62fffSJeremy L Thompson 1765eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 1766eaf62fffSJeremy L Thompson CeedBasis basis_fine; 1767eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr); 1768eaf62fffSJeremy L Thompson CeedInt Q_f, Q_c; 1769eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr); 1770eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr); 1771eaf62fffSJeremy L Thompson if (Q_f != Q_c) 1772eaf62fffSJeremy L Thompson // LCOV_EXCL_START 1773eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, 1774eaf62fffSJeremy L Thompson "Bases must have compatible quadrature spaces"); 1775eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 1776eaf62fffSJeremy L Thompson 1777eaf62fffSJeremy L Thompson // Coarse to fine basis 1778eaf62fffSJeremy L Thompson CeedElemTopology topo; 1779eaf62fffSJeremy L Thompson ierr = CeedBasisGetTopology(basis_fine, &topo); CeedChk(ierr); 1780eaf62fffSJeremy L Thompson CeedInt dim, num_comp, num_nodes_c, num_nodes_f; 1781eaf62fffSJeremy L Thompson ierr = CeedBasisGetDimension(basis_fine, &dim); CeedChk(ierr); 1782eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis_fine, &num_comp); CeedChk(ierr); 1783eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis_fine, &num_nodes_f); CeedChk(ierr); 1784eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c); 1785eaf62fffSJeremy L Thompson CeedChk(ierr); 1786eaf62fffSJeremy L Thompson CeedScalar *q_ref, *q_weight, *grad; 1787eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_nodes_f, &q_ref); CeedChk(ierr); 1788eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_nodes_f, &q_weight); CeedChk(ierr); 1789eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_nodes_f*num_nodes_c*dim, &grad); CeedChk(ierr); 1790eaf62fffSJeremy L Thompson CeedBasis basis_c_to_f; 1791eaf62fffSJeremy L Thompson ierr = CeedBasisCreateH1(ceed, topo, num_comp, num_nodes_c, num_nodes_f, 1792eaf62fffSJeremy L Thompson interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f); 1793eaf62fffSJeremy L Thompson CeedChk(ierr); 1794eaf62fffSJeremy L Thompson ierr = CeedFree(&q_ref); CeedChk(ierr); 1795eaf62fffSJeremy L Thompson ierr = CeedFree(&q_weight); CeedChk(ierr); 1796eaf62fffSJeremy L Thompson ierr = CeedFree(&grad); CeedChk(ierr); 1797eaf62fffSJeremy L Thompson 1798eaf62fffSJeremy L Thompson // Core code 1799eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, 1800eaf62fffSJeremy L Thompson basis_coarse, basis_c_to_f, op_coarse, 1801eaf62fffSJeremy L Thompson op_prolong, op_restrict); 1802eaf62fffSJeremy L Thompson CeedChk(ierr); 1803eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1804eaf62fffSJeremy L Thompson } 1805eaf62fffSJeremy L Thompson 1806eaf62fffSJeremy L Thompson /** 1807eaf62fffSJeremy L Thompson @brief Build a FDM based approximate inverse for each element for a 1808eaf62fffSJeremy L Thompson CeedOperator 1809eaf62fffSJeremy L Thompson 1810eaf62fffSJeremy L Thompson This returns a CeedOperator and CeedVector to apply a Fast Diagonalization 1811eaf62fffSJeremy L Thompson Method based approximate inverse. This function obtains the simultaneous 1812eaf62fffSJeremy L Thompson diagonalization for the 1D mass and Laplacian operators, 1813eaf62fffSJeremy L Thompson M = V^T V, K = V^T S V. 1814eaf62fffSJeremy L Thompson The assembled QFunction is used to modify the eigenvalues from simultaneous 1815eaf62fffSJeremy L Thompson diagonalization and obtain an approximate inverse of the form 1816eaf62fffSJeremy L Thompson V^T S^hat V. The CeedOperator must be linear and non-composite. The 1817eaf62fffSJeremy L Thompson associated CeedQFunction must therefore also be linear. 1818eaf62fffSJeremy L Thompson 1819f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1820f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1821f04ea552SJeremy L Thompson 1822eaf62fffSJeremy L Thompson @param op CeedOperator to create element inverses 1823eaf62fffSJeremy L Thompson @param[out] fdm_inv CeedOperator to apply the action of a FDM based inverse 1824eaf62fffSJeremy L Thompson for each element 1825eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1826eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1827eaf62fffSJeremy L Thompson 1828eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1829eaf62fffSJeremy L Thompson 1830eaf62fffSJeremy L Thompson @ref Backend 1831eaf62fffSJeremy L Thompson **/ 1832eaf62fffSJeremy L Thompson int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdm_inv, 1833eaf62fffSJeremy L Thompson CeedRequest *request) { 1834eaf62fffSJeremy L Thompson int ierr; 1835eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1836eaf62fffSJeremy L Thompson 1837eaf62fffSJeremy L Thompson // Use backend version, if available 1838eaf62fffSJeremy L Thompson if (op->CreateFDMElementInverse) { 1839eaf62fffSJeremy L Thompson ierr = op->CreateFDMElementInverse(op, fdm_inv, request); CeedChk(ierr); 1840eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1841eaf62fffSJeremy L Thompson } else { 1842eaf62fffSJeremy L Thompson // Check for valid fallback resource 1843eaf62fffSJeremy L Thompson const char *resource, *fallback_resource; 1844eaf62fffSJeremy L Thompson ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr); 1845eaf62fffSJeremy L Thompson ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource); 1846eaf62fffSJeremy L Thompson CeedChk(ierr); 1847eaf62fffSJeremy L Thompson if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) { 1848eaf62fffSJeremy L Thompson // Fallback to reference Ceed 1849eaf62fffSJeremy L Thompson if (!op->op_fallback) { 1850eaf62fffSJeremy L Thompson ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1851eaf62fffSJeremy L Thompson } 1852eaf62fffSJeremy L Thompson // Assemble 1853eaf62fffSJeremy L Thompson ierr = CeedOperatorCreateFDMElementInverse(op->op_fallback, fdm_inv, request); 1854eaf62fffSJeremy L Thompson CeedChk(ierr); 1855eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1856eaf62fffSJeremy L Thompson } 1857eaf62fffSJeremy L Thompson } 1858eaf62fffSJeremy L Thompson 1859eaf62fffSJeremy L Thompson // Interface implementation 1860eaf62fffSJeremy L Thompson Ceed ceed, ceed_parent; 1861eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 1862eaf62fffSJeremy L Thompson ierr = CeedGetOperatorFallbackParentCeed(ceed, &ceed_parent); CeedChk(ierr); 1863eaf62fffSJeremy L Thompson ceed_parent = ceed_parent ? ceed_parent : ceed; 1864eaf62fffSJeremy L Thompson CeedQFunction qf; 1865eaf62fffSJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr); 1866eaf62fffSJeremy L Thompson 1867eaf62fffSJeremy L Thompson // Determine active input basis 1868eaf62fffSJeremy L Thompson bool interp = false, grad = false; 1869eaf62fffSJeremy L Thompson CeedBasis basis = NULL; 1870eaf62fffSJeremy L Thompson CeedElemRestriction rstr = NULL; 1871eaf62fffSJeremy L Thompson CeedOperatorField *op_fields; 1872eaf62fffSJeremy L Thompson CeedQFunctionField *qf_fields; 1873eaf62fffSJeremy L Thompson CeedInt num_input_fields; 18747e7773b5SJeremy L Thompson ierr = CeedOperatorGetFields(op, &num_input_fields, &op_fields, NULL, NULL); 18757e7773b5SJeremy L Thompson CeedChk(ierr); 18767e7773b5SJeremy L Thompson ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL); CeedChk(ierr); 1877eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_input_fields; i++) { 1878eaf62fffSJeremy L Thompson CeedVector vec; 1879eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChk(ierr); 1880eaf62fffSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 1881eaf62fffSJeremy L Thompson CeedEvalMode eval_mode; 1882eaf62fffSJeremy L Thompson ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); CeedChk(ierr); 1883eaf62fffSJeremy L Thompson interp = interp || eval_mode == CEED_EVAL_INTERP; 1884eaf62fffSJeremy L Thompson grad = grad || eval_mode == CEED_EVAL_GRAD; 1885eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis); CeedChk(ierr); 1886eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr); CeedChk(ierr); 1887eaf62fffSJeremy L Thompson } 1888eaf62fffSJeremy L Thompson } 1889eaf62fffSJeremy L Thompson if (!basis) 1890eaf62fffSJeremy L Thompson // LCOV_EXCL_START 1891eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "No active field set"); 1892eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 1893eaf62fffSJeremy L Thompson CeedInt P_1d, Q_1d, elem_size, num_qpts, dim, num_comp = 1, num_elem = 1, 1894eaf62fffSJeremy L Thompson l_size = 1; 1895eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes1D(basis, &P_1d); CeedChk(ierr); 1896eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis, &elem_size); CeedChk(ierr); 1897eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d); CeedChk(ierr); 1898eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis, &num_qpts); CeedChk(ierr); 1899eaf62fffSJeremy L Thompson ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr); 1900eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis, &num_comp); CeedChk(ierr); 1901eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr); 1902eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetLVectorSize(rstr, &l_size); CeedChk(ierr); 1903eaf62fffSJeremy L Thompson 1904eaf62fffSJeremy L Thompson // Build and diagonalize 1D Mass and Laplacian 1905eaf62fffSJeremy L Thompson bool tensor_basis; 1906eaf62fffSJeremy L Thompson ierr = CeedBasisIsTensor(basis, &tensor_basis); CeedChk(ierr); 1907eaf62fffSJeremy L Thompson if (!tensor_basis) 1908eaf62fffSJeremy L Thompson // LCOV_EXCL_START 1909eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 1910eaf62fffSJeremy L Thompson "FDMElementInverse only supported for tensor " 1911eaf62fffSJeremy L Thompson "bases"); 1912eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 1913eaf62fffSJeremy L Thompson CeedScalar *mass, *laplace, *x, *fdm_interp, *lambda; 1914eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &mass); CeedChk(ierr); 1915eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &laplace); CeedChk(ierr); 1916eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &x); CeedChk(ierr); 1917eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &fdm_interp); CeedChk(ierr); 1918eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d, &lambda); CeedChk(ierr); 1919eaf62fffSJeremy L Thompson // -- Build matrices 1920eaf62fffSJeremy L Thompson const CeedScalar *interp_1d, *grad_1d, *q_weight_1d; 1921eaf62fffSJeremy L Thompson ierr = CeedBasisGetInterp1D(basis, &interp_1d); CeedChk(ierr); 1922eaf62fffSJeremy L Thompson ierr = CeedBasisGetGrad1D(basis, &grad_1d); CeedChk(ierr); 1923eaf62fffSJeremy L Thompson ierr = CeedBasisGetQWeights(basis, &q_weight_1d); CeedChk(ierr); 1924eaf62fffSJeremy L Thompson ierr = CeedBuildMassLaplace(interp_1d, grad_1d, q_weight_1d, P_1d, Q_1d, dim, 1925eaf62fffSJeremy L Thompson mass, laplace); CeedChk(ierr); 1926eaf62fffSJeremy L Thompson 1927eaf62fffSJeremy L Thompson // -- Diagonalize 1928eaf62fffSJeremy L Thompson ierr = CeedSimultaneousDiagonalization(ceed, laplace, mass, x, lambda, P_1d); 1929eaf62fffSJeremy L Thompson CeedChk(ierr); 1930eaf62fffSJeremy L Thompson ierr = CeedFree(&mass); CeedChk(ierr); 1931eaf62fffSJeremy L Thompson ierr = CeedFree(&laplace); CeedChk(ierr); 1932eaf62fffSJeremy L Thompson for (CeedInt i=0; i<P_1d; i++) 1933eaf62fffSJeremy L Thompson for (CeedInt j=0; j<P_1d; j++) 1934eaf62fffSJeremy L Thompson fdm_interp[i+j*P_1d] = x[j+i*P_1d]; 1935eaf62fffSJeremy L Thompson ierr = CeedFree(&x); CeedChk(ierr); 1936eaf62fffSJeremy L Thompson 1937eaf62fffSJeremy L Thompson // Assemble QFunction 1938eaf62fffSJeremy L Thompson CeedVector assembled; 1939eaf62fffSJeremy L Thompson CeedElemRestriction rstr_qf; 1940*70a7ffb3SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled, 1941*70a7ffb3SJeremy L Thompson &rstr_qf, request); CeedChk(ierr); 1942eaf62fffSJeremy L Thompson CeedInt layout[3]; 1943eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetELayout(rstr_qf, &layout); CeedChk(ierr); 1944eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr_qf); CeedChk(ierr); 1945eaf62fffSJeremy L Thompson CeedScalar max_norm = 0; 1946eaf62fffSJeremy L Thompson ierr = CeedVectorNorm(assembled, CEED_NORM_MAX, &max_norm); CeedChk(ierr); 1947eaf62fffSJeremy L Thompson 1948eaf62fffSJeremy L Thompson // Calculate element averages 1949eaf62fffSJeremy L Thompson CeedInt num_modes = (interp?1:0) + (grad?dim:0); 1950eaf62fffSJeremy L Thompson CeedScalar *elem_avg; 1951eaf62fffSJeremy L Thompson const CeedScalar *assembled_array, *q_weight_array; 1952eaf62fffSJeremy L Thompson CeedVector q_weight; 1953eaf62fffSJeremy L Thompson ierr = CeedVectorCreate(ceed_parent, num_qpts, &q_weight); CeedChk(ierr); 1954eaf62fffSJeremy L Thompson ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, 1955eaf62fffSJeremy L Thompson CEED_VECTOR_NONE, q_weight); CeedChk(ierr); 1956eaf62fffSJeremy L Thompson ierr = CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembled_array); 1957eaf62fffSJeremy L Thompson CeedChk(ierr); 1958eaf62fffSJeremy L Thompson ierr = CeedVectorGetArrayRead(q_weight, CEED_MEM_HOST, &q_weight_array); 1959eaf62fffSJeremy L Thompson CeedChk(ierr); 1960eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_elem, &elem_avg); CeedChk(ierr); 1961eaf62fffSJeremy L Thompson const CeedScalar qf_value_bound = max_norm*100*CEED_EPSILON; 1962eaf62fffSJeremy L Thompson for (CeedInt e=0; e<num_elem; e++) { 1963eaf62fffSJeremy L Thompson CeedInt count = 0; 1964eaf62fffSJeremy L Thompson for (CeedInt q=0; q<num_qpts; q++) 1965eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_comp*num_comp*num_modes*num_modes; i++) 1966eaf62fffSJeremy L Thompson if (fabs(assembled_array[q*layout[0] + i*layout[1] + e*layout[2]]) > 1967eaf62fffSJeremy L Thompson qf_value_bound) { 1968eaf62fffSJeremy L Thompson elem_avg[e] += assembled_array[q*layout[0] + i*layout[1] + e*layout[2]] / 1969eaf62fffSJeremy L Thompson q_weight_array[q]; 1970eaf62fffSJeremy L Thompson count++; 1971eaf62fffSJeremy L Thompson } 1972eaf62fffSJeremy L Thompson if (count) { 1973eaf62fffSJeremy L Thompson elem_avg[e] /= count; 1974eaf62fffSJeremy L Thompson } else { 1975eaf62fffSJeremy L Thompson elem_avg[e] = 1.0; 1976eaf62fffSJeremy L Thompson } 1977eaf62fffSJeremy L Thompson } 1978eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArrayRead(assembled, &assembled_array); CeedChk(ierr); 1979eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&assembled); CeedChk(ierr); 1980eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArrayRead(q_weight, &q_weight_array); CeedChk(ierr); 1981eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&q_weight); CeedChk(ierr); 1982eaf62fffSJeremy L Thompson 1983eaf62fffSJeremy L Thompson // Build FDM diagonal 1984eaf62fffSJeremy L Thompson CeedVector q_data; 1985eaf62fffSJeremy L Thompson CeedScalar *q_data_array, *fdm_diagonal; 1986eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_comp*elem_size, &fdm_diagonal); CeedChk(ierr); 1987eaf62fffSJeremy L Thompson const CeedScalar fdm_diagonal_bound = elem_size*CEED_EPSILON; 1988eaf62fffSJeremy L Thompson for (CeedInt c=0; c<num_comp; c++) 1989eaf62fffSJeremy L Thompson for (CeedInt n=0; n<elem_size; n++) { 1990eaf62fffSJeremy L Thompson if (interp) 1991eaf62fffSJeremy L Thompson fdm_diagonal[c*elem_size + n] = 1.0; 1992eaf62fffSJeremy L Thompson if (grad) 1993eaf62fffSJeremy L Thompson for (CeedInt d=0; d<dim; d++) { 1994eaf62fffSJeremy L Thompson CeedInt i = (n / CeedIntPow(P_1d, d)) % P_1d; 1995eaf62fffSJeremy L Thompson fdm_diagonal[c*elem_size + n] += lambda[i]; 1996eaf62fffSJeremy L Thompson } 1997eaf62fffSJeremy L Thompson if (fabs(fdm_diagonal[c*elem_size + n]) < fdm_diagonal_bound) 1998eaf62fffSJeremy L Thompson fdm_diagonal[c*elem_size + n] = fdm_diagonal_bound; 1999eaf62fffSJeremy L Thompson } 2000eaf62fffSJeremy L Thompson ierr = CeedVectorCreate(ceed_parent, num_elem*num_comp*elem_size, &q_data); 2001eaf62fffSJeremy L Thompson CeedChk(ierr); 2002eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(q_data, 0.0); CeedChk(ierr); 2003eaf62fffSJeremy L Thompson ierr = CeedVectorGetArray(q_data, CEED_MEM_HOST, &q_data_array); CeedChk(ierr); 2004eaf62fffSJeremy L Thompson for (CeedInt e=0; e<num_elem; e++) 2005eaf62fffSJeremy L Thompson for (CeedInt c=0; c<num_comp; c++) 2006eaf62fffSJeremy L Thompson for (CeedInt n=0; n<elem_size; n++) 2007eaf62fffSJeremy L Thompson q_data_array[(e*num_comp+c)*elem_size+n] = 1. / (elem_avg[e] * 2008eaf62fffSJeremy L Thompson fdm_diagonal[c*elem_size + n]); 2009eaf62fffSJeremy L Thompson ierr = CeedFree(&elem_avg); CeedChk(ierr); 2010eaf62fffSJeremy L Thompson ierr = CeedFree(&fdm_diagonal); CeedChk(ierr); 2011eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArray(q_data, &q_data_array); CeedChk(ierr); 2012eaf62fffSJeremy L Thompson 2013eaf62fffSJeremy L Thompson // Setup FDM operator 2014eaf62fffSJeremy L Thompson // -- Basis 2015eaf62fffSJeremy L Thompson CeedBasis fdm_basis; 2016eaf62fffSJeremy L Thompson CeedScalar *grad_dummy, *q_ref_dummy, *q_weight_dummy; 2017eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &grad_dummy); CeedChk(ierr); 2018eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d, &q_ref_dummy); CeedChk(ierr); 2019eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d, &q_weight_dummy); CeedChk(ierr); 2020eaf62fffSJeremy L Thompson ierr = CeedBasisCreateTensorH1(ceed_parent, dim, num_comp, P_1d, P_1d, 2021eaf62fffSJeremy L Thompson fdm_interp, grad_dummy, q_ref_dummy, 2022eaf62fffSJeremy L Thompson q_weight_dummy, &fdm_basis); CeedChk(ierr); 2023eaf62fffSJeremy L Thompson ierr = CeedFree(&fdm_interp); CeedChk(ierr); 2024eaf62fffSJeremy L Thompson ierr = CeedFree(&grad_dummy); CeedChk(ierr); 2025eaf62fffSJeremy L Thompson ierr = CeedFree(&q_ref_dummy); CeedChk(ierr); 2026eaf62fffSJeremy L Thompson ierr = CeedFree(&q_weight_dummy); CeedChk(ierr); 2027eaf62fffSJeremy L Thompson ierr = CeedFree(&lambda); CeedChk(ierr); 2028eaf62fffSJeremy L Thompson 2029eaf62fffSJeremy L Thompson // -- Restriction 2030eaf62fffSJeremy L Thompson CeedElemRestriction rstr_qd_i; 2031eaf62fffSJeremy L Thompson CeedInt strides[3] = {1, elem_size, elem_size*num_comp}; 2032eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionCreateStrided(ceed_parent, num_elem, elem_size, 2033eaf62fffSJeremy L Thompson num_comp, num_elem*num_comp*elem_size, 2034eaf62fffSJeremy L Thompson strides, &rstr_qd_i); CeedChk(ierr); 2035eaf62fffSJeremy L Thompson // -- QFunction 2036eaf62fffSJeremy L Thompson CeedQFunction qf_fdm; 2037eaf62fffSJeremy L Thompson ierr = CeedQFunctionCreateInteriorByName(ceed_parent, "Scale", &qf_fdm); 2038eaf62fffSJeremy L Thompson CeedChk(ierr); 2039eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_fdm, "input", num_comp, CEED_EVAL_INTERP); 2040eaf62fffSJeremy L Thompson CeedChk(ierr); 2041eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_fdm, "scale", num_comp, CEED_EVAL_NONE); 2042eaf62fffSJeremy L Thompson CeedChk(ierr); 2043eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddOutput(qf_fdm, "output", num_comp, CEED_EVAL_INTERP); 2044eaf62fffSJeremy L Thompson CeedChk(ierr); 2045eaf62fffSJeremy L Thompson // -- QFunction context 2046eaf62fffSJeremy L Thompson CeedInt *num_comp_data; 2047eaf62fffSJeremy L Thompson ierr = CeedCalloc(1, &num_comp_data); CeedChk(ierr); 2048eaf62fffSJeremy L Thompson num_comp_data[0] = num_comp; 2049eaf62fffSJeremy L Thompson CeedQFunctionContext ctx_fdm; 2050eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextCreate(ceed, &ctx_fdm); CeedChk(ierr); 2051eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextSetData(ctx_fdm, CEED_MEM_HOST, CEED_OWN_POINTER, 2052eaf62fffSJeremy L Thompson sizeof(*num_comp_data), num_comp_data); 2053eaf62fffSJeremy L Thompson CeedChk(ierr); 2054eaf62fffSJeremy L Thompson ierr = CeedQFunctionSetContext(qf_fdm, ctx_fdm); CeedChk(ierr); 2055eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextDestroy(&ctx_fdm); CeedChk(ierr); 2056eaf62fffSJeremy L Thompson // -- Operator 2057eaf62fffSJeremy L Thompson ierr = CeedOperatorCreate(ceed_parent, qf_fdm, NULL, NULL, fdm_inv); 2058eaf62fffSJeremy L Thompson CeedChk(ierr); 2059eaf62fffSJeremy L Thompson CeedOperatorSetField(*fdm_inv, "input", rstr, fdm_basis, CEED_VECTOR_ACTIVE); 2060eaf62fffSJeremy L Thompson CeedChk(ierr); 2061eaf62fffSJeremy L Thompson CeedOperatorSetField(*fdm_inv, "scale", rstr_qd_i, CEED_BASIS_COLLOCATED, 2062eaf62fffSJeremy L Thompson q_data); CeedChk(ierr); 2063eaf62fffSJeremy L Thompson CeedOperatorSetField(*fdm_inv, "output", rstr, fdm_basis, CEED_VECTOR_ACTIVE); 2064eaf62fffSJeremy L Thompson CeedChk(ierr); 2065eaf62fffSJeremy L Thompson 2066eaf62fffSJeremy L Thompson // Cleanup 2067eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&q_data); CeedChk(ierr); 2068eaf62fffSJeremy L Thompson ierr = CeedBasisDestroy(&fdm_basis); CeedChk(ierr); 2069eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr_qd_i); CeedChk(ierr); 2070eaf62fffSJeremy L Thompson ierr = CeedQFunctionDestroy(&qf_fdm); CeedChk(ierr); 2071eaf62fffSJeremy L Thompson 2072eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2073eaf62fffSJeremy L Thompson } 2074eaf62fffSJeremy L Thompson 2075eaf62fffSJeremy L Thompson /// @} 2076