13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3eaf62fffSJeremy L Thompson // 43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause 5eaf62fffSJeremy L Thompson // 63d8e8822SJeremy L Thompson // This file is part of CEED: http://github.com/ceed 7eaf62fffSJeremy L Thompson 82b730f8bSJeremy L Thompson #include <ceed-impl.h> 949aac155SJeremy L Thompson #include <ceed.h> 102b730f8bSJeremy L Thompson #include <ceed/backend.h> 11c85e8640SSebastian Grimberg #include <assert.h> 122b730f8bSJeremy L Thompson #include <math.h> 13eaf62fffSJeremy L Thompson #include <stdbool.h> 14eaf62fffSJeremy L Thompson #include <stdio.h> 15eaf62fffSJeremy L Thompson #include <string.h> 16eaf62fffSJeremy L Thompson 17eaf62fffSJeremy L Thompson /// @file 18eaf62fffSJeremy L Thompson /// Implementation of CeedOperator preconditioning interfaces 19eaf62fffSJeremy L Thompson 20eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 21eaf62fffSJeremy L Thompson /// CeedOperator Library Internal Preconditioning Functions 22eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 23eaf62fffSJeremy L Thompson /// @addtogroup CeedOperatorDeveloper 24eaf62fffSJeremy L Thompson /// @{ 25eaf62fffSJeremy L Thompson 26eaf62fffSJeremy L Thompson /** 27ea61e9acSJeremy L Thompson @brief Duplicate a CeedQFunction with a reference Ceed to fallback for advanced CeedOperator functionality 289e77b9c8SJeremy L Thompson 2901ea9c81SJed Brown @param[in] fallback_ceed Ceed on which to create fallback CeedQFunction 309e77b9c8SJeremy L Thompson @param[in] qf CeedQFunction to create fallback for 3101ea9c81SJed Brown @param[out] qf_fallback fallback CeedQFunction 329e77b9c8SJeremy L Thompson 339e77b9c8SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 349e77b9c8SJeremy L Thompson 359e77b9c8SJeremy L Thompson @ref Developer 369e77b9c8SJeremy L Thompson **/ 372b730f8bSJeremy L Thompson static int CeedQFunctionCreateFallback(Ceed fallback_ceed, CeedQFunction qf, CeedQFunction *qf_fallback) { 389e77b9c8SJeremy L Thompson // Check if NULL qf passed in 399e77b9c8SJeremy L Thompson if (!qf) return CEED_ERROR_SUCCESS; 409e77b9c8SJeremy L Thompson 41d04bbc78SJeremy L Thompson CeedDebug256(qf->ceed, 1, "---------- CeedOperator Fallback ----------\n"); 4213f886e9SJeremy L Thompson CeedDebug(qf->ceed, "Creating fallback CeedQFunction\n"); 43d04bbc78SJeremy L Thompson 449e77b9c8SJeremy L Thompson char *source_path_with_name = ""; 459e77b9c8SJeremy L Thompson if (qf->source_path) { 462b730f8bSJeremy L Thompson size_t path_len = strlen(qf->source_path), name_len = strlen(qf->kernel_name); 472b730f8bSJeremy L Thompson CeedCall(CeedCalloc(path_len + name_len + 2, &source_path_with_name)); 489e77b9c8SJeremy L Thompson memcpy(source_path_with_name, qf->source_path, path_len); 499e77b9c8SJeremy L Thompson memcpy(&source_path_with_name[path_len], ":", 1); 509e77b9c8SJeremy L Thompson memcpy(&source_path_with_name[path_len + 1], qf->kernel_name, name_len); 519e77b9c8SJeremy L Thompson } else { 522b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, &source_path_with_name)); 539e77b9c8SJeremy L Thompson } 549e77b9c8SJeremy L Thompson 552b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateInterior(fallback_ceed, qf->vec_length, qf->function, source_path_with_name, qf_fallback)); 569e77b9c8SJeremy L Thompson { 579e77b9c8SJeremy L Thompson CeedQFunctionContext ctx; 589e77b9c8SJeremy L Thompson 592b730f8bSJeremy L Thompson CeedCall(CeedQFunctionGetContext(qf, &ctx)); 602b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetContext(*qf_fallback, ctx)); 619e77b9c8SJeremy L Thompson } 629e77b9c8SJeremy L Thompson for (CeedInt i = 0; i < qf->num_input_fields; i++) { 632b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(*qf_fallback, qf->input_fields[i]->field_name, qf->input_fields[i]->size, qf->input_fields[i]->eval_mode)); 649e77b9c8SJeremy L Thompson } 659e77b9c8SJeremy L Thompson for (CeedInt i = 0; i < qf->num_output_fields; i++) { 662b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddOutput(*qf_fallback, qf->output_fields[i]->field_name, qf->output_fields[i]->size, qf->output_fields[i]->eval_mode)); 679e77b9c8SJeremy L Thompson } 682b730f8bSJeremy L Thompson CeedCall(CeedFree(&source_path_with_name)); 699e77b9c8SJeremy L Thompson 709e77b9c8SJeremy L Thompson return CEED_ERROR_SUCCESS; 719e77b9c8SJeremy L Thompson } 729e77b9c8SJeremy L Thompson 739e77b9c8SJeremy L Thompson /** 74ea61e9acSJeremy L Thompson @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced CeedOperator functionality 75eaf62fffSJeremy L Thompson 76ea61e9acSJeremy L Thompson @param[in,out] op CeedOperator to create fallback for 77eaf62fffSJeremy L Thompson 78eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 79eaf62fffSJeremy L Thompson 80eaf62fffSJeremy L Thompson @ref Developer 81eaf62fffSJeremy L Thompson **/ 82d04bbc78SJeremy L Thompson static int CeedOperatorCreateFallback(CeedOperator op) { 83b275c451SJeremy L Thompson bool is_composite; 849e77b9c8SJeremy L Thompson Ceed ceed_fallback; 85eaf62fffSJeremy L Thompson 86805fe78eSJeremy L Thompson // Check not already created 87805fe78eSJeremy L Thompson if (op->op_fallback) return CEED_ERROR_SUCCESS; 88805fe78eSJeremy L Thompson 89eaf62fffSJeremy L Thompson // Fallback Ceed 902b730f8bSJeremy L Thompson CeedCall(CeedGetOperatorFallbackCeed(op->ceed, &ceed_fallback)); 91d04bbc78SJeremy L Thompson if (!ceed_fallback) return CEED_ERROR_SUCCESS; 92d04bbc78SJeremy L Thompson 93d04bbc78SJeremy L Thompson CeedDebug256(op->ceed, 1, "---------- CeedOperator Fallback ----------\n"); 9413f886e9SJeremy L Thompson CeedDebug(op->ceed, "Creating fallback CeedOperator\n"); 95eaf62fffSJeremy L Thompson 96eaf62fffSJeremy L Thompson // Clone Op 97805fe78eSJeremy L Thompson CeedOperator op_fallback; 98b275c451SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 99b275c451SJeremy L Thompson if (is_composite) { 100b275c451SJeremy L Thompson CeedInt num_suboperators; 101b275c451SJeremy L Thompson CeedOperator *sub_operators; 102b275c451SJeremy L Thompson 1032b730f8bSJeremy L Thompson CeedCall(CeedCompositeOperatorCreate(ceed_fallback, &op_fallback)); 104b275c451SJeremy L Thompson CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 105b275c451SJeremy L Thompson CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 106b275c451SJeremy L Thompson for (CeedInt i = 0; i < num_suboperators; i++) { 107d04bbc78SJeremy L Thompson CeedOperator op_sub_fallback; 108d04bbc78SJeremy L Thompson 109b275c451SJeremy L Thompson CeedCall(CeedOperatorGetFallback(sub_operators[i], &op_sub_fallback)); 1102b730f8bSJeremy L Thompson CeedCall(CeedCompositeOperatorAddSub(op_fallback, op_sub_fallback)); 111805fe78eSJeremy L Thompson } 112805fe78eSJeremy L Thompson } else { 1139e77b9c8SJeremy L Thompson CeedQFunction qf_fallback = NULL, dqf_fallback = NULL, dqfT_fallback = NULL; 1142b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateFallback(ceed_fallback, op->qf, &qf_fallback)); 1152b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateFallback(ceed_fallback, op->dqf, &dqf_fallback)); 1162b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateFallback(ceed_fallback, op->dqfT, &dqfT_fallback)); 1172b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(ceed_fallback, qf_fallback, dqf_fallback, dqfT_fallback, &op_fallback)); 118805fe78eSJeremy L Thompson for (CeedInt i = 0; i < op->qf->num_input_fields; i++) { 119437c7c90SJeremy L Thompson CeedCall(CeedOperatorSetField(op_fallback, op->input_fields[i]->field_name, op->input_fields[i]->elem_rstr, op->input_fields[i]->basis, 1202b730f8bSJeremy L Thompson op->input_fields[i]->vec)); 121805fe78eSJeremy L Thompson } 122805fe78eSJeremy L Thompson for (CeedInt i = 0; i < op->qf->num_output_fields; i++) { 123437c7c90SJeremy L Thompson CeedCall(CeedOperatorSetField(op_fallback, op->output_fields[i]->field_name, op->output_fields[i]->elem_rstr, op->output_fields[i]->basis, 1242b730f8bSJeremy L Thompson op->output_fields[i]->vec)); 125805fe78eSJeremy L Thompson } 1262b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataReferenceCopy(op->qf_assembled, &op_fallback->qf_assembled)); 127805fe78eSJeremy L Thompson if (op_fallback->num_qpts == 0) { 1282b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetNumQuadraturePoints(op_fallback, op->num_qpts)); 129805fe78eSJeremy L Thompson } 1309e77b9c8SJeremy L Thompson // Cleanup 1312b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&qf_fallback)); 1322b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&dqf_fallback)); 1332b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&dqfT_fallback)); 134805fe78eSJeremy L Thompson } 1352b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetName(op_fallback, op->name)); 1362b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op_fallback)); 137805fe78eSJeremy L Thompson op->op_fallback = op_fallback; 138eaf62fffSJeremy L Thompson 139eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 140eaf62fffSJeremy L Thompson } 141eaf62fffSJeremy L Thompson 142eaf62fffSJeremy L Thompson /** 143ea61e9acSJeremy L Thompson @brief Retrieve fallback CeedOperator with a reference Ceed for advanced CeedOperator functionality 144d04bbc78SJeremy L Thompson 145d04bbc78SJeremy L Thompson @param[in] op CeedOperator to retrieve fallback for 146d04bbc78SJeremy L Thompson @param[out] op_fallback Fallback CeedOperator 147d04bbc78SJeremy L Thompson 148d04bbc78SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 149d04bbc78SJeremy L Thompson 150d04bbc78SJeremy L Thompson @ref Developer 151d04bbc78SJeremy L Thompson **/ 152d04bbc78SJeremy L Thompson int CeedOperatorGetFallback(CeedOperator op, CeedOperator *op_fallback) { 153d04bbc78SJeremy L Thompson // Create if needed 154d04bbc78SJeremy L Thompson if (!op->op_fallback) { 1552b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreateFallback(op)); 156d04bbc78SJeremy L Thompson } 157d04bbc78SJeremy L Thompson if (op->op_fallback) { 158d04bbc78SJeremy L Thompson bool is_debug; 159d04bbc78SJeremy L Thompson 1602b730f8bSJeremy L Thompson CeedCall(CeedIsDebug(op->ceed, &is_debug)); 161d04bbc78SJeremy L Thompson if (is_debug) { 162b275c451SJeremy L Thompson Ceed ceed, ceed_fallback; 163d04bbc78SJeremy L Thompson const char *resource, *resource_fallback; 164d04bbc78SJeremy L Thompson 165b275c451SJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 166b275c451SJeremy L Thompson CeedCall(CeedGetOperatorFallbackCeed(ceed, &ceed_fallback)); 167b275c451SJeremy L Thompson CeedCall(CeedGetResource(ceed, &resource)); 1682b730f8bSJeremy L Thompson CeedCall(CeedGetResource(ceed_fallback, &resource_fallback)); 169d04bbc78SJeremy L Thompson 170b275c451SJeremy L Thompson CeedDebug256(ceed, 1, "---------- CeedOperator Fallback ----------\n"); 171b275c451SJeremy L Thompson CeedDebug(ceed, "Falling back from %s operator at address %ld to %s operator at address %ld\n", resource, op, resource_fallback, 1722b730f8bSJeremy L Thompson op->op_fallback); 173d04bbc78SJeremy L Thompson } 174d04bbc78SJeremy L Thompson } 175d04bbc78SJeremy L Thompson *op_fallback = op->op_fallback; 176d04bbc78SJeremy L Thompson 177d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 178d04bbc78SJeremy L Thompson } 179d04bbc78SJeremy L Thompson 180d04bbc78SJeremy L Thompson /** 181eaf62fffSJeremy L Thompson @brief Select correct basis matrix pointer based on CeedEvalMode 182eaf62fffSJeremy L Thompson 183352a5e7cSSebastian Grimberg @param[in] basis CeedBasis from which to get the basis matrix 184eaf62fffSJeremy L Thompson @param[in] eval_mode Current basis evaluation mode 185eaf62fffSJeremy L Thompson @param[in] identity Pointer to identity matrix 186eaf62fffSJeremy L Thompson @param[out] basis_ptr Basis pointer to set 187eaf62fffSJeremy L Thompson 188eaf62fffSJeremy L Thompson @ref Developer 189eaf62fffSJeremy L Thompson **/ 190352a5e7cSSebastian Grimberg static inline int CeedOperatorGetBasisPointer(CeedBasis basis, CeedEvalMode eval_mode, const CeedScalar *identity, const CeedScalar **basis_ptr) { 191eaf62fffSJeremy L Thompson switch (eval_mode) { 192eaf62fffSJeremy L Thompson case CEED_EVAL_NONE: 193eaf62fffSJeremy L Thompson *basis_ptr = identity; 194eaf62fffSJeremy L Thompson break; 195eaf62fffSJeremy L Thompson case CEED_EVAL_INTERP: 196352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetInterp(basis, basis_ptr)); 197eaf62fffSJeremy L Thompson break; 198eaf62fffSJeremy L Thompson case CEED_EVAL_GRAD: 199352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetGrad(basis, basis_ptr)); 200352a5e7cSSebastian Grimberg break; 201352a5e7cSSebastian Grimberg case CEED_EVAL_DIV: 202352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetDiv(basis, basis_ptr)); 203352a5e7cSSebastian Grimberg break; 204352a5e7cSSebastian Grimberg case CEED_EVAL_CURL: 205352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetCurl(basis, basis_ptr)); 206eaf62fffSJeremy L Thompson break; 207eaf62fffSJeremy L Thompson case CEED_EVAL_WEIGHT: 208eaf62fffSJeremy L Thompson break; // Caught by QF Assembly 209eaf62fffSJeremy L Thompson } 210ed9e99e6SJeremy L Thompson assert(*basis_ptr != NULL); 211352a5e7cSSebastian Grimberg 212352a5e7cSSebastian Grimberg return CEED_ERROR_SUCCESS; 213eaf62fffSJeremy L Thompson } 214eaf62fffSJeremy L Thompson 215eaf62fffSJeremy L Thompson /** 216eaf62fffSJeremy L Thompson @brief Create point block restriction for active operator field 217eaf62fffSJeremy L Thompson 218eaf62fffSJeremy L Thompson @param[in] rstr Original CeedElemRestriction for active field 219ea61e9acSJeremy L Thompson @param[out] pointblock_rstr Address of the variable where the newly created CeedElemRestriction will be stored 220eaf62fffSJeremy L Thompson 221eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 222eaf62fffSJeremy L Thompson 223eaf62fffSJeremy L Thompson @ref Developer 224eaf62fffSJeremy L Thompson **/ 2252b730f8bSJeremy L Thompson static int CeedOperatorCreateActivePointBlockRestriction(CeedElemRestriction rstr, CeedElemRestriction *pointblock_rstr) { 226eaf62fffSJeremy L Thompson Ceed ceed; 2272b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 228eaf62fffSJeremy L Thompson const CeedInt *offsets; 2292b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets)); 230eaf62fffSJeremy L Thompson 231eaf62fffSJeremy L Thompson // Expand offsets 2327b63f5c6SJed Brown CeedInt num_elem, num_comp, elem_size, comp_stride, *pointblock_offsets; 2337b63f5c6SJed Brown CeedSize l_size; 2342b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 2352b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 2362b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 2372b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetCompStride(rstr, &comp_stride)); 2382b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size)); 239eaf62fffSJeremy L Thompson CeedInt shift = num_comp; 2402b730f8bSJeremy L Thompson if (comp_stride != 1) shift *= num_comp; 2412b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_elem * elem_size, &pointblock_offsets)); 242eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_elem * elem_size; i++) { 243eaf62fffSJeremy L Thompson pointblock_offsets[i] = offsets[i] * shift; 244eaf62fffSJeremy L Thompson } 245eaf62fffSJeremy L Thompson 246eaf62fffSJeremy L Thompson // Create new restriction 2472b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionCreate(ceed, num_elem, elem_size, num_comp * num_comp, 1, l_size * num_comp, CEED_MEM_HOST, CEED_OWN_POINTER, 2482b730f8bSJeremy L Thompson pointblock_offsets, pointblock_rstr)); 249eaf62fffSJeremy L Thompson 250eaf62fffSJeremy L Thompson // Cleanup 2512b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionRestoreOffsets(rstr, &offsets)); 252eaf62fffSJeremy L Thompson 253eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 254eaf62fffSJeremy L Thompson } 255eaf62fffSJeremy L Thompson 256eaf62fffSJeremy L Thompson /** 257eaf62fffSJeremy L Thompson @brief Core logic for assembling operator diagonal or point block diagonal 258eaf62fffSJeremy L Thompson 259eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble point block diagonal 260ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else CEED_REQUEST_IMMEDIATE 261eaf62fffSJeremy L Thompson @param[in] is_pointblock Boolean flag to assemble diagonal or point block diagonal 262eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled diagonal 263eaf62fffSJeremy L Thompson 264eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 265eaf62fffSJeremy L Thompson 266eaf62fffSJeremy L Thompson @ref Developer 267eaf62fffSJeremy L Thompson **/ 2682b730f8bSJeremy L Thompson static inline int CeedSingleOperatorAssembleAddDiagonal_Core(CeedOperator op, CeedRequest *request, const bool is_pointblock, CeedVector assembled) { 269eaf62fffSJeremy L Thompson Ceed ceed; 2702b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 271eaf62fffSJeremy L Thompson 272eaf62fffSJeremy L Thompson // Assemble QFunction 273eaf62fffSJeremy L Thompson CeedQFunction qf; 274437c7c90SJeremy L Thompson const CeedScalar *assembled_qf_array; 275eaf62fffSJeremy L Thompson CeedVector assembled_qf; 276437c7c90SJeremy L Thompson CeedElemRestriction assembled_elem_rstr; 277437c7c90SJeremy L Thompson CeedInt num_input_fields, num_output_fields; 278eaf62fffSJeremy L Thompson CeedInt layout[3]; 279437c7c90SJeremy L Thompson 280437c7c90SJeremy L Thompson CeedCall(CeedOperatorGetQFunction(op, &qf)); 281437c7c90SJeremy L Thompson CeedCall(CeedQFunctionGetNumArgs(qf, &num_input_fields, &num_output_fields)); 282437c7c90SJeremy L Thompson CeedCall(CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled_qf, &assembled_elem_rstr, request)); 283437c7c90SJeremy L Thompson CeedCall(CeedElemRestrictionGetELayout(assembled_elem_rstr, &layout)); 284437c7c90SJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&assembled_elem_rstr)); 285437c7c90SJeremy L Thompson CeedCall(CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array)); 286eaf62fffSJeremy L Thompson 287ed9e99e6SJeremy L Thompson // Get assembly data 288ed9e99e6SJeremy L Thompson CeedOperatorAssemblyData data; 289437c7c90SJeremy L Thompson const CeedEvalMode **eval_modes_in, **eval_modes_out; 290437c7c90SJeremy L Thompson CeedInt *num_eval_modes_in, *num_eval_modes_out, num_active_bases; 291437c7c90SJeremy L Thompson CeedSize **eval_mode_offsets_in, **eval_mode_offsets_out, num_output_components; 292437c7c90SJeremy L Thompson CeedBasis *active_bases; 293437c7c90SJeremy L Thompson CeedElemRestriction *active_elem_rstrs; 294437c7c90SJeremy L Thompson CeedCall(CeedOperatorGetOperatorAssemblyData(op, &data)); 295437c7c90SJeremy L Thompson CeedCall(CeedOperatorAssemblyDataGetEvalModes(data, &num_active_bases, &num_eval_modes_in, &eval_modes_in, &eval_mode_offsets_in, 296437c7c90SJeremy L Thompson &num_eval_modes_out, &eval_modes_out, &eval_mode_offsets_out, &num_output_components)); 297437c7c90SJeremy L Thompson CeedCall(CeedOperatorAssemblyDataGetBases(data, NULL, &active_bases, NULL, NULL)); 298437c7c90SJeremy L Thompson CeedCall(CeedOperatorAssemblyDataGetElemRestrictions(data, NULL, &active_elem_rstrs)); 299437c7c90SJeremy L Thompson 300437c7c90SJeremy L Thompson // Loop over all active bases 301437c7c90SJeremy L Thompson for (CeedInt b = 0; b < num_active_bases; b++) { 302eaf62fffSJeremy L Thompson // Assemble point block diagonal restriction, if needed 303437c7c90SJeremy L Thompson CeedElemRestriction diag_elem_rstr = active_elem_rstrs[b]; 304437c7c90SJeremy L Thompson 305eaf62fffSJeremy L Thompson if (is_pointblock) { 306437c7c90SJeremy L Thompson CeedElemRestriction point_block_elem_rstr; 307437c7c90SJeremy L Thompson 308437c7c90SJeremy L Thompson CeedCall(CeedOperatorCreateActivePointBlockRestriction(diag_elem_rstr, &point_block_elem_rstr)); 309437c7c90SJeremy L Thompson diag_elem_rstr = point_block_elem_rstr; 310eaf62fffSJeremy L Thompson } 311eaf62fffSJeremy L Thompson 312eaf62fffSJeremy L Thompson // Create diagonal vector 313eaf62fffSJeremy L Thompson CeedVector elem_diag; 314437c7c90SJeremy L Thompson CeedCall(CeedElemRestrictionCreateVector(diag_elem_rstr, NULL, &elem_diag)); 315eaf62fffSJeremy L Thompson 316eaf62fffSJeremy L Thompson // Assemble element operator diagonals 3179c774eddSJeremy L Thompson CeedScalar *elem_diag_array; 318437c7c90SJeremy L Thompson CeedInt num_elem, num_nodes, num_qpts, num_components; 319437c7c90SJeremy L Thompson 3202b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(elem_diag, 0.0)); 3212b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArray(elem_diag, CEED_MEM_HOST, &elem_diag_array)); 322437c7c90SJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(diag_elem_rstr, &num_elem)); 323437c7c90SJeremy L Thompson CeedCall(CeedBasisGetNumNodes(active_bases[b], &num_nodes)); 324437c7c90SJeremy L Thompson CeedCall(CeedBasisGetNumComponents(active_bases[b], &num_components)); 325437c7c90SJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(active_bases[b], &num_qpts)); 326ed9e99e6SJeremy L Thompson 327352a5e7cSSebastian Grimberg // Construct identity matrix for basis if required 328ed9e99e6SJeremy L Thompson bool has_eval_none = false; 329352a5e7cSSebastian Grimberg CeedScalar *identity = NULL; 330437c7c90SJeremy L Thompson for (CeedInt i = 0; i < num_eval_modes_in[b]; i++) { 331437c7c90SJeremy L Thompson has_eval_none = has_eval_none || (eval_modes_in[b][i] == CEED_EVAL_NONE); 332ed9e99e6SJeremy L Thompson } 333437c7c90SJeremy L Thompson for (CeedInt i = 0; i < num_eval_modes_out[b]; i++) { 334437c7c90SJeremy L Thompson has_eval_none = has_eval_none || (eval_modes_out[b][i] == CEED_EVAL_NONE); 335ed9e99e6SJeremy L Thompson } 336ed9e99e6SJeremy L Thompson if (has_eval_none) { 3372b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_qpts * num_nodes, &identity)); 3382b730f8bSJeremy L Thompson for (CeedInt i = 0; i < (num_nodes < num_qpts ? num_nodes : num_qpts); i++) identity[i * num_nodes + i] = 1.0; 339eaf62fffSJeremy L Thompson } 340352a5e7cSSebastian Grimberg 341eaf62fffSJeremy L Thompson // Compute the diagonal of B^T D B 342eaf62fffSJeremy L Thompson // Each element 343eaf62fffSJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) { 344eaf62fffSJeremy L Thompson // Each basis eval mode pair 345352a5e7cSSebastian Grimberg CeedInt d_out = 0, q_comp_out; 346352a5e7cSSebastian Grimberg CeedEvalMode eval_mode_out_prev = CEED_EVAL_NONE; 347437c7c90SJeremy L Thompson for (CeedInt e_out = 0; e_out < num_eval_modes_out[b]; e_out++) { 348437c7c90SJeremy L Thompson const CeedScalar *B_t = NULL; 349352a5e7cSSebastian Grimberg CeedOperatorGetBasisPointer(active_bases[b], eval_modes_out[b][e_out], identity, &B_t); 350352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumQuadratureComponents(active_bases[b], eval_modes_out[b][e_out], &q_comp_out)); 351352a5e7cSSebastian Grimberg if (q_comp_out > 1) { 352352a5e7cSSebastian Grimberg if (e_out == 0 || eval_modes_out[b][e_out] != eval_mode_out_prev) d_out = 0; 353352a5e7cSSebastian Grimberg else B_t = &B_t[(++d_out) * num_qpts * num_nodes]; 354352a5e7cSSebastian Grimberg } 355352a5e7cSSebastian Grimberg eval_mode_out_prev = eval_modes_out[b][e_out]; 356352a5e7cSSebastian Grimberg 357352a5e7cSSebastian Grimberg CeedInt d_in = 0, q_comp_in; 358352a5e7cSSebastian Grimberg CeedEvalMode eval_mode_in_prev = CEED_EVAL_NONE; 359437c7c90SJeremy L Thompson for (CeedInt e_in = 0; e_in < num_eval_modes_in[b]; e_in++) { 360437c7c90SJeremy L Thompson const CeedScalar *B = NULL; 361352a5e7cSSebastian Grimberg CeedOperatorGetBasisPointer(active_bases[b], eval_modes_in[b][e_in], identity, &B); 362352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumQuadratureComponents(active_bases[b], eval_modes_in[b][e_in], &q_comp_in)); 363352a5e7cSSebastian Grimberg if (q_comp_in > 1) { 364352a5e7cSSebastian Grimberg if (e_in == 0 || eval_modes_in[b][e_in] != eval_mode_in_prev) d_in = 0; 365352a5e7cSSebastian Grimberg else B = &B[(++d_in) * num_qpts * num_nodes]; 366352a5e7cSSebastian Grimberg } 367352a5e7cSSebastian Grimberg eval_mode_in_prev = eval_modes_in[b][e_in]; 368352a5e7cSSebastian Grimberg 369eaf62fffSJeremy L Thompson // Each component 370437c7c90SJeremy L Thompson for (CeedInt c_out = 0; c_out < num_components; c_out++) { 371437c7c90SJeremy L Thompson // Each qpt/node pair 3722b730f8bSJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 373eaf62fffSJeremy L Thompson if (is_pointblock) { 374eaf62fffSJeremy L Thompson // Point Block Diagonal 375437c7c90SJeremy L Thompson for (CeedInt c_in = 0; c_in < num_components; c_in++) { 376437c7c90SJeremy L Thompson const CeedInt c_offset = (eval_mode_offsets_in[b][e_in] + c_in) * num_output_components + eval_mode_offsets_out[b][e_out] + c_out; 377437c7c90SJeremy L Thompson const CeedScalar qf_value = assembled_qf_array[q * layout[0] + c_offset * layout[1] + e * layout[2]]; 3782b730f8bSJeremy L Thompson for (CeedInt n = 0; n < num_nodes; n++) { 379437c7c90SJeremy L Thompson elem_diag_array[((e * num_components + c_out) * num_components + c_in) * num_nodes + n] += 380437c7c90SJeremy L Thompson B_t[q * num_nodes + n] * qf_value * B[q * num_nodes + n]; 381eaf62fffSJeremy L Thompson } 3822b730f8bSJeremy L Thompson } 383eaf62fffSJeremy L Thompson } else { 384eaf62fffSJeremy L Thompson // Diagonal Only 385437c7c90SJeremy L Thompson const CeedInt c_offset = (eval_mode_offsets_in[b][e_in] + c_out) * num_output_components + eval_mode_offsets_out[b][e_out] + c_out; 386437c7c90SJeremy L Thompson const CeedScalar qf_value = assembled_qf_array[q * layout[0] + c_offset * layout[1] + e * layout[2]]; 3872b730f8bSJeremy L Thompson for (CeedInt n = 0; n < num_nodes; n++) { 388437c7c90SJeremy L Thompson elem_diag_array[(e * num_components + c_out) * num_nodes + n] += B_t[q * num_nodes + n] * qf_value * B[q * num_nodes + n]; 389eaf62fffSJeremy L Thompson } 390eaf62fffSJeremy L Thompson } 391eaf62fffSJeremy L Thompson } 392eaf62fffSJeremy L Thompson } 3932b730f8bSJeremy L Thompson } 3942b730f8bSJeremy L Thompson } 3952b730f8bSJeremy L Thompson } 3962b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArray(elem_diag, &elem_diag_array)); 397eaf62fffSJeremy L Thompson 398eaf62fffSJeremy L Thompson // Assemble local operator diagonal 399437c7c90SJeremy L Thompson CeedCall(CeedElemRestrictionApply(diag_elem_rstr, CEED_TRANSPOSE, elem_diag, assembled, request)); 400eaf62fffSJeremy L Thompson 401eaf62fffSJeremy L Thompson // Cleanup 402437c7c90SJeremy L Thompson if (is_pointblock) CeedCall(CeedElemRestrictionDestroy(&diag_elem_rstr)); 4032b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&elem_diag)); 4042b730f8bSJeremy L Thompson CeedCall(CeedFree(&identity)); 405437c7c90SJeremy L Thompson } 406437c7c90SJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array)); 407437c7c90SJeremy L Thompson CeedCall(CeedVectorDestroy(&assembled_qf)); 408eaf62fffSJeremy L Thompson 409eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 410eaf62fffSJeremy L Thompson } 411eaf62fffSJeremy L Thompson 412eaf62fffSJeremy L Thompson /** 413eaf62fffSJeremy L Thompson @brief Core logic for assembling composite operator diagonal 414eaf62fffSJeremy L Thompson 415eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble point block diagonal 416ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else CEED_REQUEST_IMMEDIATE 417eaf62fffSJeremy L Thompson @param[in] is_pointblock Boolean flag to assemble diagonal or point block diagonal 418eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled diagonal 419eaf62fffSJeremy L Thompson 420eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 421eaf62fffSJeremy L Thompson 422eaf62fffSJeremy L Thompson @ref Developer 423eaf62fffSJeremy L Thompson **/ 4242b730f8bSJeremy L Thompson static inline int CeedCompositeOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedRequest *request, const bool is_pointblock, 425eaf62fffSJeremy L Thompson CeedVector assembled) { 426eaf62fffSJeremy L Thompson CeedInt num_sub; 427eaf62fffSJeremy L Thompson CeedOperator *suboperators; 428c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub)); 429c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetSubList(op, &suboperators)); 430eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_sub; i++) { 4316aa95790SJeremy L Thompson if (is_pointblock) { 4322b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddPointBlockDiagonal(suboperators[i], assembled, request)); 4336aa95790SJeremy L Thompson } else { 4342b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddDiagonal(suboperators[i], assembled, request)); 4356aa95790SJeremy L Thompson } 436eaf62fffSJeremy L Thompson } 437eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 438eaf62fffSJeremy L Thompson } 439eaf62fffSJeremy L Thompson 440eaf62fffSJeremy L Thompson /** 441eaf62fffSJeremy L Thompson @brief Build nonzero pattern for non-composite operator 442eaf62fffSJeremy L Thompson 443eaf62fffSJeremy L Thompson Users should generally use CeedOperatorLinearAssembleSymbolic() 444eaf62fffSJeremy L Thompson 445eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble nonzero pattern 446eaf62fffSJeremy L Thompson @param[in] offset Offset for number of entries 447eaf62fffSJeremy L Thompson @param[out] rows Row number for each entry 448eaf62fffSJeremy L Thompson @param[out] cols Column number for each entry 449eaf62fffSJeremy L Thompson 450eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 451eaf62fffSJeremy L Thompson 452eaf62fffSJeremy L Thompson @ref Developer 453eaf62fffSJeremy L Thompson **/ 4542b730f8bSJeremy L Thompson static int CeedSingleOperatorAssembleSymbolic(CeedOperator op, CeedInt offset, CeedInt *rows, CeedInt *cols) { 455f3d47e36SJeremy L Thompson Ceed ceed; 456f3d47e36SJeremy L Thompson bool is_composite; 457f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 458f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 459f3d47e36SJeremy L Thompson 460b275c451SJeremy L Thompson if (is_composite) { 461eaf62fffSJeremy L Thompson // LCOV_EXCL_START 4622b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Composite operator not supported"); 463eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 4642b730f8bSJeremy L Thompson } 465eaf62fffSJeremy L Thompson 466c9366a6bSJeremy L Thompson CeedSize num_nodes; 4672b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &num_nodes, NULL)); 468eaf62fffSJeremy L Thompson CeedElemRestriction rstr_in; 4692b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveElemRestriction(op, &rstr_in)); 470e79b91d9SJeremy L Thompson CeedInt num_elem, elem_size, num_comp; 4712b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(rstr_in, &num_elem)); 4722b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetElementSize(rstr_in, &elem_size)); 4732b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumComponents(rstr_in, &num_comp)); 474eaf62fffSJeremy L Thompson CeedInt layout_er[3]; 4752b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetELayout(rstr_in, &layout_er)); 476eaf62fffSJeremy L Thompson 477eaf62fffSJeremy L Thompson CeedInt local_num_entries = elem_size * num_comp * elem_size * num_comp * num_elem; 478eaf62fffSJeremy L Thompson 479eaf62fffSJeremy L Thompson // Determine elem_dof relation 480eaf62fffSJeremy L Thompson CeedVector index_vec; 4812b730f8bSJeremy L Thompson CeedCall(CeedVectorCreate(ceed, num_nodes, &index_vec)); 482eaf62fffSJeremy L Thompson CeedScalar *array; 4832b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayWrite(index_vec, CEED_MEM_HOST, &array)); 484ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < num_nodes; i++) array[i] = i; 4852b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArray(index_vec, &array)); 486eaf62fffSJeremy L Thompson CeedVector elem_dof; 4872b730f8bSJeremy L Thompson CeedCall(CeedVectorCreate(ceed, num_elem * elem_size * num_comp, &elem_dof)); 4882b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(elem_dof, 0.0)); 4892b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionApply(rstr_in, CEED_NOTRANSPOSE, index_vec, elem_dof, CEED_REQUEST_IMMEDIATE)); 490eaf62fffSJeremy L Thompson const CeedScalar *elem_dof_a; 4912b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayRead(elem_dof, CEED_MEM_HOST, &elem_dof_a)); 4922b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&index_vec)); 493eaf62fffSJeremy L Thompson 494eaf62fffSJeremy L Thompson // Determine i, j locations for element matrices 495eaf62fffSJeremy L Thompson CeedInt count = 0; 496ed9e99e6SJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) { 497ed9e99e6SJeremy L Thompson for (CeedInt comp_in = 0; comp_in < num_comp; comp_in++) { 498ed9e99e6SJeremy L Thompson for (CeedInt comp_out = 0; comp_out < num_comp; comp_out++) { 499ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < elem_size; i++) { 500ed9e99e6SJeremy L Thompson for (CeedInt j = 0; j < elem_size; j++) { 5012b730f8bSJeremy L Thompson const CeedInt elem_dof_index_row = i * layout_er[0] + (comp_out)*layout_er[1] + e * layout_er[2]; 5022b730f8bSJeremy L Thompson const CeedInt elem_dof_index_col = j * layout_er[0] + 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 } 5152b730f8bSJeremy 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 5192b730f8bSJeremy L Thompson } 5202b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(elem_dof, &elem_dof_a)); 5212b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&elem_dof)); 522eaf62fffSJeremy L Thompson 523eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 524eaf62fffSJeremy L Thompson } 525eaf62fffSJeremy L Thompson 526eaf62fffSJeremy L Thompson /** 527eaf62fffSJeremy L Thompson @brief Assemble nonzero entries for non-composite operator 528eaf62fffSJeremy L Thompson 529eaf62fffSJeremy L Thompson Users should generally use CeedOperatorLinearAssemble() 530eaf62fffSJeremy L Thompson 531eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 532ea61e9acSJeremy L Thompson @param[in] offset Offset for number of entries 533eaf62fffSJeremy L Thompson @param[out] values Values to assemble into matrix 534eaf62fffSJeremy L Thompson 535eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 536eaf62fffSJeremy L Thompson 537eaf62fffSJeremy L Thompson @ref Developer 538eaf62fffSJeremy L Thompson **/ 5392b730f8bSJeremy L Thompson static int CeedSingleOperatorAssemble(CeedOperator op, CeedInt offset, CeedVector values) { 540f3d47e36SJeremy L Thompson Ceed ceed; 541f3d47e36SJeremy L Thompson bool is_composite; 542f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 543f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 544f3d47e36SJeremy L Thompson 545f3d47e36SJeremy L Thompson if (is_composite) { 546eaf62fffSJeremy L Thompson // LCOV_EXCL_START 5472b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Composite operator not supported"); 548eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 5492b730f8bSJeremy L Thompson } 550f3d47e36SJeremy L Thompson 551f3d47e36SJeremy L Thompson // Early exit for empty operator 552f3d47e36SJeremy L Thompson { 553f3d47e36SJeremy L Thompson CeedInt num_elem = 0; 554f3d47e36SJeremy L Thompson 555f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 556f3d47e36SJeremy L Thompson if (num_elem == 0) return CEED_ERROR_SUCCESS; 557f3d47e36SJeremy L Thompson } 558eaf62fffSJeremy L Thompson 559cefa2673SJeremy L Thompson if (op->LinearAssembleSingle) { 560cefa2673SJeremy L Thompson // Backend version 5612b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleSingle(op, offset, values)); 562cefa2673SJeremy L Thompson return CEED_ERROR_SUCCESS; 563cefa2673SJeremy L Thompson } else { 564cefa2673SJeremy L Thompson // Operator fallback 565cefa2673SJeremy L Thompson CeedOperator op_fallback; 566cefa2673SJeremy L Thompson 5672b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 568cefa2673SJeremy L Thompson if (op_fallback) { 5692b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemble(op_fallback, offset, values)); 570cefa2673SJeremy L Thompson return CEED_ERROR_SUCCESS; 571cefa2673SJeremy L Thompson } 572cefa2673SJeremy L Thompson } 573cefa2673SJeremy L Thompson 574eaf62fffSJeremy L Thompson // Assemble QFunction 575eaf62fffSJeremy L Thompson CeedQFunction qf; 5762b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetQFunction(op, &qf)); 577eaf62fffSJeremy L Thompson CeedVector assembled_qf; 578eaf62fffSJeremy L Thompson CeedElemRestriction rstr_q; 5792b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled_qf, &rstr_q, CEED_REQUEST_IMMEDIATE)); 5801f9221feSJeremy L Thompson CeedSize qf_length; 5812b730f8bSJeremy L Thompson CeedCall(CeedVectorGetLength(assembled_qf, &qf_length)); 582eaf62fffSJeremy L Thompson 5837e7773b5SJeremy L Thompson CeedInt num_input_fields, num_output_fields; 584eaf62fffSJeremy L Thompson CeedOperatorField *input_fields; 585eaf62fffSJeremy L Thompson CeedOperatorField *output_fields; 5862b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields)); 587eaf62fffSJeremy L Thompson 588ed9e99e6SJeremy L Thompson // Get assembly data 589ed9e99e6SJeremy L Thompson CeedOperatorAssemblyData data; 5902b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetOperatorAssemblyData(op, &data)); 591437c7c90SJeremy L Thompson const CeedEvalMode **eval_modes_in, **eval_modes_out; 592437c7c90SJeremy L Thompson CeedInt *num_eval_modes_in, *num_eval_modes_out, num_active_bases; 593437c7c90SJeremy L Thompson CeedCall(CeedOperatorAssemblyDataGetEvalModes(data, &num_active_bases, &num_eval_modes_in, &eval_modes_in, NULL, &num_eval_modes_out, 594437c7c90SJeremy L Thompson &eval_modes_out, NULL, NULL)); 595437c7c90SJeremy L Thompson CeedBasis *bases; 596437c7c90SJeremy L Thompson CeedCall(CeedOperatorAssemblyDataGetBases(data, NULL, &bases, NULL, NULL)); 597437c7c90SJeremy L Thompson CeedBasis basis_in = bases[0]; 598eaf62fffSJeremy L Thompson 599437c7c90SJeremy L Thompson if (num_active_bases > 1) { 600437c7c90SJeremy L Thompson // LCOV_EXCL_START 601437c7c90SJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Cannot assemble operator with multiple active bases"); 602437c7c90SJeremy L Thompson // LCOV_EXCL_STOP 603437c7c90SJeremy L Thompson } 604437c7c90SJeremy L Thompson if (num_eval_modes_in[0] == 0 || num_eval_modes_out[0] == 0) { 605eaf62fffSJeremy L Thompson // LCOV_EXCL_START 6062b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Cannot assemble operator with out inputs/outputs"); 607eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 6082b730f8bSJeremy L Thompson } 609eaf62fffSJeremy L Thompson 610ed9e99e6SJeremy L Thompson CeedElemRestriction active_rstr; 611eaf62fffSJeremy L Thompson CeedInt num_elem, elem_size, num_qpts, num_comp; 6122b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveElemRestriction(op, &active_rstr)); 6132b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(active_rstr, &num_elem)); 6142b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetElementSize(active_rstr, &elem_size)); 6152b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumComponents(active_rstr, &num_comp)); 6162b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts)); 617eaf62fffSJeremy L Thompson 618eaf62fffSJeremy L Thompson CeedInt local_num_entries = elem_size * num_comp * elem_size * num_comp * num_elem; 619eaf62fffSJeremy L Thompson 620eaf62fffSJeremy L Thompson // loop over elements and put in data structure 621eaf62fffSJeremy L Thompson const CeedScalar *assembled_qf_array; 6222b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array)); 623eaf62fffSJeremy L Thompson 624eaf62fffSJeremy L Thompson CeedInt layout_qf[3]; 6252b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetELayout(rstr_q, &layout_qf)); 6262b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&rstr_q)); 627eaf62fffSJeremy L Thompson 628eaf62fffSJeremy L Thompson // we store B_mat_in, B_mat_out, BTD, elem_mat in row-major order 629437c7c90SJeremy L Thompson const CeedScalar **B_mats_in, **B_mats_out; 630437c7c90SJeremy L Thompson CeedCall(CeedOperatorAssemblyDataGetBases(data, NULL, NULL, &B_mats_in, &B_mats_out)); 631437c7c90SJeremy L Thompson const CeedScalar *B_mat_in = B_mats_in[0], *B_mat_out = B_mats_out[0]; 632437c7c90SJeremy L Thompson CeedScalar BTD_mat[elem_size * num_qpts * num_eval_modes_in[0]]; 633eaf62fffSJeremy L Thompson CeedScalar elem_mat[elem_size * elem_size]; 63492ae7e47SJeremy L Thompson CeedInt count = 0; 635eaf62fffSJeremy L Thompson CeedScalar *vals; 63628ec399dSJeremy L Thompson CeedCall(CeedVectorGetArray(values, CEED_MEM_HOST, &vals)); 637ed9e99e6SJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) { 638ed9e99e6SJeremy L Thompson for (CeedInt comp_in = 0; comp_in < num_comp; comp_in++) { 639ed9e99e6SJeremy L Thompson for (CeedInt comp_out = 0; comp_out < num_comp; comp_out++) { 640ed9e99e6SJeremy L Thompson // Compute B^T*D 641ed9e99e6SJeremy L Thompson for (CeedInt n = 0; n < elem_size; n++) { 642ed9e99e6SJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 643437c7c90SJeremy L Thompson for (CeedInt e_in = 0; e_in < num_eval_modes_in[0]; e_in++) { 644437c7c90SJeremy L Thompson const CeedInt btd_index = n * (num_qpts * num_eval_modes_in[0]) + (num_eval_modes_in[0] * q + e_in); 645067fd99fSJeremy L Thompson CeedScalar sum = 0.0; 646437c7c90SJeremy L Thompson for (CeedInt e_out = 0; e_out < num_eval_modes_out[0]; e_out++) { 647437c7c90SJeremy L Thompson const CeedInt b_out_index = (num_eval_modes_out[0] * q + e_out) * elem_size + n; 648437c7c90SJeremy L Thompson const CeedInt eval_mode_index = ((e_in * num_comp + comp_in) * num_eval_modes_out[0] + e_out) * num_comp + comp_out; 6492b730f8bSJeremy L Thompson const CeedInt qf_index = q * layout_qf[0] + eval_mode_index * layout_qf[1] + e * layout_qf[2]; 650067fd99fSJeremy L Thompson sum += B_mat_out[b_out_index] * assembled_qf_array[qf_index]; 651eaf62fffSJeremy L Thompson } 652067fd99fSJeremy L Thompson BTD_mat[btd_index] = sum; 653ed9e99e6SJeremy L Thompson } 654ed9e99e6SJeremy L Thompson } 655eaf62fffSJeremy L Thompson } 656eaf62fffSJeremy L Thompson // form element matrix itself (for each block component) 657437c7c90SJeremy L Thompson CeedCall(CeedMatrixMatrixMultiply(ceed, BTD_mat, B_mat_in, elem_mat, elem_size, elem_size, num_qpts * num_eval_modes_in[0])); 658eaf62fffSJeremy L Thompson 659eaf62fffSJeremy L Thompson // put element matrix in coordinate data structure 660ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < elem_size; i++) { 661ed9e99e6SJeremy L Thompson for (CeedInt j = 0; j < elem_size; j++) { 662eaf62fffSJeremy L Thompson vals[offset + count] = elem_mat[i * elem_size + j]; 663eaf62fffSJeremy L Thompson count++; 664eaf62fffSJeremy L Thompson } 665eaf62fffSJeremy L Thompson } 666eaf62fffSJeremy L Thompson } 667eaf62fffSJeremy L Thompson } 668eaf62fffSJeremy L Thompson } 6692b730f8bSJeremy L Thompson if (count != local_num_entries) { 670eaf62fffSJeremy L Thompson // LCOV_EXCL_START 671eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing entries"); 672eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 6732b730f8bSJeremy L Thompson } 6742b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArray(values, &vals)); 675eaf62fffSJeremy L Thompson 6762b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array)); 6772b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&assembled_qf)); 678eaf62fffSJeremy L Thompson 679eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 680eaf62fffSJeremy L Thompson } 681eaf62fffSJeremy L Thompson 682eaf62fffSJeremy L Thompson /** 683eaf62fffSJeremy L Thompson @brief Count number of entries for assembled CeedOperator 684eaf62fffSJeremy L Thompson 685eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 686eaf62fffSJeremy L Thompson @param[out] num_entries Number of entries in assembled representation 687eaf62fffSJeremy L Thompson 688eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 689eaf62fffSJeremy L Thompson 690eaf62fffSJeremy L Thompson @ref Utility 691eaf62fffSJeremy L Thompson **/ 6922b730f8bSJeremy L Thompson static int CeedSingleOperatorAssemblyCountEntries(CeedOperator op, CeedInt *num_entries) { 693b275c451SJeremy L Thompson bool is_composite; 694eaf62fffSJeremy L Thompson CeedElemRestriction rstr; 695eaf62fffSJeremy L Thompson CeedInt num_elem, elem_size, num_comp; 696eaf62fffSJeremy L Thompson 697b275c451SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 698b275c451SJeremy L Thompson if (is_composite) { 699eaf62fffSJeremy L Thompson // LCOV_EXCL_START 7002b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, "Composite operator not supported"); 701eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 7022b730f8bSJeremy L Thompson } 7032b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveElemRestriction(op, &rstr)); 7042b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 7052b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 7062b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 707eaf62fffSJeremy L Thompson *num_entries = elem_size * num_comp * elem_size * num_comp * num_elem; 708eaf62fffSJeremy L Thompson 709eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 710eaf62fffSJeremy L Thompson } 711eaf62fffSJeremy L Thompson 712eaf62fffSJeremy L Thompson /** 713ea61e9acSJeremy L Thompson @brief Common code for creating a multigrid coarse operator and level transfer operators for a CeedOperator 714eaf62fffSJeremy L Thompson 715eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 71685bb9dcfSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter, or NULL if not creating prolongation/restriction operators 717eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 718eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 71985bb9dcfSJeremy L Thompson @param[in] basis_c_to_f Basis for coarse to fine interpolation, or NULL if not creating prolongation/restriction operators 720eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 72185bb9dcfSJeremy L Thompson @param[out] op_prolong Coarse to fine operator, or NULL 72285bb9dcfSJeremy L Thompson @param[out] op_restrict Fine to coarse operator, or NULL 723eaf62fffSJeremy L Thompson 724eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 725eaf62fffSJeremy L Thompson 726eaf62fffSJeremy L Thompson @ref Developer 727eaf62fffSJeremy L Thompson **/ 7282b730f8bSJeremy L Thompson static int CeedSingleOperatorMultigridLevel(CeedOperator op_fine, CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 7292b730f8bSJeremy L Thompson CeedBasis basis_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong, CeedOperator *op_restrict) { 730eaf62fffSJeremy L Thompson Ceed ceed; 73185bb9dcfSJeremy L Thompson CeedVector mult_vec = NULL; 7322b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op_fine, &ceed)); 733eaf62fffSJeremy L Thompson 734eaf62fffSJeremy L Thompson // Check for composite operator 735eaf62fffSJeremy L Thompson bool is_composite; 7362b730f8bSJeremy L Thompson CeedCall(CeedOperatorIsComposite(op_fine, &is_composite)); 7372b730f8bSJeremy L Thompson if (is_composite) { 738eaf62fffSJeremy L Thompson // LCOV_EXCL_START 7392b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Automatic multigrid setup for composite operators not supported"); 740eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 7412b730f8bSJeremy L Thompson } 742eaf62fffSJeremy L Thompson 743eaf62fffSJeremy L Thompson // Coarse Grid 7442b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(ceed, op_fine->qf, op_fine->dqf, op_fine->dqfT, op_coarse)); 745eaf62fffSJeremy L Thompson CeedElemRestriction rstr_fine = NULL; 746eaf62fffSJeremy L Thompson // -- Clone input fields 74792ae7e47SJeremy L Thompson for (CeedInt i = 0; i < op_fine->qf->num_input_fields; i++) { 748eaf62fffSJeremy L Thompson if (op_fine->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 749437c7c90SJeremy L Thompson rstr_fine = op_fine->input_fields[i]->elem_rstr; 7502b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name, rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE)); 751eaf62fffSJeremy L Thompson } else { 752437c7c90SJeremy L Thompson CeedCall(CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name, op_fine->input_fields[i]->elem_rstr, 7532b730f8bSJeremy L Thompson op_fine->input_fields[i]->basis, op_fine->input_fields[i]->vec)); 754eaf62fffSJeremy L Thompson } 755eaf62fffSJeremy L Thompson } 756eaf62fffSJeremy L Thompson // -- Clone output fields 75792ae7e47SJeremy L Thompson for (CeedInt i = 0; i < op_fine->qf->num_output_fields; i++) { 758eaf62fffSJeremy L Thompson if (op_fine->output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 7592b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name, rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE)); 760eaf62fffSJeremy L Thompson } else { 761437c7c90SJeremy L Thompson CeedCall(CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name, op_fine->output_fields[i]->elem_rstr, 7622b730f8bSJeremy L Thompson op_fine->output_fields[i]->basis, op_fine->output_fields[i]->vec)); 763eaf62fffSJeremy L Thompson } 764eaf62fffSJeremy L Thompson } 765af99e877SJeremy L Thompson // -- Clone QFunctionAssemblyData 7662b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataReferenceCopy(op_fine->qf_assembled, &(*op_coarse)->qf_assembled)); 767eaf62fffSJeremy L Thompson 768eaf62fffSJeremy L Thompson // Multiplicity vector 76985bb9dcfSJeremy L Thompson if (op_restrict || op_prolong) { 77085bb9dcfSJeremy L Thompson CeedVector mult_e_vec; 77185bb9dcfSJeremy L Thompson 77285bb9dcfSJeremy L Thompson if (!p_mult_fine) { 77385bb9dcfSJeremy L Thompson // LCOV_EXCL_START 77485bb9dcfSJeremy L Thompson return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, "Prolongation or restriction operator creation requires fine grid multiplicity vector"); 77585bb9dcfSJeremy L Thompson // LCOV_EXCL_STOP 77685bb9dcfSJeremy L Thompson } 7772b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionCreateVector(rstr_fine, &mult_vec, &mult_e_vec)); 7782b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(mult_e_vec, 0.0)); 7792b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionApply(rstr_fine, CEED_NOTRANSPOSE, p_mult_fine, mult_e_vec, CEED_REQUEST_IMMEDIATE)); 7802b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(mult_vec, 0.0)); 7812b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionApply(rstr_fine, CEED_TRANSPOSE, mult_e_vec, mult_vec, CEED_REQUEST_IMMEDIATE)); 7822b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&mult_e_vec)); 7832b730f8bSJeremy L Thompson CeedCall(CeedVectorReciprocal(mult_vec)); 78485bb9dcfSJeremy L Thompson } 785eaf62fffSJeremy L Thompson 786addd79feSZach Atkins // Clone name 787addd79feSZach Atkins bool has_name = op_fine->name; 788addd79feSZach Atkins size_t name_len = op_fine->name ? strlen(op_fine->name) : 0; 789addd79feSZach Atkins CeedCall(CeedOperatorSetName(*op_coarse, op_fine->name)); 790addd79feSZach Atkins 79183d6adf3SZach Atkins // Check that coarse to fine basis is provided if prolong/restrict operators are requested 79283d6adf3SZach Atkins if ((op_restrict || op_prolong) && !basis_c_to_f) { 79383d6adf3SZach Atkins // LCOV_EXCL_START 79483d6adf3SZach Atkins return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, "Prolongation or restriction operator creation requires coarse-to-fine basis"); 79583d6adf3SZach Atkins // LCOV_EXCL_STOP 79683d6adf3SZach Atkins } 79783d6adf3SZach Atkins 79885bb9dcfSJeremy L Thompson // Restriction/Prolongation Operators 799eaf62fffSJeremy L Thompson CeedInt num_comp; 8002b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumComponents(basis_coarse, &num_comp)); 801addd79feSZach Atkins 802addd79feSZach Atkins // Restriction 803addd79feSZach Atkins if (op_restrict) { 804eaf62fffSJeremy L Thompson CeedInt *num_comp_r_data; 80585bb9dcfSJeremy L Thompson CeedQFunction qf_restrict; 80685bb9dcfSJeremy L Thompson CeedQFunctionContext ctx_r; 80785bb9dcfSJeremy L Thompson 80885bb9dcfSJeremy L Thompson CeedCall(CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_restrict)); 8092b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, &num_comp_r_data)); 810eaf62fffSJeremy L Thompson num_comp_r_data[0] = num_comp; 8112b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextCreate(ceed, &ctx_r)); 8122b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextSetData(ctx_r, CEED_MEM_HOST, CEED_OWN_POINTER, sizeof(*num_comp_r_data), num_comp_r_data)); 8132b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetContext(qf_restrict, ctx_r)); 8142b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextDestroy(&ctx_r)); 8152b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_restrict, "input", num_comp, CEED_EVAL_NONE)); 8162b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_restrict, "scale", num_comp, CEED_EVAL_NONE)); 8172b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddOutput(qf_restrict, "output", num_comp, CEED_EVAL_INTERP)); 8182b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetUserFlopsEstimate(qf_restrict, num_comp)); 819eaf62fffSJeremy L Thompson 8202b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(ceed, qf_restrict, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, op_restrict)); 8212b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_restrict, "input", rstr_fine, CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE)); 8222b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_restrict, "scale", rstr_fine, CEED_BASIS_COLLOCATED, mult_vec)); 8232b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_restrict, "output", rstr_coarse, basis_c_to_f, CEED_VECTOR_ACTIVE)); 824eaf62fffSJeremy L Thompson 825addd79feSZach Atkins // Set name 826addd79feSZach Atkins char *restriction_name; 827addd79feSZach Atkins CeedCall(CeedCalloc(17 + name_len, &restriction_name)); 828addd79feSZach Atkins sprintf(restriction_name, "restriction%s%s", has_name ? " for " : "", has_name ? op_fine->name : ""); 829addd79feSZach Atkins CeedCall(CeedOperatorSetName(*op_restrict, restriction_name)); 830addd79feSZach Atkins CeedCall(CeedFree(&restriction_name)); 831addd79feSZach Atkins 832addd79feSZach Atkins // Check 833addd79feSZach Atkins CeedCall(CeedOperatorCheckReady(*op_restrict)); 834addd79feSZach Atkins 835addd79feSZach Atkins // Cleanup 836addd79feSZach Atkins CeedCall(CeedQFunctionDestroy(&qf_restrict)); 837addd79feSZach Atkins } 838addd79feSZach Atkins 839eaf62fffSJeremy L Thompson // Prolongation 840addd79feSZach Atkins if (op_prolong) { 841eaf62fffSJeremy L Thompson CeedInt *num_comp_p_data; 84285bb9dcfSJeremy L Thompson CeedQFunction qf_prolong; 84385bb9dcfSJeremy L Thompson CeedQFunctionContext ctx_p; 84485bb9dcfSJeremy L Thompson 84585bb9dcfSJeremy L Thompson CeedCall(CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_prolong)); 8462b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, &num_comp_p_data)); 847eaf62fffSJeremy L Thompson num_comp_p_data[0] = num_comp; 8482b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextCreate(ceed, &ctx_p)); 8492b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextSetData(ctx_p, CEED_MEM_HOST, CEED_OWN_POINTER, sizeof(*num_comp_p_data), num_comp_p_data)); 8502b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetContext(qf_prolong, ctx_p)); 8512b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextDestroy(&ctx_p)); 8522b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_prolong, "input", num_comp, CEED_EVAL_INTERP)); 8532b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_prolong, "scale", num_comp, CEED_EVAL_NONE)); 8542b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddOutput(qf_prolong, "output", num_comp, CEED_EVAL_NONE)); 8552b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetUserFlopsEstimate(qf_prolong, num_comp)); 856eaf62fffSJeremy L Thompson 8572b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(ceed, qf_prolong, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, op_prolong)); 8582b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_prolong, "input", rstr_coarse, basis_c_to_f, CEED_VECTOR_ACTIVE)); 8592b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_prolong, "scale", rstr_fine, CEED_BASIS_COLLOCATED, mult_vec)); 8602b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_prolong, "output", rstr_fine, CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE)); 861eaf62fffSJeremy L Thompson 862addd79feSZach Atkins // Set name 863ea6b5821SJeremy L Thompson char *prolongation_name; 8642b730f8bSJeremy L Thompson CeedCall(CeedCalloc(18 + name_len, &prolongation_name)); 8652b730f8bSJeremy L Thompson sprintf(prolongation_name, "prolongation%s%s", has_name ? " for " : "", has_name ? op_fine->name : ""); 8662b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetName(*op_prolong, prolongation_name)); 8672b730f8bSJeremy L Thompson CeedCall(CeedFree(&prolongation_name)); 868addd79feSZach Atkins 869addd79feSZach Atkins // Check 870addd79feSZach Atkins CeedCall(CeedOperatorCheckReady(*op_prolong)); 871addd79feSZach Atkins 872addd79feSZach Atkins // Cleanup 873addd79feSZach Atkins CeedCall(CeedQFunctionDestroy(&qf_prolong)); 874ea6b5821SJeremy L Thompson } 875ea6b5821SJeremy L Thompson 87658e4b056SJeremy L Thompson // Check 87758e4b056SJeremy L Thompson CeedCall(CeedOperatorCheckReady(*op_coarse)); 87858e4b056SJeremy L Thompson 879eaf62fffSJeremy L Thompson // Cleanup 8802b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&mult_vec)); 8812b730f8bSJeremy L Thompson CeedCall(CeedBasisDestroy(&basis_c_to_f)); 882805fe78eSJeremy L Thompson 883eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 884eaf62fffSJeremy L Thompson } 885eaf62fffSJeremy L Thompson 886eaf62fffSJeremy L Thompson /** 887eaf62fffSJeremy L Thompson @brief Build 1D mass matrix and Laplacian with perturbation 888eaf62fffSJeremy L Thompson 889eaf62fffSJeremy L Thompson @param[in] interp_1d Interpolation matrix in one dimension 890eaf62fffSJeremy L Thompson @param[in] grad_1d Gradient matrix in one dimension 891eaf62fffSJeremy L Thompson @param[in] q_weight_1d Quadrature weights in one dimension 892eaf62fffSJeremy L Thompson @param[in] P_1d Number of basis nodes in one dimension 893eaf62fffSJeremy L Thompson @param[in] Q_1d Number of quadrature points in one dimension 894eaf62fffSJeremy L Thompson @param[in] dim Dimension of basis 895eaf62fffSJeremy L Thompson @param[out] mass Assembled mass matrix in one dimension 896eaf62fffSJeremy L Thompson @param[out] laplace Assembled perturbed Laplacian in one dimension 897eaf62fffSJeremy L Thompson 898eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 899eaf62fffSJeremy L Thompson 900eaf62fffSJeremy L Thompson @ref Developer 901eaf62fffSJeremy L Thompson **/ 9022c2ea1dbSJeremy L Thompson CeedPragmaOptimizeOff 9032c2ea1dbSJeremy L Thompson static int CeedBuildMassLaplace(const CeedScalar *interp_1d, const CeedScalar *grad_1d, const CeedScalar *q_weight_1d, CeedInt P_1d, CeedInt Q_1d, 9042c2ea1dbSJeremy L Thompson CeedInt dim, CeedScalar *mass, CeedScalar *laplace) { 9052b730f8bSJeremy L Thompson for (CeedInt i = 0; i < P_1d; i++) { 906eaf62fffSJeremy L Thompson for (CeedInt j = 0; j < P_1d; j++) { 907eaf62fffSJeremy L Thompson CeedScalar sum = 0.0; 9082b730f8bSJeremy L Thompson for (CeedInt k = 0; k < Q_1d; k++) sum += interp_1d[k * P_1d + i] * q_weight_1d[k] * interp_1d[k * P_1d + j]; 909eaf62fffSJeremy L Thompson mass[i + j * P_1d] = sum; 910eaf62fffSJeremy L Thompson } 9112b730f8bSJeremy L Thompson } 912eaf62fffSJeremy L Thompson // -- Laplacian 9132b730f8bSJeremy L Thompson for (CeedInt i = 0; i < P_1d; i++) { 914eaf62fffSJeremy L Thompson for (CeedInt j = 0; j < P_1d; j++) { 915eaf62fffSJeremy L Thompson CeedScalar sum = 0.0; 9162b730f8bSJeremy L Thompson for (CeedInt k = 0; k < Q_1d; k++) sum += grad_1d[k * P_1d + i] * q_weight_1d[k] * grad_1d[k * P_1d + j]; 917eaf62fffSJeremy L Thompson laplace[i + j * P_1d] = sum; 918eaf62fffSJeremy L Thompson } 9192b730f8bSJeremy L Thompson } 920eaf62fffSJeremy L Thompson CeedScalar perturbation = dim > 2 ? 1e-6 : 1e-4; 9212b730f8bSJeremy L Thompson for (CeedInt i = 0; i < P_1d; i++) laplace[i + P_1d * i] += perturbation; 922eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 923eaf62fffSJeremy L Thompson } 9242c2ea1dbSJeremy L Thompson CeedPragmaOptimizeOn 925eaf62fffSJeremy L Thompson 926eaf62fffSJeremy L Thompson /// @} 927eaf62fffSJeremy L Thompson 928eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 929480fae85SJeremy L Thompson /// CeedOperator Backend API 930480fae85SJeremy L Thompson /// ---------------------------------------------------------------------------- 931480fae85SJeremy L Thompson /// @addtogroup CeedOperatorBackend 932480fae85SJeremy L Thompson /// @{ 933480fae85SJeremy L Thompson 934480fae85SJeremy L Thompson /** 935480fae85SJeremy L Thompson @brief Create object holding CeedQFunction assembly data for CeedOperator 936480fae85SJeremy L Thompson 937480fae85SJeremy L Thompson @param[in] ceed A Ceed object where the CeedQFunctionAssemblyData will be created 938ea61e9acSJeremy L Thompson @param[out] data Address of the variable where the newly created CeedQFunctionAssemblyData will be stored 939480fae85SJeremy L Thompson 940480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 941480fae85SJeremy L Thompson 942480fae85SJeremy L Thompson @ref Backend 943480fae85SJeremy L Thompson **/ 944ea61e9acSJeremy L Thompson int CeedQFunctionAssemblyDataCreate(Ceed ceed, CeedQFunctionAssemblyData *data) { 9452b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, data)); 946480fae85SJeremy L Thompson (*data)->ref_count = 1; 947480fae85SJeremy L Thompson (*data)->ceed = ceed; 9482b730f8bSJeremy L Thompson CeedCall(CeedReference(ceed)); 949480fae85SJeremy L Thompson 950480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 951480fae85SJeremy L Thompson } 952480fae85SJeremy L Thompson 953480fae85SJeremy L Thompson /** 954480fae85SJeremy L Thompson @brief Increment the reference counter for a CeedQFunctionAssemblyData 955480fae85SJeremy L Thompson 956ea61e9acSJeremy L Thompson @param[in,out] data CeedQFunctionAssemblyData to increment the reference counter 957480fae85SJeremy L Thompson 958480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 959480fae85SJeremy L Thompson 960480fae85SJeremy L Thompson @ref Backend 961480fae85SJeremy L Thompson **/ 962480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataReference(CeedQFunctionAssemblyData data) { 963480fae85SJeremy L Thompson data->ref_count++; 964480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 965480fae85SJeremy L Thompson } 966480fae85SJeremy L Thompson 967480fae85SJeremy L Thompson /** 968beecbf24SJeremy L Thompson @brief Set re-use of CeedQFunctionAssemblyData 9698b919e6bSJeremy L Thompson 970ea61e9acSJeremy L Thompson @param[in,out] data CeedQFunctionAssemblyData to mark for reuse 971ea61e9acSJeremy L Thompson @param[in] reuse_data Boolean flag indicating data re-use 9728b919e6bSJeremy L Thompson 9738b919e6bSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 9748b919e6bSJeremy L Thompson 9758b919e6bSJeremy L Thompson @ref Backend 9768b919e6bSJeremy L Thompson **/ 9772b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataSetReuse(CeedQFunctionAssemblyData data, bool reuse_data) { 978beecbf24SJeremy L Thompson data->reuse_data = reuse_data; 979beecbf24SJeremy L Thompson data->needs_data_update = true; 980beecbf24SJeremy L Thompson return CEED_ERROR_SUCCESS; 981beecbf24SJeremy L Thompson } 982beecbf24SJeremy L Thompson 983beecbf24SJeremy L Thompson /** 984beecbf24SJeremy L Thompson @brief Mark QFunctionAssemblyData as stale 985beecbf24SJeremy L Thompson 986ea61e9acSJeremy L Thompson @param[in,out] data CeedQFunctionAssemblyData to mark as stale 987ea61e9acSJeremy L Thompson @param[in] needs_data_update Boolean flag indicating if update is needed or completed 988beecbf24SJeremy L Thompson 989beecbf24SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 990beecbf24SJeremy L Thompson 991beecbf24SJeremy L Thompson @ref Backend 992beecbf24SJeremy L Thompson **/ 9932b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataSetUpdateNeeded(CeedQFunctionAssemblyData data, bool needs_data_update) { 994beecbf24SJeremy L Thompson data->needs_data_update = needs_data_update; 9958b919e6bSJeremy L Thompson return CEED_ERROR_SUCCESS; 9968b919e6bSJeremy L Thompson } 9978b919e6bSJeremy L Thompson 9988b919e6bSJeremy L Thompson /** 9998b919e6bSJeremy L Thompson @brief Determine if QFunctionAssemblyData needs update 10008b919e6bSJeremy L Thompson 10018b919e6bSJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to mark as stale 10028b919e6bSJeremy L Thompson @param[out] is_update_needed Boolean flag indicating if re-assembly is required 10038b919e6bSJeremy L Thompson 10048b919e6bSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 10058b919e6bSJeremy L Thompson 10068b919e6bSJeremy L Thompson @ref Backend 10078b919e6bSJeremy L Thompson **/ 10082b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataIsUpdateNeeded(CeedQFunctionAssemblyData data, bool *is_update_needed) { 1009beecbf24SJeremy L Thompson *is_update_needed = !data->reuse_data || data->needs_data_update; 10108b919e6bSJeremy L Thompson return CEED_ERROR_SUCCESS; 10118b919e6bSJeremy L Thompson } 10128b919e6bSJeremy L Thompson 10138b919e6bSJeremy L Thompson /** 1014ea61e9acSJeremy L Thompson @brief Copy the pointer to a CeedQFunctionAssemblyData. 10154385fb7fSSebastian Grimberg 1016ea61e9acSJeremy L Thompson Both pointers should be destroyed with `CeedCeedQFunctionAssemblyDataDestroy()`. 1017512bb800SJeremy L Thompson 1018512bb800SJeremy L Thompson Note: If the value of `data_copy` passed to this function is non-NULL, then it is assumed that `*data_copy` is a pointer to a 1019512bb800SJeremy L Thompson CeedQFunctionAssemblyData. This CeedQFunctionAssemblyData will be destroyed if `data_copy` is the only reference to this 1020512bb800SJeremy L Thompson CeedQFunctionAssemblyData. 1021480fae85SJeremy L Thompson 1022ea61e9acSJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to copy reference to 1023ea61e9acSJeremy L Thompson @param[in,out] data_copy Variable to store copied reference 1024480fae85SJeremy L Thompson 1025480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1026480fae85SJeremy L Thompson 1027480fae85SJeremy L Thompson @ref Backend 1028480fae85SJeremy L Thompson **/ 10292b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataReferenceCopy(CeedQFunctionAssemblyData data, CeedQFunctionAssemblyData *data_copy) { 10302b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataReference(data)); 10312b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataDestroy(data_copy)); 1032480fae85SJeremy L Thompson *data_copy = data; 1033480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1034480fae85SJeremy L Thompson } 1035480fae85SJeremy L Thompson 1036480fae85SJeremy L Thompson /** 1037480fae85SJeremy L Thompson @brief Get setup status for internal objects for CeedQFunctionAssemblyData 1038480fae85SJeremy L Thompson 1039ea61e9acSJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to retrieve status 1040480fae85SJeremy L Thompson @param[out] is_setup Boolean flag for setup status 1041480fae85SJeremy L Thompson 1042480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1043480fae85SJeremy L Thompson 1044480fae85SJeremy L Thompson @ref Backend 1045480fae85SJeremy L Thompson **/ 10462b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataIsSetup(CeedQFunctionAssemblyData data, bool *is_setup) { 1047480fae85SJeremy L Thompson *is_setup = data->is_setup; 1048480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1049480fae85SJeremy L Thompson } 1050480fae85SJeremy L Thompson 1051480fae85SJeremy L Thompson /** 1052480fae85SJeremy L Thompson @brief Set internal objects for CeedQFunctionAssemblyData 1053480fae85SJeremy L Thompson 1054ea61e9acSJeremy L Thompson @param[in,out] data CeedQFunctionAssemblyData to set objects 1055480fae85SJeremy L Thompson @param[in] vec CeedVector to store assembled CeedQFunction at quadrature points 1056480fae85SJeremy L Thompson @param[in] rstr CeedElemRestriction for CeedVector containing assembled CeedQFunction 1057480fae85SJeremy L Thompson 1058480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1059480fae85SJeremy L Thompson 1060480fae85SJeremy L Thompson @ref Backend 1061480fae85SJeremy L Thompson **/ 10622b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataSetObjects(CeedQFunctionAssemblyData data, CeedVector vec, CeedElemRestriction rstr) { 10632b730f8bSJeremy L Thompson CeedCall(CeedVectorReferenceCopy(vec, &data->vec)); 10642b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionReferenceCopy(rstr, &data->rstr)); 1065480fae85SJeremy L Thompson 1066480fae85SJeremy L Thompson data->is_setup = true; 1067480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1068480fae85SJeremy L Thompson } 1069480fae85SJeremy L Thompson 10702b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataGetObjects(CeedQFunctionAssemblyData data, CeedVector *vec, CeedElemRestriction *rstr) { 10712b730f8bSJeremy L Thompson if (!data->is_setup) { 1072480fae85SJeremy L Thompson // LCOV_EXCL_START 10732b730f8bSJeremy L Thompson return CeedError(data->ceed, CEED_ERROR_INCOMPLETE, "Internal objects not set; must call CeedQFunctionAssemblyDataSetObjects first."); 1074480fae85SJeremy L Thompson // LCOV_EXCL_STOP 10752b730f8bSJeremy L Thompson } 1076480fae85SJeremy L Thompson 10772b730f8bSJeremy L Thompson CeedCall(CeedVectorReferenceCopy(data->vec, vec)); 10782b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionReferenceCopy(data->rstr, rstr)); 1079480fae85SJeremy L Thompson 1080480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1081480fae85SJeremy L Thompson } 1082480fae85SJeremy L Thompson 1083480fae85SJeremy L Thompson /** 1084480fae85SJeremy L Thompson @brief Destroy CeedQFunctionAssemblyData 1085480fae85SJeremy L Thompson 1086ea61e9acSJeremy L Thompson @param[in,out] data CeedQFunctionAssemblyData to destroy 1087480fae85SJeremy L Thompson 1088480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1089480fae85SJeremy L Thompson 1090480fae85SJeremy L Thompson @ref Backend 1091480fae85SJeremy L Thompson **/ 1092480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataDestroy(CeedQFunctionAssemblyData *data) { 1093ad6481ceSJeremy L Thompson if (!*data || --(*data)->ref_count > 0) { 1094ad6481ceSJeremy L Thompson *data = NULL; 1095ad6481ceSJeremy L Thompson return CEED_ERROR_SUCCESS; 1096ad6481ceSJeremy L Thompson } 10972b730f8bSJeremy L Thompson CeedCall(CeedDestroy(&(*data)->ceed)); 10982b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&(*data)->vec)); 10992b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&(*data)->rstr)); 1100480fae85SJeremy L Thompson 11012b730f8bSJeremy L Thompson CeedCall(CeedFree(data)); 1102480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1103480fae85SJeremy L Thompson } 1104480fae85SJeremy L Thompson 1105ed9e99e6SJeremy L Thompson /** 1106ed9e99e6SJeremy L Thompson @brief Get CeedOperatorAssemblyData 1107ed9e99e6SJeremy L Thompson 1108ed9e99e6SJeremy L Thompson @param[in] op CeedOperator to assemble 1109ed9e99e6SJeremy L Thompson @param[out] data CeedQFunctionAssemblyData 1110ed9e99e6SJeremy L Thompson 1111ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1112ed9e99e6SJeremy L Thompson 1113ed9e99e6SJeremy L Thompson @ref Backend 1114ed9e99e6SJeremy L Thompson **/ 11152b730f8bSJeremy L Thompson int CeedOperatorGetOperatorAssemblyData(CeedOperator op, CeedOperatorAssemblyData *data) { 1116ed9e99e6SJeremy L Thompson if (!op->op_assembled) { 1117ed9e99e6SJeremy L Thompson CeedOperatorAssemblyData data; 1118ed9e99e6SJeremy L Thompson 11192b730f8bSJeremy L Thompson CeedCall(CeedOperatorAssemblyDataCreate(op->ceed, op, &data)); 1120ed9e99e6SJeremy L Thompson op->op_assembled = data; 1121ed9e99e6SJeremy L Thompson } 1122ed9e99e6SJeremy L Thompson *data = op->op_assembled; 1123ed9e99e6SJeremy L Thompson 1124ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1125ed9e99e6SJeremy L Thompson } 1126ed9e99e6SJeremy L Thompson 1127ed9e99e6SJeremy L Thompson /** 1128ba746a46SJeremy L Thompson @brief Create object holding CeedOperator assembly data. 1129ba746a46SJeremy L Thompson 1130ba746a46SJeremy L Thompson The CeedOperatorAssemblyData holds an array with references to every active CeedBasis used in the CeedOperator. 1131ba746a46SJeremy L Thompson An array with references to the corresponding active CeedElemRestrictions is also stored. 1132ba746a46SJeremy L Thompson For each active CeedBasis, the CeedOperatorAssemblyData holds an array of all input and output CeedEvalModes for this CeedBasis. 1133ba746a46SJeremy L Thompson The CeedOperatorAssemblyData holds an array of offsets for indexing into the assembled CeedQFunction arrays to the row representing each 1134*9fd66db6SSebastian Grimberg CeedEvalMode. 1135*9fd66db6SSebastian Grimberg The number of input columns across all active bases for the assembled CeedQFunction is also stored. 1136*9fd66db6SSebastian Grimberg Lastly, the CeedOperatorAssembly data holds assembled matrices representing the full action of the CeedBasis for all CeedEvalModes. 1137ed9e99e6SJeremy L Thompson 1138ea61e9acSJeremy L Thompson @param[in] ceed Ceed object where the CeedOperatorAssemblyData will be created 1139ed9e99e6SJeremy L Thompson @param[in] op CeedOperator to be assembled 1140ea61e9acSJeremy L Thompson @param[out] data Address of the variable where the newly created CeedOperatorAssemblyData will be stored 1141ed9e99e6SJeremy L Thompson 1142ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1143ed9e99e6SJeremy L Thompson 1144ed9e99e6SJeremy L Thompson @ref Backend 1145ed9e99e6SJeremy L Thompson **/ 11462b730f8bSJeremy L Thompson int CeedOperatorAssemblyDataCreate(Ceed ceed, CeedOperator op, CeedOperatorAssemblyData *data) { 1147437c7c90SJeremy L Thompson CeedInt num_active_bases = 0; 1148437c7c90SJeremy L Thompson 1149437c7c90SJeremy L Thompson // Allocate 11502b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, data)); 1151ed9e99e6SJeremy L Thompson (*data)->ceed = ceed; 11522b730f8bSJeremy L Thompson CeedCall(CeedReference(ceed)); 1153ed9e99e6SJeremy L Thompson 1154ed9e99e6SJeremy L Thompson // Build OperatorAssembly data 1155ed9e99e6SJeremy L Thompson CeedQFunction qf; 1156ed9e99e6SJeremy L Thompson CeedQFunctionField *qf_fields; 1157ed9e99e6SJeremy L Thompson CeedOperatorField *op_fields; 1158ed9e99e6SJeremy L Thompson CeedInt num_input_fields; 11592b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetQFunction(op, &qf)); 11602b730f8bSJeremy L Thompson CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, &qf_fields, NULL, NULL)); 11612b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFields(op, NULL, &op_fields, NULL, NULL)); 1162ed9e99e6SJeremy L Thompson 1163ed9e99e6SJeremy L Thompson // Determine active input basis 1164437c7c90SJeremy L Thompson CeedInt *num_eval_modes_in = NULL, *num_eval_modes_out = NULL, offset = 0; 1165437c7c90SJeremy L Thompson CeedEvalMode **eval_modes_in = NULL, **eval_modes_out = NULL; 1166437c7c90SJeremy L Thompson CeedSize **eval_mode_offsets_in = NULL, **eval_mode_offsets_out = NULL; 1167ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < num_input_fields; i++) { 1168ed9e99e6SJeremy L Thompson CeedVector vec; 11692b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetVector(op_fields[i], &vec)); 1170ed9e99e6SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 1171437c7c90SJeremy L Thompson CeedBasis basis_in = NULL; 1172437c7c90SJeremy L Thompson CeedEvalMode eval_mode; 1173352a5e7cSSebastian Grimberg CeedInt index = -1, dim, num_comp, q_comp; 11742b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetBasis(op_fields[i], &basis_in)); 11752b730f8bSJeremy L Thompson CeedCall(CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode)); 1176352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetDimension(basis_in, &dim)); 1177352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumComponents(basis_in, &num_comp)); 1178352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumQuadratureComponents(basis_in, eval_mode, &q_comp)); 1179437c7c90SJeremy L Thompson for (CeedInt i = 0; i < num_active_bases; i++) { 1180437c7c90SJeremy L Thompson if ((*data)->active_bases[i] == basis_in) index = i; 1181437c7c90SJeremy L Thompson } 1182437c7c90SJeremy L Thompson if (index == -1) { 1183437c7c90SJeremy L Thompson CeedElemRestriction elem_rstr_in; 1184437c7c90SJeremy L Thompson index = num_active_bases; 1185437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &(*data)->active_bases)); 1186437c7c90SJeremy L Thompson (*data)->active_bases[num_active_bases] = NULL; 1187437c7c90SJeremy L Thompson CeedCall(CeedBasisReferenceCopy(basis_in, &(*data)->active_bases[num_active_bases])); 1188437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &(*data)->active_elem_rstrs)); 1189437c7c90SJeremy L Thompson (*data)->active_elem_rstrs[num_active_bases] = NULL; 1190437c7c90SJeremy L Thompson CeedCall(CeedOperatorFieldGetElemRestriction(op_fields[i], &elem_rstr_in)); 1191437c7c90SJeremy L Thompson CeedCall(CeedElemRestrictionReferenceCopy(elem_rstr_in, &(*data)->active_elem_rstrs[num_active_bases])); 1192437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &num_eval_modes_in)); 1193437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &num_eval_modes_out)); 1194437c7c90SJeremy L Thompson num_eval_modes_in[index] = 0; 1195437c7c90SJeremy L Thompson num_eval_modes_out[index] = 0; 1196437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &eval_modes_in)); 1197437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &eval_modes_out)); 1198437c7c90SJeremy L Thompson eval_modes_in[index] = NULL; 1199437c7c90SJeremy L Thompson eval_modes_out[index] = NULL; 1200437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &eval_mode_offsets_in)); 1201437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &eval_mode_offsets_out)); 1202437c7c90SJeremy L Thompson eval_mode_offsets_in[index] = NULL; 1203437c7c90SJeremy L Thompson eval_mode_offsets_out[index] = NULL; 1204437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &(*data)->assembled_bases_in)); 1205437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &(*data)->assembled_bases_out)); 1206437c7c90SJeremy L Thompson (*data)->assembled_bases_in[index] = NULL; 1207437c7c90SJeremy L Thompson (*data)->assembled_bases_out[index] = NULL; 1208437c7c90SJeremy L Thompson num_active_bases++; 1209437c7c90SJeremy L Thompson } 1210352a5e7cSSebastian Grimberg if (eval_mode != CEED_EVAL_WEIGHT) { 1211352a5e7cSSebastian Grimberg // q_comp = 1 if CEED_EVAL_NONE, CEED_EVAL_WEIGHT caught by QF Assembly 1212352a5e7cSSebastian Grimberg CeedCall(CeedRealloc(num_eval_modes_in[index] + q_comp, &eval_modes_in[index])); 1213352a5e7cSSebastian Grimberg CeedCall(CeedRealloc(num_eval_modes_in[index] + q_comp, &eval_mode_offsets_in[index])); 1214352a5e7cSSebastian Grimberg for (CeedInt d = 0; d < q_comp; d++) { 1215437c7c90SJeremy L Thompson eval_modes_in[index][num_eval_modes_in[index] + d] = eval_mode; 1216437c7c90SJeremy L Thompson eval_mode_offsets_in[index][num_eval_modes_in[index] + d] = offset; 1217352a5e7cSSebastian Grimberg offset += num_comp; 1218ed9e99e6SJeremy L Thompson } 1219352a5e7cSSebastian Grimberg num_eval_modes_in[index] += q_comp; 1220ed9e99e6SJeremy L Thompson } 1221ed9e99e6SJeremy L Thompson } 1222ed9e99e6SJeremy L Thompson } 1223437c7c90SJeremy L Thompson (*data)->num_eval_modes_in = num_eval_modes_in; 1224437c7c90SJeremy L Thompson (*data)->eval_modes_in = eval_modes_in; 1225437c7c90SJeremy L Thompson (*data)->eval_mode_offsets_in = eval_mode_offsets_in; 1226ed9e99e6SJeremy L Thompson 1227ed9e99e6SJeremy L Thompson // Determine active output basis 1228ed9e99e6SJeremy L Thompson CeedInt num_output_fields; 12292b730f8bSJeremy L Thompson CeedCall(CeedQFunctionGetFields(qf, NULL, NULL, &num_output_fields, &qf_fields)); 12302b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFields(op, NULL, NULL, NULL, &op_fields)); 1231437c7c90SJeremy L Thompson offset = 0; 1232ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < num_output_fields; i++) { 1233ed9e99e6SJeremy L Thompson CeedVector vec; 12342b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetVector(op_fields[i], &vec)); 1235ed9e99e6SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 1236437c7c90SJeremy L Thompson CeedBasis basis_out = NULL; 1237ed9e99e6SJeremy L Thompson CeedEvalMode eval_mode; 1238352a5e7cSSebastian Grimberg CeedInt index = -1, dim, num_comp, q_comp; 1239437c7c90SJeremy L Thompson CeedCall(CeedOperatorFieldGetBasis(op_fields[i], &basis_out)); 12402b730f8bSJeremy L Thompson CeedCall(CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode)); 1241352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetDimension(basis_out, &dim)); 1242352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumComponents(basis_out, &num_comp)); 1243352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumQuadratureComponents(basis_out, eval_mode, &q_comp)); 1244437c7c90SJeremy L Thompson for (CeedInt i = 0; i < num_active_bases; i++) { 1245437c7c90SJeremy L Thompson if ((*data)->active_bases[i] == basis_out) index = i; 1246437c7c90SJeremy L Thompson } 1247437c7c90SJeremy L Thompson if (index == -1) { 1248437c7c90SJeremy L Thompson CeedElemRestriction elem_rstr_out; 1249437c7c90SJeremy L Thompson 1250437c7c90SJeremy L Thompson index = num_active_bases; 1251437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &(*data)->active_bases)); 1252437c7c90SJeremy L Thompson (*data)->active_bases[num_active_bases] = NULL; 1253437c7c90SJeremy L Thompson CeedCall(CeedBasisReferenceCopy(basis_out, &(*data)->active_bases[num_active_bases])); 1254437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &(*data)->active_elem_rstrs)); 1255437c7c90SJeremy L Thompson (*data)->active_elem_rstrs[num_active_bases] = NULL; 1256437c7c90SJeremy L Thompson CeedCall(CeedOperatorFieldGetElemRestriction(op_fields[i], &elem_rstr_out)); 1257437c7c90SJeremy L Thompson CeedCall(CeedElemRestrictionReferenceCopy(elem_rstr_out, &(*data)->active_elem_rstrs[num_active_bases])); 1258437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &num_eval_modes_in)); 1259437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &num_eval_modes_out)); 1260437c7c90SJeremy L Thompson num_eval_modes_in[index] = 0; 1261437c7c90SJeremy L Thompson num_eval_modes_out[index] = 0; 1262437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &eval_modes_in)); 1263437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &eval_modes_out)); 1264437c7c90SJeremy L Thompson eval_modes_in[index] = NULL; 1265437c7c90SJeremy L Thompson eval_modes_out[index] = NULL; 1266437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &eval_mode_offsets_in)); 1267437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &eval_mode_offsets_out)); 1268437c7c90SJeremy L Thompson eval_mode_offsets_in[index] = NULL; 1269437c7c90SJeremy L Thompson eval_mode_offsets_out[index] = NULL; 1270437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &(*data)->assembled_bases_in)); 1271437c7c90SJeremy L Thompson CeedCall(CeedRealloc(num_active_bases + 1, &(*data)->assembled_bases_out)); 1272437c7c90SJeremy L Thompson (*data)->assembled_bases_in[index] = NULL; 1273437c7c90SJeremy L Thompson (*data)->assembled_bases_out[index] = NULL; 1274437c7c90SJeremy L Thompson num_active_bases++; 1275437c7c90SJeremy L Thompson } 1276352a5e7cSSebastian Grimberg if (eval_mode != CEED_EVAL_WEIGHT) { 1277352a5e7cSSebastian Grimberg // q_comp = 1 if CEED_EVAL_NONE, CEED_EVAL_WEIGHT caught by QF Assembly 1278352a5e7cSSebastian Grimberg CeedCall(CeedRealloc(num_eval_modes_out[index] + q_comp, &eval_modes_out[index])); 1279352a5e7cSSebastian Grimberg CeedCall(CeedRealloc(num_eval_modes_out[index] + q_comp, &eval_mode_offsets_out[index])); 1280352a5e7cSSebastian Grimberg for (CeedInt d = 0; d < q_comp; d++) { 1281437c7c90SJeremy L Thompson eval_modes_out[index][num_eval_modes_out[index] + d] = eval_mode; 1282437c7c90SJeremy L Thompson eval_mode_offsets_out[index][num_eval_modes_out[index] + d] = offset; 1283352a5e7cSSebastian Grimberg offset += num_comp; 1284ed9e99e6SJeremy L Thompson } 1285352a5e7cSSebastian Grimberg num_eval_modes_out[index] += q_comp; 1286ed9e99e6SJeremy L Thompson } 1287ed9e99e6SJeremy L Thompson } 1288ed9e99e6SJeremy L Thompson } 1289437c7c90SJeremy L Thompson (*data)->num_output_components = offset; 1290437c7c90SJeremy L Thompson (*data)->num_eval_modes_out = num_eval_modes_out; 1291437c7c90SJeremy L Thompson (*data)->eval_modes_out = eval_modes_out; 1292437c7c90SJeremy L Thompson (*data)->eval_mode_offsets_out = eval_mode_offsets_out; 1293437c7c90SJeremy L Thompson (*data)->num_active_bases = num_active_bases; 1294ed9e99e6SJeremy L Thompson 1295ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1296ed9e99e6SJeremy L Thompson } 1297ed9e99e6SJeremy L Thompson 1298ed9e99e6SJeremy L Thompson /** 1299ba746a46SJeremy L Thompson @brief Get CeedOperator CeedEvalModes for assembly. 1300ba746a46SJeremy L Thompson 1301ba746a46SJeremy L Thompson Note: See CeedOperatorAssemblyDataCreate for a full description of the data stored in this object. 1302ed9e99e6SJeremy L Thompson 1303ed9e99e6SJeremy L Thompson @param[in] data CeedOperatorAssemblyData 1304ba746a46SJeremy L Thompson @param[out] num_active_bases Total number of active bases 1305c5d0f995SJed Brown @param[out] num_eval_modes_in Pointer to hold array of numbers of input CeedEvalModes, or NULL. 1306ba746a46SJeremy L Thompson `eval_modes_in[0]` holds an array of eval modes for the first active basis. 1307c5d0f995SJed Brown @param[out] eval_modes_in Pointer to hold arrays of input CeedEvalModes, or NULL. 1308ba746a46SJeremy L Thompson @param[out] eval_mode_offsets_in Pointer to hold arrays of input offsets at each quadrature point. 1309c5d0f995SJed Brown @param[out] num_eval_modes_out Pointer to hold array of numbers of output CeedEvalModes, or NULL 1310c5d0f995SJed Brown @param[out] eval_modes_out Pointer to hold arrays of output CeedEvalModes, or NULL. 1311437c7c90SJeremy L Thompson @param[out] eval_mode_offsets_out Pointer to hold arrays of output offsets at each quadrature point 1312ba746a46SJeremy L Thompson @param[out] num_output_components The number of columns in the assembled CeedQFunction matrix for each quadrature point, 1313ba746a46SJeremy L Thompson including contributions of all active bases 1314ed9e99e6SJeremy L Thompson 1315ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1316ed9e99e6SJeremy L Thompson 1317c5d0f995SJed Brown 1318ed9e99e6SJeremy L Thompson @ref Backend 1319ed9e99e6SJeremy L Thompson **/ 1320437c7c90SJeremy L Thompson int CeedOperatorAssemblyDataGetEvalModes(CeedOperatorAssemblyData data, CeedInt *num_active_bases, CeedInt **num_eval_modes_in, 1321437c7c90SJeremy L Thompson const CeedEvalMode ***eval_modes_in, CeedSize ***eval_mode_offsets_in, CeedInt **num_eval_modes_out, 1322437c7c90SJeremy L Thompson const CeedEvalMode ***eval_modes_out, CeedSize ***eval_mode_offsets_out, CeedSize *num_output_components) { 1323437c7c90SJeremy L Thompson if (num_active_bases) *num_active_bases = data->num_active_bases; 1324437c7c90SJeremy L Thompson if (num_eval_modes_in) *num_eval_modes_in = data->num_eval_modes_in; 1325437c7c90SJeremy L Thompson if (eval_modes_in) *eval_modes_in = (const CeedEvalMode **)data->eval_modes_in; 1326437c7c90SJeremy L Thompson if (eval_mode_offsets_in) *eval_mode_offsets_in = data->eval_mode_offsets_in; 1327437c7c90SJeremy L Thompson if (num_eval_modes_out) *num_eval_modes_out = data->num_eval_modes_out; 1328437c7c90SJeremy L Thompson if (eval_modes_out) *eval_modes_out = (const CeedEvalMode **)data->eval_modes_out; 1329437c7c90SJeremy L Thompson if (eval_mode_offsets_out) *eval_mode_offsets_out = data->eval_mode_offsets_out; 1330437c7c90SJeremy L Thompson if (num_output_components) *num_output_components = data->num_output_components; 1331ed9e99e6SJeremy L Thompson 1332ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1333ed9e99e6SJeremy L Thompson } 1334ed9e99e6SJeremy L Thompson 1335ed9e99e6SJeremy L Thompson /** 1336ba746a46SJeremy L Thompson @brief Get CeedOperator CeedBasis data for assembly. 1337ba746a46SJeremy L Thompson 1338ba746a46SJeremy L Thompson Note: See CeedOperatorAssemblyDataCreate for a full description of the data stored in this object. 1339ed9e99e6SJeremy L Thompson 1340ed9e99e6SJeremy L Thompson @param[in] data CeedOperatorAssemblyData 1341437c7c90SJeremy L Thompson @param[out] num_active_bases Number of active bases, or NULL 1342437c7c90SJeremy L Thompson @param[out] active_bases Pointer to hold active CeedBasis, or NULL 1343437c7c90SJeremy L Thompson @param[out] assembled_bases_in Pointer to hold assembled active input B, or NULL 1344437c7c90SJeremy L Thompson @param[out] assembled_bases_out Pointer to hold assembled active output B, or NULL 1345ed9e99e6SJeremy L Thompson 1346ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1347ed9e99e6SJeremy L Thompson 1348ed9e99e6SJeremy L Thompson @ref Backend 1349ed9e99e6SJeremy L Thompson **/ 1350437c7c90SJeremy L Thompson int CeedOperatorAssemblyDataGetBases(CeedOperatorAssemblyData data, CeedInt *num_active_bases, CeedBasis **active_bases, 1351437c7c90SJeremy L Thompson const CeedScalar ***assembled_bases_in, const CeedScalar ***assembled_bases_out) { 1352ed9e99e6SJeremy L Thompson // Assemble B_in, B_out if needed 1353437c7c90SJeremy L Thompson if (assembled_bases_in && !data->assembled_bases_in[0]) { 1354437c7c90SJeremy L Thompson CeedInt num_qpts; 1355437c7c90SJeremy L Thompson 1356437c7c90SJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(data->active_bases[0], &num_qpts)); 1357437c7c90SJeremy L Thompson for (CeedInt b = 0; b < data->num_active_bases; b++) { 1358352a5e7cSSebastian Grimberg CeedInt num_nodes; 1359437c7c90SJeremy L Thompson CeedScalar *B_in = NULL, *identity = NULL; 1360ed9e99e6SJeremy L Thompson bool has_eval_none = false; 1361ed9e99e6SJeremy L Thompson 1362352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumNodes(data->active_bases[b], &num_nodes)); 1363352a5e7cSSebastian Grimberg CeedCall(CeedCalloc(num_qpts * num_nodes * data->num_eval_modes_in[b], &B_in)); 1364ed9e99e6SJeremy L Thompson 1365437c7c90SJeremy L Thompson for (CeedInt i = 0; i < data->num_eval_modes_in[b]; i++) { 1366437c7c90SJeremy L Thompson has_eval_none = has_eval_none || (data->eval_modes_in[b][i] == CEED_EVAL_NONE); 1367ed9e99e6SJeremy L Thompson } 1368ed9e99e6SJeremy L Thompson if (has_eval_none) { 1369352a5e7cSSebastian Grimberg CeedCall(CeedCalloc(num_qpts * num_nodes, &identity)); 1370352a5e7cSSebastian Grimberg for (CeedInt i = 0; i < (num_nodes < num_qpts ? num_nodes : num_qpts); i++) { 1371352a5e7cSSebastian Grimberg identity[i * num_nodes + i] = 1.0; 1372ed9e99e6SJeremy L Thompson } 1373ed9e99e6SJeremy L Thompson } 1374ed9e99e6SJeremy L Thompson 1375ed9e99e6SJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 1376352a5e7cSSebastian Grimberg for (CeedInt n = 0; n < num_nodes; n++) { 1377352a5e7cSSebastian Grimberg CeedInt d_in = 0, q_comp_in; 1378352a5e7cSSebastian Grimberg CeedEvalMode eval_mode_in_prev = CEED_EVAL_NONE; 1379437c7c90SJeremy L Thompson for (CeedInt e_in = 0; e_in < data->num_eval_modes_in[b]; e_in++) { 1380437c7c90SJeremy L Thompson const CeedInt qq = data->num_eval_modes_in[b] * q; 1381437c7c90SJeremy L Thompson const CeedScalar *B = NULL; 1382352a5e7cSSebastian Grimberg CeedOperatorGetBasisPointer(data->active_bases[b], data->eval_modes_in[b][e_in], identity, &B); 1383352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumQuadratureComponents(data->active_bases[b], data->eval_modes_in[b][e_in], &q_comp_in)); 1384352a5e7cSSebastian Grimberg if (q_comp_in > 1) { 1385352a5e7cSSebastian Grimberg if (e_in == 0 || data->eval_modes_in[b][e_in] != eval_mode_in_prev) d_in = 0; 1386352a5e7cSSebastian Grimberg else B = &B[(++d_in) * num_qpts * num_nodes]; 1387352a5e7cSSebastian Grimberg } 1388352a5e7cSSebastian Grimberg eval_mode_in_prev = data->eval_modes_in[b][e_in]; 1389352a5e7cSSebastian Grimberg B_in[(qq + e_in) * num_nodes + n] = B[q * num_nodes + n]; 1390ed9e99e6SJeremy L Thompson } 1391ed9e99e6SJeremy L Thompson } 1392ed9e99e6SJeremy L Thompson } 1393437c7c90SJeremy L Thompson if (identity) CeedCall(CeedFree(identity)); 1394437c7c90SJeremy L Thompson data->assembled_bases_in[b] = B_in; 1395437c7c90SJeremy L Thompson } 1396ed9e99e6SJeremy L Thompson } 1397ed9e99e6SJeremy L Thompson 1398437c7c90SJeremy L Thompson if (assembled_bases_out && !data->assembled_bases_out[0]) { 1399437c7c90SJeremy L Thompson CeedInt num_qpts; 1400437c7c90SJeremy L Thompson 1401437c7c90SJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(data->active_bases[0], &num_qpts)); 1402437c7c90SJeremy L Thompson for (CeedInt b = 0; b < data->num_active_bases; b++) { 1403352a5e7cSSebastian Grimberg CeedInt num_nodes; 1404ed9e99e6SJeremy L Thompson bool has_eval_none = false; 1405437c7c90SJeremy L Thompson CeedScalar *B_out = NULL, *identity = NULL; 1406ed9e99e6SJeremy L Thompson 1407352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumNodes(data->active_bases[b], &num_nodes)); 1408352a5e7cSSebastian Grimberg CeedCall(CeedCalloc(num_qpts * num_nodes * data->num_eval_modes_out[b], &B_out)); 1409ed9e99e6SJeremy L Thompson 1410437c7c90SJeremy L Thompson for (CeedInt i = 0; i < data->num_eval_modes_out[b]; i++) { 1411437c7c90SJeremy L Thompson has_eval_none = has_eval_none || (data->eval_modes_out[b][i] == CEED_EVAL_NONE); 1412ed9e99e6SJeremy L Thompson } 1413ed9e99e6SJeremy L Thompson if (has_eval_none) { 1414352a5e7cSSebastian Grimberg CeedCall(CeedCalloc(num_qpts * num_nodes, &identity)); 1415352a5e7cSSebastian Grimberg for (CeedInt i = 0; i < (num_nodes < num_qpts ? num_nodes : num_qpts); i++) { 1416352a5e7cSSebastian Grimberg identity[i * num_nodes + i] = 1.0; 1417ed9e99e6SJeremy L Thompson } 1418ed9e99e6SJeremy L Thompson } 1419ed9e99e6SJeremy L Thompson 1420ed9e99e6SJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 1421352a5e7cSSebastian Grimberg for (CeedInt n = 0; n < num_nodes; n++) { 1422352a5e7cSSebastian Grimberg CeedInt d_out = 0, q_comp_out; 1423352a5e7cSSebastian Grimberg CeedEvalMode eval_mode_out_prev = CEED_EVAL_NONE; 1424437c7c90SJeremy L Thompson for (CeedInt e_out = 0; e_out < data->num_eval_modes_out[b]; e_out++) { 1425437c7c90SJeremy L Thompson const CeedInt qq = data->num_eval_modes_out[b] * q; 1426437c7c90SJeremy L Thompson const CeedScalar *B = NULL; 1427352a5e7cSSebastian Grimberg CeedOperatorGetBasisPointer(data->active_bases[b], data->eval_modes_out[b][e_out], identity, &B); 1428352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumQuadratureComponents(data->active_bases[b], data->eval_modes_out[b][e_out], &q_comp_out)); 1429352a5e7cSSebastian Grimberg if (q_comp_out > 1) { 1430352a5e7cSSebastian Grimberg if (e_out == 0 || data->eval_modes_out[b][e_out] != eval_mode_out_prev) d_out = 0; 1431352a5e7cSSebastian Grimberg else B = &B[(++d_out) * num_qpts * num_nodes]; 1432352a5e7cSSebastian Grimberg } 1433352a5e7cSSebastian Grimberg eval_mode_out_prev = data->eval_modes_out[b][e_out]; 1434352a5e7cSSebastian Grimberg B_out[(qq + e_out) * num_nodes + n] = B[q * num_nodes + n]; 1435ed9e99e6SJeremy L Thompson } 1436ed9e99e6SJeremy L Thompson } 1437ed9e99e6SJeremy L Thompson } 1438437c7c90SJeremy L Thompson if (identity) CeedCall(CeedFree(identity)); 1439437c7c90SJeremy L Thompson data->assembled_bases_out[b] = B_out; 1440437c7c90SJeremy L Thompson } 1441ed9e99e6SJeremy L Thompson } 1442ed9e99e6SJeremy L Thompson 1443437c7c90SJeremy L Thompson // Pass out assembled data 1444437c7c90SJeremy L Thompson if (active_bases) *active_bases = data->active_bases; 1445437c7c90SJeremy L Thompson if (assembled_bases_in) *assembled_bases_in = (const CeedScalar **)data->assembled_bases_in; 1446437c7c90SJeremy L Thompson if (assembled_bases_out) *assembled_bases_out = (const CeedScalar **)data->assembled_bases_out; 1447437c7c90SJeremy L Thompson 1448437c7c90SJeremy L Thompson return CEED_ERROR_SUCCESS; 1449437c7c90SJeremy L Thompson } 1450437c7c90SJeremy L Thompson 1451437c7c90SJeremy L Thompson /** 1452ba746a46SJeremy L Thompson @brief Get CeedOperator CeedBasis data for assembly. 1453ba746a46SJeremy L Thompson 1454ba746a46SJeremy L Thompson Note: See CeedOperatorAssemblyDataCreate for a full description of the data stored in this object. 1455437c7c90SJeremy L Thompson 1456437c7c90SJeremy L Thompson @param[in] data CeedOperatorAssemblyData 1457437c7c90SJeremy L Thompson @param[out] num_active_elem_rstrs Number of active element restrictions, or NULL 1458437c7c90SJeremy L Thompson @param[out] active_elem_rstrs Pointer to hold active CeedElemRestrictions, or NULL 1459437c7c90SJeremy L Thompson 1460437c7c90SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1461437c7c90SJeremy L Thompson 1462437c7c90SJeremy L Thompson @ref Backend 1463437c7c90SJeremy L Thompson **/ 1464437c7c90SJeremy L Thompson int CeedOperatorAssemblyDataGetElemRestrictions(CeedOperatorAssemblyData data, CeedInt *num_active_elem_rstrs, 1465437c7c90SJeremy L Thompson CeedElemRestriction **active_elem_rstrs) { 1466437c7c90SJeremy L Thompson if (num_active_elem_rstrs) *num_active_elem_rstrs = data->num_active_bases; 1467437c7c90SJeremy L Thompson if (active_elem_rstrs) *active_elem_rstrs = data->active_elem_rstrs; 1468ed9e99e6SJeremy L Thompson 1469ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1470ed9e99e6SJeremy L Thompson } 1471ed9e99e6SJeremy L Thompson 1472ed9e99e6SJeremy L Thompson /** 1473ed9e99e6SJeremy L Thompson @brief Destroy CeedOperatorAssemblyData 1474ed9e99e6SJeremy L Thompson 1475ea61e9acSJeremy L Thompson @param[in,out] data CeedOperatorAssemblyData to destroy 1476ed9e99e6SJeremy L Thompson 1477ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1478ed9e99e6SJeremy L Thompson 1479ed9e99e6SJeremy L Thompson @ref Backend 1480ed9e99e6SJeremy L Thompson **/ 1481ed9e99e6SJeremy L Thompson int CeedOperatorAssemblyDataDestroy(CeedOperatorAssemblyData *data) { 1482ad6481ceSJeremy L Thompson if (!*data) { 1483ad6481ceSJeremy L Thompson *data = NULL; 1484ad6481ceSJeremy L Thompson return CEED_ERROR_SUCCESS; 1485ad6481ceSJeremy L Thompson } 14862b730f8bSJeremy L Thompson CeedCall(CeedDestroy(&(*data)->ceed)); 1487437c7c90SJeremy L Thompson for (CeedInt b = 0; b < (*data)->num_active_bases; b++) { 1488437c7c90SJeremy L Thompson CeedCall(CeedBasisDestroy(&(*data)->active_bases[b])); 1489437c7c90SJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&(*data)->active_elem_rstrs[b])); 1490437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_modes_in[b])); 1491437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_modes_out[b])); 1492437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_mode_offsets_in[b])); 1493437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_mode_offsets_out[b])); 1494437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->assembled_bases_in[b])); 1495437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->assembled_bases_out[b])); 1496437c7c90SJeremy L Thompson } 1497437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->active_bases)); 1498437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->active_elem_rstrs)); 1499437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->num_eval_modes_in)); 1500437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->num_eval_modes_out)); 1501437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_modes_in)); 1502437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_modes_out)); 1503437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_mode_offsets_in)); 1504437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_mode_offsets_out)); 1505437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->assembled_bases_in)); 1506437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->assembled_bases_out)); 1507ed9e99e6SJeremy L Thompson 15082b730f8bSJeremy L Thompson CeedCall(CeedFree(data)); 1509ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1510ed9e99e6SJeremy L Thompson } 1511ed9e99e6SJeremy L Thompson 1512480fae85SJeremy L Thompson /// @} 1513480fae85SJeremy L Thompson 1514480fae85SJeremy L Thompson /// ---------------------------------------------------------------------------- 1515eaf62fffSJeremy L Thompson /// CeedOperator Public API 1516eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 1517eaf62fffSJeremy L Thompson /// @addtogroup CeedOperatorUser 1518eaf62fffSJeremy L Thompson /// @{ 1519eaf62fffSJeremy L Thompson 1520eaf62fffSJeremy L Thompson /** 1521eaf62fffSJeremy L Thompson @brief Assemble a linear CeedQFunction associated with a CeedOperator 1522eaf62fffSJeremy L Thompson 1523ea61e9acSJeremy L Thompson This returns a CeedVector containing a matrix at each quadrature point providing the action of the CeedQFunction associated with the CeedOperator. 1524859c15bbSJames Wright The vector `assembled` is of shape `[num_elements, num_input_fields, num_output_fields, num_quad_points]` and contains column-major matrices 1525859c15bbSJames Wright representing the action of the CeedQFunction for a corresponding quadrature point on an element. 1526859c15bbSJames Wright 1527*9fd66db6SSebastian Grimberg Inputs and outputs are in the order provided by the user when adding CeedOperator fields. 1528*9fd66db6SSebastian Grimberg For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and 'v', provided in that order, would result in an assembled QFunction 1529*9fd66db6SSebastian Grimberg that consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v]. 1530eaf62fffSJeremy L Thompson 1531ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1532f04ea552SJeremy L Thompson 1533ea61e9acSJeremy L Thompson @param[in] op CeedOperator to assemble CeedQFunction 1534ea61e9acSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedQFunction at quadrature points 1535ea61e9acSJeremy L Thompson @param[out] rstr CeedElemRestriction for CeedVector containing assembled CeedQFunction 1536ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1537eaf62fffSJeremy L Thompson 1538eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1539eaf62fffSJeremy L Thompson 1540eaf62fffSJeremy L Thompson @ref User 1541eaf62fffSJeremy L Thompson **/ 15422b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) { 15432b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1544eaf62fffSJeremy L Thompson 1545eaf62fffSJeremy L Thompson if (op->LinearAssembleQFunction) { 1546d04bbc78SJeremy L Thompson // Backend version 15472b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleQFunction(op, assembled, rstr, request)); 1548eaf62fffSJeremy L Thompson } else { 1549d04bbc78SJeremy L Thompson // Operator fallback 1550d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1551d04bbc78SJeremy L Thompson 15522b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1553d04bbc78SJeremy L Thompson if (op_fallback) { 15542b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleQFunction(op_fallback, assembled, rstr, request)); 1555d04bbc78SJeremy L Thompson } else { 1556d04bbc78SJeremy L Thompson // LCOV_EXCL_START 15572b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedOperatorLinearAssembleQFunction"); 1558d04bbc78SJeremy L Thompson // LCOV_EXCL_STOP 1559d04bbc78SJeremy L Thompson } 156070a7ffb3SJeremy L Thompson } 1561eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1562eaf62fffSJeremy L Thompson } 156370a7ffb3SJeremy L Thompson 156470a7ffb3SJeremy L Thompson /** 1565ea61e9acSJeremy L Thompson @brief Assemble CeedQFunction and store result internally. 15664385fb7fSSebastian Grimberg 1567ea61e9acSJeremy L Thompson Return copied references of stored data to the caller. 1568ea61e9acSJeremy L Thompson Caller is responsible for ownership and destruction of the copied references. 1569ea61e9acSJeremy L Thompson See also @ref CeedOperatorLinearAssembleQFunction 157070a7ffb3SJeremy L Thompson 1571ea61e9acSJeremy L Thompson @param[in] op CeedOperator to assemble CeedQFunction 1572ea61e9acSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedQFunction at quadrature points 1573ea61e9acSJeremy L Thompson @param[out] rstr CeedElemRestriction for CeedVector containing assembledCeedQFunction 1574ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 157570a7ffb3SJeremy L Thompson 157670a7ffb3SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 157770a7ffb3SJeremy L Thompson 157870a7ffb3SJeremy L Thompson @ref User 157970a7ffb3SJeremy L Thompson **/ 15802b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleQFunctionBuildOrUpdate(CeedOperator op, CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) { 15812b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 158270a7ffb3SJeremy L Thompson 158370a7ffb3SJeremy L Thompson if (op->LinearAssembleQFunctionUpdate) { 1584d04bbc78SJeremy L Thompson // Backend version 1585480fae85SJeremy L Thompson bool qf_assembled_is_setup; 15862efa2d85SJeremy L Thompson CeedVector assembled_vec = NULL; 15872efa2d85SJeremy L Thompson CeedElemRestriction assembled_rstr = NULL; 1588480fae85SJeremy L Thompson 15892b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataIsSetup(op->qf_assembled, &qf_assembled_is_setup)); 1590480fae85SJeremy L Thompson if (qf_assembled_is_setup) { 1591d04bbc78SJeremy L Thompson bool update_needed; 1592d04bbc78SJeremy L Thompson 15932b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataGetObjects(op->qf_assembled, &assembled_vec, &assembled_rstr)); 15942b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataIsUpdateNeeded(op->qf_assembled, &update_needed)); 15958b919e6bSJeremy L Thompson if (update_needed) { 15962b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleQFunctionUpdate(op, assembled_vec, assembled_rstr, request)); 15978b919e6bSJeremy L Thompson } 159870a7ffb3SJeremy L Thompson } else { 15992b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleQFunction(op, &assembled_vec, &assembled_rstr, request)); 16002b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataSetObjects(op->qf_assembled, assembled_vec, assembled_rstr)); 160170a7ffb3SJeremy L Thompson } 16022b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, false)); 16032efa2d85SJeremy L Thompson 1604d04bbc78SJeremy L Thompson // Copy reference from internally held copy 160570a7ffb3SJeremy L Thompson *assembled = NULL; 160670a7ffb3SJeremy L Thompson *rstr = NULL; 16072b730f8bSJeremy L Thompson CeedCall(CeedVectorReferenceCopy(assembled_vec, assembled)); 16082b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&assembled_vec)); 16092b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionReferenceCopy(assembled_rstr, rstr)); 16102b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&assembled_rstr)); 161170a7ffb3SJeremy L Thompson } else { 1612d04bbc78SJeremy L Thompson // Operator fallback 1613d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1614d04bbc78SJeremy L Thompson 16152b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1616d04bbc78SJeremy L Thompson if (op_fallback) { 16172b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op_fallback, assembled, rstr, request)); 1618d04bbc78SJeremy L Thompson } else { 1619d04bbc78SJeremy L Thompson // LCOV_EXCL_START 16202b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedOperatorLinearAssembleQFunctionUpdate"); 1621d04bbc78SJeremy L Thompson // LCOV_EXCL_STOP 162270a7ffb3SJeremy L Thompson } 162370a7ffb3SJeremy L Thompson } 162470a7ffb3SJeremy L Thompson 162570a7ffb3SJeremy L Thompson return CEED_ERROR_SUCCESS; 1626eaf62fffSJeremy L Thompson } 1627eaf62fffSJeremy L Thompson 1628eaf62fffSJeremy L Thompson /** 1629eaf62fffSJeremy L Thompson @brief Assemble the diagonal of a square linear CeedOperator 1630eaf62fffSJeremy L Thompson 1631eaf62fffSJeremy L Thompson This overwrites a CeedVector with the diagonal of a linear CeedOperator. 1632eaf62fffSJeremy L Thompson 1633ea61e9acSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and composite CeedOperators with single field sub-operators are supported. 1634eaf62fffSJeremy L Thompson 1635ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1636f04ea552SJeremy L Thompson 1637ea61e9acSJeremy L Thompson @param[in] op CeedOperator to assemble CeedQFunction 1638eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator diagonal 1639ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1640eaf62fffSJeremy L Thompson 1641eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1642eaf62fffSJeremy L Thompson 1643eaf62fffSJeremy L Thompson @ref User 1644eaf62fffSJeremy L Thompson **/ 16452b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled, CeedRequest *request) { 1646f3d47e36SJeremy L Thompson bool is_composite; 16472b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1648f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1649eaf62fffSJeremy L Thompson 1650c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 16512b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 16522b730f8bSJeremy L Thompson if (input_size != output_size) { 1653c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1654c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1655c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 16562b730f8bSJeremy L Thompson } 1657c9366a6bSJeremy L Thompson 1658f3d47e36SJeremy L Thompson // Early exit for empty operator 1659f3d47e36SJeremy L Thompson if (!is_composite) { 1660f3d47e36SJeremy L Thompson CeedInt num_elem = 0; 1661f3d47e36SJeremy L Thompson 1662f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 1663f3d47e36SJeremy L Thompson if (num_elem == 0) return CEED_ERROR_SUCCESS; 1664f3d47e36SJeremy L Thompson } 1665f3d47e36SJeremy L Thompson 1666eaf62fffSJeremy L Thompson if (op->LinearAssembleDiagonal) { 1667d04bbc78SJeremy L Thompson // Backend version 16682b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleDiagonal(op, assembled, request)); 1669eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1670eaf62fffSJeremy L Thompson } else if (op->LinearAssembleAddDiagonal) { 1671d04bbc78SJeremy L Thompson // Backend version with zeroing first 16722b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(assembled, 0.0)); 16732b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleAddDiagonal(op, assembled, request)); 1674eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1675eaf62fffSJeremy L Thompson } else { 1676d04bbc78SJeremy L Thompson // Operator fallback 1677d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1678d04bbc78SJeremy L Thompson 16792b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1680d04bbc78SJeremy L Thompson if (op_fallback) { 16812b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleDiagonal(op_fallback, assembled, request)); 1682eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1683eaf62fffSJeremy L Thompson } 1684eaf62fffSJeremy L Thompson } 1685eaf62fffSJeremy L Thompson // Default interface implementation 16862b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(assembled, 0.0)); 16872b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddDiagonal(op, assembled, request)); 1688d04bbc78SJeremy L Thompson 1689eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1690eaf62fffSJeremy L Thompson } 1691eaf62fffSJeremy L Thompson 1692eaf62fffSJeremy L Thompson /** 1693eaf62fffSJeremy L Thompson @brief Assemble the diagonal of a square linear CeedOperator 1694eaf62fffSJeremy L Thompson 1695eaf62fffSJeremy L Thompson This sums into a CeedVector the diagonal of a linear CeedOperator. 1696eaf62fffSJeremy L Thompson 1697ea61e9acSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and composite CeedOperators with single field sub-operators are supported. 1698eaf62fffSJeremy L Thompson 1699ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1700f04ea552SJeremy L Thompson 1701ea61e9acSJeremy L Thompson @param[in] op CeedOperator to assemble CeedQFunction 1702eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator diagonal 1703ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1704eaf62fffSJeremy L Thompson 1705eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1706eaf62fffSJeremy L Thompson 1707eaf62fffSJeremy L Thompson @ref User 1708eaf62fffSJeremy L Thompson **/ 17092b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled, CeedRequest *request) { 1710f3d47e36SJeremy L Thompson bool is_composite; 17112b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1712f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1713eaf62fffSJeremy L Thompson 1714c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 17152b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 17162b730f8bSJeremy L Thompson if (input_size != output_size) { 1717c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1718c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1719c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 17202b730f8bSJeremy L Thompson } 1721c9366a6bSJeremy L Thompson 1722f3d47e36SJeremy L Thompson // Early exit for empty operator 1723f3d47e36SJeremy L Thompson if (!is_composite) { 1724f3d47e36SJeremy L Thompson CeedInt num_elem = 0; 1725f3d47e36SJeremy L Thompson 1726f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 1727f3d47e36SJeremy L Thompson if (num_elem == 0) return CEED_ERROR_SUCCESS; 1728f3d47e36SJeremy L Thompson } 1729f3d47e36SJeremy L Thompson 1730eaf62fffSJeremy L Thompson if (op->LinearAssembleAddDiagonal) { 1731d04bbc78SJeremy L Thompson // Backend version 17322b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleAddDiagonal(op, assembled, request)); 1733eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1734eaf62fffSJeremy L Thompson } else { 1735d04bbc78SJeremy L Thompson // Operator fallback 1736d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1737d04bbc78SJeremy L Thompson 17382b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1739d04bbc78SJeremy L Thompson if (op_fallback) { 17402b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddDiagonal(op_fallback, assembled, request)); 1741eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1742eaf62fffSJeremy L Thompson } 1743eaf62fffSJeremy L Thompson } 1744eaf62fffSJeremy L Thompson // Default interface implementation 1745eaf62fffSJeremy L Thompson if (is_composite) { 17462b730f8bSJeremy L Thompson CeedCall(CeedCompositeOperatorLinearAssembleAddDiagonal(op, request, false, assembled)); 1747eaf62fffSJeremy L Thompson } else { 17482b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssembleAddDiagonal_Core(op, request, false, assembled)); 1749eaf62fffSJeremy L Thompson } 1750d04bbc78SJeremy L Thompson 1751d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 1752eaf62fffSJeremy L Thompson } 1753eaf62fffSJeremy L Thompson 1754eaf62fffSJeremy L Thompson /** 1755eaf62fffSJeremy L Thompson @brief Assemble the point block diagonal of a square linear CeedOperator 1756eaf62fffSJeremy L Thompson 1757ea61e9acSJeremy L Thompson This overwrites a CeedVector with the point block diagonal of a linear CeedOperator. 1758eaf62fffSJeremy L Thompson 1759ea61e9acSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and composite CeedOperators with single field sub-operators are supported. 1760eaf62fffSJeremy L Thompson 1761ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1762f04ea552SJeremy L Thompson 1763ea61e9acSJeremy L Thompson @param[in] op CeedOperator to assemble CeedQFunction 1764ea61e9acSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator point block diagonal, provided in row-major form with an @a num_comp * @a num_comp 1765ea61e9acSJeremy L Thompson block at each node. The dimensions of this vector are derived from the active vector for the CeedOperator. The array has shape [nodes, component out, 1766ea61e9acSJeremy L Thompson component in]. 1767ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1768eaf62fffSJeremy L Thompson 1769eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1770eaf62fffSJeremy L Thompson 1771eaf62fffSJeremy L Thompson @ref User 1772eaf62fffSJeremy L Thompson **/ 17732b730f8bSJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op, CeedVector assembled, CeedRequest *request) { 1774f3d47e36SJeremy L Thompson bool is_composite; 17752b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1776f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1777eaf62fffSJeremy L Thompson 1778c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 17792b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 17802b730f8bSJeremy L Thompson if (input_size != output_size) { 1781c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1782c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1783c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 17842b730f8bSJeremy L Thompson } 1785c9366a6bSJeremy L Thompson 1786f3d47e36SJeremy L Thompson // Early exit for empty operator 1787f3d47e36SJeremy L Thompson if (!is_composite) { 1788f3d47e36SJeremy L Thompson CeedInt num_elem = 0; 1789f3d47e36SJeremy L Thompson 1790f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 1791f3d47e36SJeremy L Thompson if (num_elem == 0) return CEED_ERROR_SUCCESS; 1792f3d47e36SJeremy L Thompson } 1793f3d47e36SJeremy L Thompson 1794eaf62fffSJeremy L Thompson if (op->LinearAssemblePointBlockDiagonal) { 1795d04bbc78SJeremy L Thompson // Backend version 17962b730f8bSJeremy L Thompson CeedCall(op->LinearAssemblePointBlockDiagonal(op, assembled, request)); 1797eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1798eaf62fffSJeremy L Thompson } else if (op->LinearAssembleAddPointBlockDiagonal) { 1799d04bbc78SJeremy L Thompson // Backend version with zeroing first 18002b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(assembled, 0.0)); 18012b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, request)); 1802eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1803eaf62fffSJeremy L Thompson } else { 1804d04bbc78SJeremy L Thompson // Operator fallback 1805d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1806d04bbc78SJeremy L Thompson 18072b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1808d04bbc78SJeremy L Thompson if (op_fallback) { 18092b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssemblePointBlockDiagonal(op_fallback, assembled, request)); 1810eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1811eaf62fffSJeremy L Thompson } 1812eaf62fffSJeremy L Thompson } 1813eaf62fffSJeremy L Thompson // Default interface implementation 18142b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(assembled, 0.0)); 18152b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, request)); 1816d04bbc78SJeremy L Thompson 1817eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1818eaf62fffSJeremy L Thompson } 1819eaf62fffSJeremy L Thompson 1820eaf62fffSJeremy L Thompson /** 1821eaf62fffSJeremy L Thompson @brief Assemble the point block diagonal of a square linear CeedOperator 1822eaf62fffSJeremy L Thompson 1823ea61e9acSJeremy L Thompson This sums into a CeedVector with the point block diagonal of a linear CeedOperator. 1824eaf62fffSJeremy L Thompson 1825ea61e9acSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and composite CeedOperators with single field sub-operators are supported. 1826eaf62fffSJeremy L Thompson 1827ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1828f04ea552SJeremy L Thompson 1829ea61e9acSJeremy L Thompson @param[in] op CeedOperator to assemble CeedQFunction 1830ea61e9acSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator point block diagonal, provided in row-major form with an @a num_comp * @a num_comp 1831ea61e9acSJeremy L Thompson block at each node. The dimensions of this vector are derived from the active vector for the CeedOperator. The array has shape [nodes, component out, 1832ea61e9acSJeremy L Thompson component in]. 1833ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1834eaf62fffSJeremy L Thompson 1835eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1836eaf62fffSJeremy L Thompson 1837eaf62fffSJeremy L Thompson @ref User 1838eaf62fffSJeremy L Thompson **/ 18392b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op, CeedVector assembled, CeedRequest *request) { 1840f3d47e36SJeremy L Thompson bool is_composite; 18412b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1842f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1843eaf62fffSJeremy L Thompson 1844c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 18452b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 18462b730f8bSJeremy L Thompson if (input_size != output_size) { 1847c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1848c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1849c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 18502b730f8bSJeremy L Thompson } 1851c9366a6bSJeremy L Thompson 1852f3d47e36SJeremy L Thompson // Early exit for empty operator 1853f3d47e36SJeremy L Thompson if (!is_composite) { 1854f3d47e36SJeremy L Thompson CeedInt num_elem = 0; 1855f3d47e36SJeremy L Thompson 1856f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 1857f3d47e36SJeremy L Thompson if (num_elem == 0) return CEED_ERROR_SUCCESS; 1858f3d47e36SJeremy L Thompson } 1859f3d47e36SJeremy L Thompson 1860eaf62fffSJeremy L Thompson if (op->LinearAssembleAddPointBlockDiagonal) { 1861d04bbc78SJeremy L Thompson // Backend version 18622b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleAddPointBlockDiagonal(op, assembled, request)); 1863eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1864eaf62fffSJeremy L Thompson } else { 1865d04bbc78SJeremy L Thompson // Operator fallback 1866d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1867d04bbc78SJeremy L Thompson 18682b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1869d04bbc78SJeremy L Thompson if (op_fallback) { 18702b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddPointBlockDiagonal(op_fallback, assembled, request)); 1871eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1872eaf62fffSJeremy L Thompson } 1873eaf62fffSJeremy L Thompson } 1874ea61e9acSJeremy L Thompson // Default interface implementation 1875eaf62fffSJeremy L Thompson if (is_composite) { 18762b730f8bSJeremy L Thompson CeedCall(CeedCompositeOperatorLinearAssembleAddDiagonal(op, request, true, assembled)); 1877eaf62fffSJeremy L Thompson } else { 18782b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssembleAddDiagonal_Core(op, request, true, assembled)); 1879eaf62fffSJeremy L Thompson } 1880d04bbc78SJeremy L Thompson 1881d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 1882eaf62fffSJeremy L Thompson } 1883eaf62fffSJeremy L Thompson 1884eaf62fffSJeremy L Thompson /** 1885eaf62fffSJeremy L Thompson @brief Fully assemble the nonzero pattern of a linear operator. 1886eaf62fffSJeremy L Thompson 1887ea61e9acSJeremy L Thompson Expected to be used in conjunction with CeedOperatorLinearAssemble(). 1888eaf62fffSJeremy L Thompson 1889ea61e9acSJeremy L Thompson The assembly routines use coordinate format, with num_entries tuples of the form (i, j, value) which indicate that value should be added to the 1890*9fd66db6SSebastian Grimberg matrix in entry (i, j). 1891*9fd66db6SSebastian Grimberg Note that the (i, j) pairs are not unique and may repeat. 1892*9fd66db6SSebastian Grimberg This function returns the number of entries and their (i, j) locations, while CeedOperatorLinearAssemble() provides the values in the same ordering. 1893eaf62fffSJeremy L Thompson 1894eaf62fffSJeremy L Thompson This will generally be slow unless your operator is low-order. 1895eaf62fffSJeremy L Thompson 1896ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1897f04ea552SJeremy L Thompson 1898eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 1899eaf62fffSJeremy L Thompson @param[out] num_entries Number of entries in coordinate nonzero pattern 1900eaf62fffSJeremy L Thompson @param[out] rows Row number for each entry 1901eaf62fffSJeremy L Thompson @param[out] cols Column number for each entry 1902eaf62fffSJeremy L Thompson 1903eaf62fffSJeremy L Thompson @ref User 1904eaf62fffSJeremy L Thompson **/ 19052b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleSymbolic(CeedOperator op, CeedSize *num_entries, CeedInt **rows, CeedInt **cols) { 1906eaf62fffSJeremy L Thompson CeedInt num_suboperators, single_entries; 1907eaf62fffSJeremy L Thompson CeedOperator *sub_operators; 1908eaf62fffSJeremy L Thompson bool is_composite; 19092b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1910f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1911eaf62fffSJeremy L Thompson 1912eaf62fffSJeremy L Thompson if (op->LinearAssembleSymbolic) { 1913d04bbc78SJeremy L Thompson // Backend version 19142b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleSymbolic(op, num_entries, rows, cols)); 1915eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1916eaf62fffSJeremy L Thompson } else { 1917d04bbc78SJeremy L Thompson // Operator fallback 1918d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1919d04bbc78SJeremy L Thompson 19202b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1921d04bbc78SJeremy L Thompson if (op_fallback) { 19222b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleSymbolic(op_fallback, num_entries, rows, cols)); 1923eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1924eaf62fffSJeremy L Thompson } 1925eaf62fffSJeremy L Thompson } 1926eaf62fffSJeremy L Thompson 1927eaf62fffSJeremy L Thompson // Default interface implementation 1928eaf62fffSJeremy L Thompson 1929eaf62fffSJeremy L Thompson // count entries and allocate rows, cols arrays 1930eaf62fffSJeremy L Thompson *num_entries = 0; 1931eaf62fffSJeremy L Thompson if (is_composite) { 1932c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1933c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 193492ae7e47SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; ++k) { 19352b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemblyCountEntries(sub_operators[k], &single_entries)); 1936eaf62fffSJeremy L Thompson *num_entries += single_entries; 1937eaf62fffSJeremy L Thompson } 1938eaf62fffSJeremy L Thompson } else { 19392b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemblyCountEntries(op, &single_entries)); 1940eaf62fffSJeremy L Thompson *num_entries += single_entries; 1941eaf62fffSJeremy L Thompson } 19422b730f8bSJeremy L Thompson CeedCall(CeedCalloc(*num_entries, rows)); 19432b730f8bSJeremy L Thompson CeedCall(CeedCalloc(*num_entries, cols)); 1944eaf62fffSJeremy L Thompson 1945eaf62fffSJeremy L Thompson // assemble nonzero locations 1946eaf62fffSJeremy L Thompson CeedInt offset = 0; 1947eaf62fffSJeremy L Thompson if (is_composite) { 1948c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1949c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 195092ae7e47SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; ++k) { 19512b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssembleSymbolic(sub_operators[k], offset, *rows, *cols)); 19522b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemblyCountEntries(sub_operators[k], &single_entries)); 1953eaf62fffSJeremy L Thompson offset += single_entries; 1954eaf62fffSJeremy L Thompson } 1955eaf62fffSJeremy L Thompson } else { 19562b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssembleSymbolic(op, offset, *rows, *cols)); 1957eaf62fffSJeremy L Thompson } 1958eaf62fffSJeremy L Thompson 1959eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1960eaf62fffSJeremy L Thompson } 1961eaf62fffSJeremy L Thompson 1962eaf62fffSJeremy L Thompson /** 1963eaf62fffSJeremy L Thompson @brief Fully assemble the nonzero entries of a linear operator. 1964eaf62fffSJeremy L Thompson 1965ea61e9acSJeremy L Thompson Expected to be used in conjunction with CeedOperatorLinearAssembleSymbolic(). 1966eaf62fffSJeremy L Thompson 1967ea61e9acSJeremy L Thompson The assembly routines use coordinate format, with num_entries tuples of the form (i, j, value) which indicate that value should be added to the 1968*9fd66db6SSebastian Grimberg matrix in entry (i, j). 1969*9fd66db6SSebastian Grimberg Note that the (i, j) pairs are not unique and may repeat. 1970*9fd66db6SSebastian Grimberg This function returns the values of the nonzero entries to be added, their (i, j) locations are provided by CeedOperatorLinearAssembleSymbolic() 1971eaf62fffSJeremy L Thompson 1972eaf62fffSJeremy L Thompson This will generally be slow unless your operator is low-order. 1973eaf62fffSJeremy L Thompson 1974ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1975f04ea552SJeremy L Thompson 1976eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 1977eaf62fffSJeremy L Thompson @param[out] values Values to assemble into matrix 1978eaf62fffSJeremy L Thompson 1979eaf62fffSJeremy L Thompson @ref User 1980eaf62fffSJeremy L Thompson **/ 1981eaf62fffSJeremy L Thompson int CeedOperatorLinearAssemble(CeedOperator op, CeedVector values) { 1982eaf62fffSJeremy L Thompson CeedInt num_suboperators, single_entries = 0; 1983eaf62fffSJeremy L Thompson CeedOperator *sub_operators; 1984f3d47e36SJeremy L Thompson bool is_composite; 19852b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1986f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1987f3d47e36SJeremy L Thompson 1988f3d47e36SJeremy L Thompson // Early exit for empty operator 1989f3d47e36SJeremy L Thompson if (!is_composite) { 1990f3d47e36SJeremy L Thompson CeedInt num_elem = 0; 1991f3d47e36SJeremy L Thompson 1992f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 1993f3d47e36SJeremy L Thompson if (num_elem == 0) return CEED_ERROR_SUCCESS; 1994f3d47e36SJeremy L Thompson } 1995eaf62fffSJeremy L Thompson 1996eaf62fffSJeremy L Thompson if (op->LinearAssemble) { 1997d04bbc78SJeremy L Thompson // Backend version 19982b730f8bSJeremy L Thompson CeedCall(op->LinearAssemble(op, values)); 1999eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2000eaf62fffSJeremy L Thompson } else { 2001d04bbc78SJeremy L Thompson // Operator fallback 2002d04bbc78SJeremy L Thompson CeedOperator op_fallback; 2003d04bbc78SJeremy L Thompson 20042b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 2005d04bbc78SJeremy L Thompson if (op_fallback) { 20062b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssemble(op_fallback, values)); 2007eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2008eaf62fffSJeremy L Thompson } 2009eaf62fffSJeremy L Thompson } 2010eaf62fffSJeremy L Thompson 2011eaf62fffSJeremy L Thompson // Default interface implementation 2012eaf62fffSJeremy L Thompson CeedInt offset = 0; 201328ec399dSJeremy L Thompson CeedCall(CeedVectorSetValue(values, 0.0)); 2014eaf62fffSJeremy L Thompson if (is_composite) { 2015c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 2016c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 2017cefa2673SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; k++) { 20182b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemble(sub_operators[k], offset, values)); 20192b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemblyCountEntries(sub_operators[k], &single_entries)); 2020eaf62fffSJeremy L Thompson offset += single_entries; 2021eaf62fffSJeremy L Thompson } 2022eaf62fffSJeremy L Thompson } else { 20232b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemble(op, offset, values)); 2024eaf62fffSJeremy L Thompson } 2025eaf62fffSJeremy L Thompson 2026eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2027eaf62fffSJeremy L Thompson } 2028eaf62fffSJeremy L Thompson 2029eaf62fffSJeremy L Thompson /** 203075f0d5a4SJeremy L Thompson @brief Get the multiplicity of nodes across suboperators in a composite CeedOperator 203175f0d5a4SJeremy L Thompson 203275f0d5a4SJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 203375f0d5a4SJeremy L Thompson 203475f0d5a4SJeremy L Thompson @param[in] op Composite CeedOperator 203575f0d5a4SJeremy L Thompson @param[in] num_skip_indices Number of suboperators to skip 203675f0d5a4SJeremy L Thompson @param[in] skip_indices Array of indices of suboperators to skip 203775f0d5a4SJeremy L Thompson @param[out] mult Vector to store multiplicity (of size l_size) 203875f0d5a4SJeremy L Thompson 203975f0d5a4SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 204075f0d5a4SJeremy L Thompson 204175f0d5a4SJeremy L Thompson @ref User 204275f0d5a4SJeremy L Thompson **/ 204375f0d5a4SJeremy L Thompson int CeedCompositeOperatorGetMultiplicity(CeedOperator op, CeedInt num_skip_indices, CeedInt *skip_indices, CeedVector mult) { 204475f0d5a4SJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 204575f0d5a4SJeremy L Thompson 204675f0d5a4SJeremy L Thompson Ceed ceed; 2047b275c451SJeremy L Thompson CeedInt num_suboperators; 204875f0d5a4SJeremy L Thompson CeedSize l_vec_len; 204975f0d5a4SJeremy L Thompson CeedScalar *mult_array; 205075f0d5a4SJeremy L Thompson CeedVector ones_l_vec; 2051437c7c90SJeremy L Thompson CeedElemRestriction elem_rstr; 2052b275c451SJeremy L Thompson CeedOperator *sub_operators; 205375f0d5a4SJeremy L Thompson 205475f0d5a4SJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 205575f0d5a4SJeremy L Thompson 205675f0d5a4SJeremy L Thompson // Zero mult vector 205775f0d5a4SJeremy L Thompson CeedCall(CeedVectorSetValue(mult, 0.0)); 205875f0d5a4SJeremy L Thompson 205975f0d5a4SJeremy L Thompson // Get suboperators 2060b275c451SJeremy L Thompson CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 2061b275c451SJeremy L Thompson CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 2062b275c451SJeremy L Thompson if (num_suboperators == 0) return CEED_ERROR_SUCCESS; 206375f0d5a4SJeremy L Thompson 206475f0d5a4SJeremy L Thompson // Work vector 206575f0d5a4SJeremy L Thompson CeedCall(CeedVectorGetLength(mult, &l_vec_len)); 206675f0d5a4SJeremy L Thompson CeedCall(CeedVectorCreate(ceed, l_vec_len, &ones_l_vec)); 206775f0d5a4SJeremy L Thompson CeedCall(CeedVectorSetValue(ones_l_vec, 1.0)); 206875f0d5a4SJeremy L Thompson CeedCall(CeedVectorGetArray(mult, CEED_MEM_HOST, &mult_array)); 206975f0d5a4SJeremy L Thompson 207075f0d5a4SJeremy L Thompson // Compute multiplicity across suboperators 2071b275c451SJeremy L Thompson for (CeedInt i = 0; i < num_suboperators; i++) { 207275f0d5a4SJeremy L Thompson const CeedScalar *sub_mult_array; 207375f0d5a4SJeremy L Thompson CeedVector sub_mult_l_vec, ones_e_vec; 207475f0d5a4SJeremy L Thompson 207575f0d5a4SJeremy L Thompson // -- Check for suboperator to skip 207675f0d5a4SJeremy L Thompson for (CeedInt j = 0; j < num_skip_indices; j++) { 207775f0d5a4SJeremy L Thompson if (skip_indices[j] == i) continue; 207875f0d5a4SJeremy L Thompson } 207975f0d5a4SJeremy L Thompson 208075f0d5a4SJeremy L Thompson // -- Sub operator multiplicity 2081437c7c90SJeremy L Thompson CeedCall(CeedOperatorGetActiveElemRestriction(sub_operators[i], &elem_rstr)); 2082437c7c90SJeremy L Thompson CeedCall(CeedElemRestrictionCreateVector(elem_rstr, &sub_mult_l_vec, &ones_e_vec)); 208375f0d5a4SJeremy L Thompson CeedCall(CeedVectorSetValue(sub_mult_l_vec, 0.0)); 2084437c7c90SJeremy L Thompson CeedCall(CeedElemRestrictionApply(elem_rstr, CEED_NOTRANSPOSE, ones_l_vec, ones_e_vec, CEED_REQUEST_IMMEDIATE)); 2085437c7c90SJeremy L Thompson CeedCall(CeedElemRestrictionApply(elem_rstr, CEED_TRANSPOSE, ones_e_vec, sub_mult_l_vec, CEED_REQUEST_IMMEDIATE)); 208675f0d5a4SJeremy L Thompson CeedCall(CeedVectorGetArrayRead(sub_mult_l_vec, CEED_MEM_HOST, &sub_mult_array)); 208775f0d5a4SJeremy L Thompson // ---- Flag every node present in the current suboperator 208875f0d5a4SJeremy L Thompson for (CeedInt j = 0; j < l_vec_len; j++) { 208975f0d5a4SJeremy L Thompson if (sub_mult_array[j] > 0.0) mult_array[j] += 1.0; 209075f0d5a4SJeremy L Thompson } 209175f0d5a4SJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(sub_mult_l_vec, &sub_mult_array)); 209275f0d5a4SJeremy L Thompson CeedCall(CeedVectorDestroy(&sub_mult_l_vec)); 209375f0d5a4SJeremy L Thompson CeedCall(CeedVectorDestroy(&ones_e_vec)); 209475f0d5a4SJeremy L Thompson } 209575f0d5a4SJeremy L Thompson CeedCall(CeedVectorRestoreArray(mult, &mult_array)); 2096811d0ccfSJeremy L Thompson CeedCall(CeedVectorDestroy(&ones_l_vec)); 209775f0d5a4SJeremy L Thompson 209875f0d5a4SJeremy L Thompson return CEED_ERROR_SUCCESS; 209975f0d5a4SJeremy L Thompson } 210075f0d5a4SJeremy L Thompson 210175f0d5a4SJeremy L Thompson /** 2102ea61e9acSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators for a CeedOperator, creating the prolongation basis from the fine and coarse 2103ea61e9acSJeremy L Thompson grid interpolation 2104eaf62fffSJeremy L Thompson 210558e4b056SJeremy L Thompson Note: Calling this function asserts that setup is complete and sets all four CeedOperators as immutable. 2106f04ea552SJeremy L Thompson 2107eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 210885bb9dcfSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter, or NULL if not creating prolongation/restriction operators 2109eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 2110eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 2111eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 211285bb9dcfSJeremy L Thompson @param[out] op_prolong Coarse to fine operator, or NULL 211385bb9dcfSJeremy L Thompson @param[out] op_restrict Fine to coarse operator, or NULL 2114eaf62fffSJeremy L Thompson 2115eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2116eaf62fffSJeremy L Thompson 2117eaf62fffSJeremy L Thompson @ref User 2118eaf62fffSJeremy L Thompson **/ 21192b730f8bSJeremy L Thompson int CeedOperatorMultigridLevelCreate(CeedOperator op_fine, CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 21202b730f8bSJeremy L Thompson CeedOperator *op_coarse, CeedOperator *op_prolong, CeedOperator *op_restrict) { 21212b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op_fine)); 2122eaf62fffSJeremy L Thompson 212383d6adf3SZach Atkins // Build prolongation matrix, if required 212483d6adf3SZach Atkins CeedBasis basis_c_to_f = NULL; 212583d6adf3SZach Atkins if (op_prolong || op_restrict) { 212683d6adf3SZach Atkins CeedBasis basis_fine; 21272b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveBasis(op_fine, &basis_fine)); 21282b730f8bSJeremy L Thompson CeedCall(CeedBasisCreateProjection(basis_coarse, basis_fine, &basis_c_to_f)); 212983d6adf3SZach Atkins } 2130eaf62fffSJeremy L Thompson 2131f113e5dcSJeremy L Thompson // Core code 21322b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, basis_coarse, basis_c_to_f, op_coarse, op_prolong, op_restrict)); 2133f113e5dcSJeremy L Thompson 2134eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2135eaf62fffSJeremy L Thompson } 2136eaf62fffSJeremy L Thompson 2137eaf62fffSJeremy L Thompson /** 2138ea61e9acSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators for a CeedOperator with a tensor basis for the active basis 2139eaf62fffSJeremy L Thompson 214058e4b056SJeremy L Thompson Note: Calling this function asserts that setup is complete and sets all four CeedOperators as immutable. 2141f04ea552SJeremy L Thompson 2142eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 214385bb9dcfSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter, or NULL if not creating prolongation/restriction operators 2144eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 2145eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 214685bb9dcfSJeremy L Thompson @param[in] interp_c_to_f Matrix for coarse to fine interpolation, or NULL if not creating prolongation/restriction operators 2147eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 214885bb9dcfSJeremy L Thompson @param[out] op_prolong Coarse to fine operator, or NULL 214985bb9dcfSJeremy L Thompson @param[out] op_restrict Fine to coarse operator, or NULL 2150eaf62fffSJeremy L Thompson 2151eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2152eaf62fffSJeremy L Thompson 2153eaf62fffSJeremy L Thompson @ref User 2154eaf62fffSJeremy L Thompson **/ 21552b730f8bSJeremy L Thompson int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator op_fine, CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 21562b730f8bSJeremy L Thompson const CeedScalar *interp_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong, 21572b730f8bSJeremy L Thompson CeedOperator *op_restrict) { 21582b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op_fine)); 2159eaf62fffSJeremy L Thompson Ceed ceed; 21602b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op_fine, &ceed)); 2161eaf62fffSJeremy L Thompson 2162eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 2163eaf62fffSJeremy L Thompson CeedBasis basis_fine; 21642b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveBasis(op_fine, &basis_fine)); 2165eaf62fffSJeremy L Thompson CeedInt Q_f, Q_c; 21662b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f)); 21672b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c)); 21682b730f8bSJeremy L Thompson if (Q_f != Q_c) { 2169eaf62fffSJeremy L Thompson // LCOV_EXCL_START 21702b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, "Bases must have compatible quadrature spaces"); 2171eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 21722b730f8bSJeremy L Thompson } 2173eaf62fffSJeremy L Thompson 217483d6adf3SZach Atkins // Create coarse to fine basis, if required 217583d6adf3SZach Atkins CeedBasis basis_c_to_f = NULL; 217683d6adf3SZach Atkins if (op_prolong || op_restrict) { 217783d6adf3SZach Atkins // Check if interpolation matrix is provided 217883d6adf3SZach Atkins if (!interp_c_to_f) { 217983d6adf3SZach Atkins // LCOV_EXCL_START 218083d6adf3SZach Atkins return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, "Prolongation or restriction operator creation requires coarse-to-fine interpolation matrix"); 218183d6adf3SZach Atkins // LCOV_EXCL_STOP 218283d6adf3SZach Atkins } 2183eaf62fffSJeremy L Thompson CeedInt dim, num_comp, num_nodes_c, P_1d_f, P_1d_c; 21842b730f8bSJeremy L Thompson CeedCall(CeedBasisGetDimension(basis_fine, &dim)); 21852b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumComponents(basis_fine, &num_comp)); 21862b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumNodes1D(basis_fine, &P_1d_f)); 21872b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c)); 21882b730f8bSJeremy L Thompson P_1d_c = dim == 1 ? num_nodes_c : dim == 2 ? sqrt(num_nodes_c) : cbrt(num_nodes_c); 2189eaf62fffSJeremy L Thompson CeedScalar *q_ref, *q_weight, *grad; 21902b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d_f, &q_ref)); 21912b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d_f, &q_weight)); 21922b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d_f * P_1d_c * dim, &grad)); 21932b730f8bSJeremy L Thompson CeedCall(CeedBasisCreateTensorH1(ceed, dim, num_comp, P_1d_c, P_1d_f, interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f)); 21942b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_ref)); 21952b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_weight)); 21962b730f8bSJeremy L Thompson CeedCall(CeedFree(&grad)); 219783d6adf3SZach Atkins } 2198eaf62fffSJeremy L Thompson 2199eaf62fffSJeremy L Thompson // Core code 22002b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, basis_coarse, basis_c_to_f, op_coarse, op_prolong, op_restrict)); 2201eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2202eaf62fffSJeremy L Thompson } 2203eaf62fffSJeremy L Thompson 2204eaf62fffSJeremy L Thompson /** 2205ea61e9acSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators for a CeedOperator with a non-tensor basis for the active vector 2206eaf62fffSJeremy L Thompson 220758e4b056SJeremy L Thompson Note: Calling this function asserts that setup is complete and sets all four CeedOperators as immutable. 2208f04ea552SJeremy L Thompson 2209eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 221085bb9dcfSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter, or NULL if not creating prolongation/restriction operators 2211eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 2212eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 221385bb9dcfSJeremy L Thompson @param[in] interp_c_to_f Matrix for coarse to fine interpolation, or NULL if not creating prolongation/restriction operators 2214eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 221585bb9dcfSJeremy L Thompson @param[out] op_prolong Coarse to fine operator, or NULL 221685bb9dcfSJeremy L Thompson @param[out] op_restrict Fine to coarse operator, or NULL 2217eaf62fffSJeremy L Thompson 2218eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2219eaf62fffSJeremy L Thompson 2220eaf62fffSJeremy L Thompson @ref User 2221eaf62fffSJeremy L Thompson **/ 22222b730f8bSJeremy L Thompson int CeedOperatorMultigridLevelCreateH1(CeedOperator op_fine, CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 22232b730f8bSJeremy L Thompson const CeedScalar *interp_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong, 2224eaf62fffSJeremy L Thompson CeedOperator *op_restrict) { 22252b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op_fine)); 2226eaf62fffSJeremy L Thompson Ceed ceed; 22272b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op_fine, &ceed)); 2228eaf62fffSJeremy L Thompson 2229eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 2230eaf62fffSJeremy L Thompson CeedBasis basis_fine; 22312b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveBasis(op_fine, &basis_fine)); 2232eaf62fffSJeremy L Thompson CeedInt Q_f, Q_c; 22332b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f)); 22342b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c)); 22352b730f8bSJeremy L Thompson if (Q_f != Q_c) { 2236eaf62fffSJeremy L Thompson // LCOV_EXCL_START 22372b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, "Bases must have compatible quadrature spaces"); 2238eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 22392b730f8bSJeremy L Thompson } 2240eaf62fffSJeremy L Thompson 2241eaf62fffSJeremy L Thompson // Coarse to fine basis 224283d6adf3SZach Atkins CeedBasis basis_c_to_f = NULL; 224383d6adf3SZach Atkins if (op_prolong || op_restrict) { 224483d6adf3SZach Atkins // Check if interpolation matrix is provided 224583d6adf3SZach Atkins if (!interp_c_to_f) { 224683d6adf3SZach Atkins // LCOV_EXCL_START 224783d6adf3SZach Atkins return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, "Prolongation or restriction operator creation requires coarse-to-fine interpolation matrix"); 224883d6adf3SZach Atkins // LCOV_EXCL_STOP 224983d6adf3SZach Atkins } 2250eaf62fffSJeremy L Thompson CeedElemTopology topo; 22512b730f8bSJeremy L Thompson CeedCall(CeedBasisGetTopology(basis_fine, &topo)); 2252eaf62fffSJeremy L Thompson CeedInt dim, num_comp, num_nodes_c, num_nodes_f; 22532b730f8bSJeremy L Thompson CeedCall(CeedBasisGetDimension(basis_fine, &dim)); 22542b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumComponents(basis_fine, &num_comp)); 22552b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumNodes(basis_fine, &num_nodes_f)); 22562b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c)); 2257eaf62fffSJeremy L Thompson CeedScalar *q_ref, *q_weight, *grad; 22582b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_nodes_f * dim, &q_ref)); 22592b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_nodes_f, &q_weight)); 22602b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_nodes_f * num_nodes_c * dim, &grad)); 22612b730f8bSJeremy L Thompson CeedCall(CeedBasisCreateH1(ceed, topo, num_comp, num_nodes_c, num_nodes_f, interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f)); 22622b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_ref)); 22632b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_weight)); 22642b730f8bSJeremy L Thompson CeedCall(CeedFree(&grad)); 226583d6adf3SZach Atkins } 2266eaf62fffSJeremy L Thompson 2267eaf62fffSJeremy L Thompson // Core code 22682b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, basis_coarse, basis_c_to_f, op_coarse, op_prolong, op_restrict)); 2269eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2270eaf62fffSJeremy L Thompson } 2271eaf62fffSJeremy L Thompson 2272eaf62fffSJeremy L Thompson /** 2273ea61e9acSJeremy L Thompson @brief Build a FDM based approximate inverse for each element for a CeedOperator 2274eaf62fffSJeremy L Thompson 2275ea61e9acSJeremy L Thompson This returns a CeedOperator and CeedVector to apply a Fast Diagonalization Method based approximate inverse. 2276859c15bbSJames Wright This function obtains the simultaneous diagonalization for the 1D mass and Laplacian operators, \f$M = V^T V, K = V^T S V\f$. 2277859c15bbSJames Wright The assembled QFunction is used to modify the eigenvalues from simultaneous diagonalization and obtain an approximate inverse of the form \f$V^T 2278*9fd66db6SSebastian Grimberg \hat S V\f$. 2279*9fd66db6SSebastian Grimberg The CeedOperator must be linear and non-composite. 2280*9fd66db6SSebastian Grimberg The associated CeedQFunction must therefore also be linear. 2281eaf62fffSJeremy L Thompson 2282ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 2283f04ea552SJeremy L Thompson 2284ea61e9acSJeremy L Thompson @param[in] op CeedOperator to create element inverses 2285ea61e9acSJeremy L Thompson @param[out] fdm_inv CeedOperator to apply the action of a FDM based inverse for each element 2286ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 2287eaf62fffSJeremy L Thompson 2288eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2289eaf62fffSJeremy L Thompson 2290480fae85SJeremy L Thompson @ref User 2291eaf62fffSJeremy L Thompson **/ 22922b730f8bSJeremy L Thompson int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdm_inv, CeedRequest *request) { 22932b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 2294eaf62fffSJeremy L Thompson 2295eaf62fffSJeremy L Thompson if (op->CreateFDMElementInverse) { 2296d04bbc78SJeremy L Thompson // Backend version 22972b730f8bSJeremy L Thompson CeedCall(op->CreateFDMElementInverse(op, fdm_inv, request)); 2298eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2299eaf62fffSJeremy L Thompson } else { 2300d04bbc78SJeremy L Thompson // Operator fallback 2301d04bbc78SJeremy L Thompson CeedOperator op_fallback; 2302d04bbc78SJeremy L Thompson 23032b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 2304d04bbc78SJeremy L Thompson if (op_fallback) { 23052b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreateFDMElementInverse(op_fallback, fdm_inv, request)); 2306eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2307eaf62fffSJeremy L Thompson } 2308eaf62fffSJeremy L Thompson } 2309eaf62fffSJeremy L Thompson 2310d04bbc78SJeremy L Thompson // Default interface implementation 2311eaf62fffSJeremy L Thompson Ceed ceed, ceed_parent; 23122b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 23132b730f8bSJeremy L Thompson CeedCall(CeedGetOperatorFallbackParentCeed(ceed, &ceed_parent)); 2314eaf62fffSJeremy L Thompson ceed_parent = ceed_parent ? ceed_parent : ceed; 2315eaf62fffSJeremy L Thompson CeedQFunction qf; 23162b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetQFunction(op, &qf)); 2317eaf62fffSJeremy L Thompson 2318eaf62fffSJeremy L Thompson // Determine active input basis 2319eaf62fffSJeremy L Thompson bool interp = false, grad = false; 2320eaf62fffSJeremy L Thompson CeedBasis basis = NULL; 2321eaf62fffSJeremy L Thompson CeedElemRestriction rstr = NULL; 2322eaf62fffSJeremy L Thompson CeedOperatorField *op_fields; 2323eaf62fffSJeremy L Thompson CeedQFunctionField *qf_fields; 2324eaf62fffSJeremy L Thompson CeedInt num_input_fields; 23252b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_fields, NULL, NULL)); 23262b730f8bSJeremy L Thompson CeedCall(CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL)); 2327eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_input_fields; i++) { 2328eaf62fffSJeremy L Thompson CeedVector vec; 23292b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetVector(op_fields[i], &vec)); 2330eaf62fffSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 2331eaf62fffSJeremy L Thompson CeedEvalMode eval_mode; 23322b730f8bSJeremy L Thompson CeedCall(CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode)); 2333eaf62fffSJeremy L Thompson interp = interp || eval_mode == CEED_EVAL_INTERP; 2334eaf62fffSJeremy L Thompson grad = grad || eval_mode == CEED_EVAL_GRAD; 23352b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetBasis(op_fields[i], &basis)); 23362b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr)); 2337eaf62fffSJeremy L Thompson } 2338eaf62fffSJeremy L Thompson } 23392b730f8bSJeremy L Thompson if (!basis) { 2340eaf62fffSJeremy L Thompson // LCOV_EXCL_START 2341eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "No active field set"); 2342eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 23432b730f8bSJeremy L Thompson } 2344e79b91d9SJeremy L Thompson CeedSize l_size = 1; 2345352a5e7cSSebastian Grimberg CeedInt P_1d, Q_1d, num_nodes, num_qpts, dim, num_comp = 1, num_elem = 1; 23462b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumNodes1D(basis, &P_1d)); 2347352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumNodes(basis, &num_nodes)); 23482b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d)); 23492b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis, &num_qpts)); 23502b730f8bSJeremy L Thompson CeedCall(CeedBasisGetDimension(basis, &dim)); 23512b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumComponents(basis, &num_comp)); 23522b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 23532b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size)); 2354eaf62fffSJeremy L Thompson 2355eaf62fffSJeremy L Thompson // Build and diagonalize 1D Mass and Laplacian 2356eaf62fffSJeremy L Thompson bool tensor_basis; 23572b730f8bSJeremy L Thompson CeedCall(CeedBasisIsTensor(basis, &tensor_basis)); 23582b730f8bSJeremy L Thompson if (!tensor_basis) { 2359eaf62fffSJeremy L Thompson // LCOV_EXCL_START 23602b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "FDMElementInverse only supported for tensor bases"); 2361eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 23622b730f8bSJeremy L Thompson } 2363eaf62fffSJeremy L Thompson CeedScalar *mass, *laplace, *x, *fdm_interp, *lambda; 23642b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &mass)); 23652b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &laplace)); 23662b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &x)); 23672b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &fdm_interp)); 23682b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d, &lambda)); 2369eaf62fffSJeremy L Thompson // -- Build matrices 2370eaf62fffSJeremy L Thompson const CeedScalar *interp_1d, *grad_1d, *q_weight_1d; 23712b730f8bSJeremy L Thompson CeedCall(CeedBasisGetInterp1D(basis, &interp_1d)); 23722b730f8bSJeremy L Thompson CeedCall(CeedBasisGetGrad1D(basis, &grad_1d)); 23732b730f8bSJeremy L Thompson CeedCall(CeedBasisGetQWeights(basis, &q_weight_1d)); 23742b730f8bSJeremy L Thompson CeedCall(CeedBuildMassLaplace(interp_1d, grad_1d, q_weight_1d, P_1d, Q_1d, dim, mass, laplace)); 2375eaf62fffSJeremy L Thompson 2376eaf62fffSJeremy L Thompson // -- Diagonalize 23772b730f8bSJeremy L Thompson CeedCall(CeedSimultaneousDiagonalization(ceed, laplace, mass, x, lambda, P_1d)); 23782b730f8bSJeremy L Thompson CeedCall(CeedFree(&mass)); 23792b730f8bSJeremy L Thompson CeedCall(CeedFree(&laplace)); 23802b730f8bSJeremy L Thompson for (CeedInt i = 0; i < P_1d; i++) { 23812b730f8bSJeremy L Thompson for (CeedInt j = 0; j < P_1d; j++) fdm_interp[i + j * P_1d] = x[j + i * P_1d]; 23822b730f8bSJeremy L Thompson } 23832b730f8bSJeremy L Thompson CeedCall(CeedFree(&x)); 2384eaf62fffSJeremy L Thompson 2385eaf62fffSJeremy L Thompson // Assemble QFunction 2386eaf62fffSJeremy L Thompson CeedVector assembled; 2387eaf62fffSJeremy L Thompson CeedElemRestriction rstr_qf; 23882b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled, &rstr_qf, request)); 2389eaf62fffSJeremy L Thompson CeedInt layout[3]; 23902b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetELayout(rstr_qf, &layout)); 23912b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&rstr_qf)); 2392eaf62fffSJeremy L Thompson CeedScalar max_norm = 0; 23932b730f8bSJeremy L Thompson CeedCall(CeedVectorNorm(assembled, CEED_NORM_MAX, &max_norm)); 2394eaf62fffSJeremy L Thompson 2395eaf62fffSJeremy L Thompson // Calculate element averages 2396eaf62fffSJeremy L Thompson CeedInt num_modes = (interp ? 1 : 0) + (grad ? dim : 0); 2397eaf62fffSJeremy L Thompson CeedScalar *elem_avg; 2398eaf62fffSJeremy L Thompson const CeedScalar *assembled_array, *q_weight_array; 2399eaf62fffSJeremy L Thompson CeedVector q_weight; 24002b730f8bSJeremy L Thompson CeedCall(CeedVectorCreate(ceed_parent, num_qpts, &q_weight)); 24012b730f8bSJeremy L Thompson CeedCall(CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, CEED_VECTOR_NONE, q_weight)); 24022b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembled_array)); 24032b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayRead(q_weight, CEED_MEM_HOST, &q_weight_array)); 24042b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_elem, &elem_avg)); 2405eaf62fffSJeremy L Thompson const CeedScalar qf_value_bound = max_norm * 100 * CEED_EPSILON; 2406eaf62fffSJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) { 2407eaf62fffSJeremy L Thompson CeedInt count = 0; 24082b730f8bSJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 24092b730f8bSJeremy L Thompson for (CeedInt i = 0; i < num_comp * num_comp * num_modes * num_modes; i++) { 24102b730f8bSJeremy L Thompson if (fabs(assembled_array[q * layout[0] + i * layout[1] + e * layout[2]]) > qf_value_bound) { 24112b730f8bSJeremy L Thompson elem_avg[e] += assembled_array[q * layout[0] + i * layout[1] + e * layout[2]] / q_weight_array[q]; 2412eaf62fffSJeremy L Thompson count++; 2413eaf62fffSJeremy L Thompson } 24142b730f8bSJeremy L Thompson } 24152b730f8bSJeremy L Thompson } 2416eaf62fffSJeremy L Thompson if (count) { 2417eaf62fffSJeremy L Thompson elem_avg[e] /= count; 2418eaf62fffSJeremy L Thompson } else { 2419eaf62fffSJeremy L Thompson elem_avg[e] = 1.0; 2420eaf62fffSJeremy L Thompson } 2421eaf62fffSJeremy L Thompson } 24222b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(assembled, &assembled_array)); 24232b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&assembled)); 24242b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(q_weight, &q_weight_array)); 24252b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&q_weight)); 2426eaf62fffSJeremy L Thompson 2427eaf62fffSJeremy L Thompson // Build FDM diagonal 2428eaf62fffSJeremy L Thompson CeedVector q_data; 2429eaf62fffSJeremy L Thompson CeedScalar *q_data_array, *fdm_diagonal; 2430352a5e7cSSebastian Grimberg CeedCall(CeedCalloc(num_comp * num_nodes, &fdm_diagonal)); 2431352a5e7cSSebastian Grimberg const CeedScalar fdm_diagonal_bound = num_nodes * CEED_EPSILON; 24322b730f8bSJeremy L Thompson for (CeedInt c = 0; c < num_comp; c++) { 2433352a5e7cSSebastian Grimberg for (CeedInt n = 0; n < num_nodes; n++) { 2434352a5e7cSSebastian Grimberg if (interp) fdm_diagonal[c * num_nodes + n] = 1.0; 24352b730f8bSJeremy L Thompson if (grad) { 2436eaf62fffSJeremy L Thompson for (CeedInt d = 0; d < dim; d++) { 2437eaf62fffSJeremy L Thompson CeedInt i = (n / CeedIntPow(P_1d, d)) % P_1d; 2438352a5e7cSSebastian Grimberg fdm_diagonal[c * num_nodes + n] += lambda[i]; 2439eaf62fffSJeremy L Thompson } 2440eaf62fffSJeremy L Thompson } 2441352a5e7cSSebastian Grimberg if (fabs(fdm_diagonal[c * num_nodes + n]) < fdm_diagonal_bound) fdm_diagonal[c * num_nodes + n] = fdm_diagonal_bound; 24422b730f8bSJeremy L Thompson } 24432b730f8bSJeremy L Thompson } 2444352a5e7cSSebastian Grimberg CeedCall(CeedVectorCreate(ceed_parent, num_elem * num_comp * num_nodes, &q_data)); 24452b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(q_data, 0.0)); 24462b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayWrite(q_data, CEED_MEM_HOST, &q_data_array)); 24472b730f8bSJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) { 24482b730f8bSJeremy L Thompson for (CeedInt c = 0; c < num_comp; c++) { 2449352a5e7cSSebastian Grimberg for (CeedInt n = 0; n < num_nodes; n++) q_data_array[(e * num_comp + c) * num_nodes + n] = 1. / (elem_avg[e] * fdm_diagonal[c * num_nodes + n]); 24502b730f8bSJeremy L Thompson } 24512b730f8bSJeremy L Thompson } 24522b730f8bSJeremy L Thompson CeedCall(CeedFree(&elem_avg)); 24532b730f8bSJeremy L Thompson CeedCall(CeedFree(&fdm_diagonal)); 24542b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArray(q_data, &q_data_array)); 2455eaf62fffSJeremy L Thompson 2456eaf62fffSJeremy L Thompson // Setup FDM operator 2457eaf62fffSJeremy L Thompson // -- Basis 2458eaf62fffSJeremy L Thompson CeedBasis fdm_basis; 2459eaf62fffSJeremy L Thompson CeedScalar *grad_dummy, *q_ref_dummy, *q_weight_dummy; 24602b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &grad_dummy)); 24612b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d, &q_ref_dummy)); 24622b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d, &q_weight_dummy)); 24632b730f8bSJeremy L Thompson CeedCall(CeedBasisCreateTensorH1(ceed_parent, dim, num_comp, P_1d, P_1d, fdm_interp, grad_dummy, q_ref_dummy, q_weight_dummy, &fdm_basis)); 24642b730f8bSJeremy L Thompson CeedCall(CeedFree(&fdm_interp)); 24652b730f8bSJeremy L Thompson CeedCall(CeedFree(&grad_dummy)); 24662b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_ref_dummy)); 24672b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_weight_dummy)); 24682b730f8bSJeremy L Thompson CeedCall(CeedFree(&lambda)); 2469eaf62fffSJeremy L Thompson 2470eaf62fffSJeremy L Thompson // -- Restriction 2471eaf62fffSJeremy L Thompson CeedElemRestriction rstr_qd_i; 2472352a5e7cSSebastian Grimberg CeedInt strides[3] = {1, num_nodes, num_nodes * num_comp}; 2473352a5e7cSSebastian Grimberg CeedCall(CeedElemRestrictionCreateStrided(ceed_parent, num_elem, num_nodes, num_comp, num_elem * num_comp * num_nodes, strides, &rstr_qd_i)); 2474eaf62fffSJeremy L Thompson // -- QFunction 2475eaf62fffSJeremy L Thompson CeedQFunction qf_fdm; 24762b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateInteriorByName(ceed_parent, "Scale", &qf_fdm)); 24772b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_fdm, "input", num_comp, CEED_EVAL_INTERP)); 24782b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_fdm, "scale", num_comp, CEED_EVAL_NONE)); 24792b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddOutput(qf_fdm, "output", num_comp, CEED_EVAL_INTERP)); 24802b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetUserFlopsEstimate(qf_fdm, num_comp)); 2481eaf62fffSJeremy L Thompson // -- QFunction context 2482eaf62fffSJeremy L Thompson CeedInt *num_comp_data; 24832b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, &num_comp_data)); 2484eaf62fffSJeremy L Thompson num_comp_data[0] = num_comp; 2485eaf62fffSJeremy L Thompson CeedQFunctionContext ctx_fdm; 24862b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextCreate(ceed, &ctx_fdm)); 24872b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextSetData(ctx_fdm, CEED_MEM_HOST, CEED_OWN_POINTER, sizeof(*num_comp_data), num_comp_data)); 24882b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetContext(qf_fdm, ctx_fdm)); 24892b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextDestroy(&ctx_fdm)); 2490eaf62fffSJeremy L Thompson // -- Operator 24912b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(ceed_parent, qf_fdm, NULL, NULL, fdm_inv)); 24922b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*fdm_inv, "input", rstr, fdm_basis, CEED_VECTOR_ACTIVE)); 24932b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*fdm_inv, "scale", rstr_qd_i, CEED_BASIS_COLLOCATED, q_data)); 24942b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*fdm_inv, "output", rstr, fdm_basis, CEED_VECTOR_ACTIVE)); 2495eaf62fffSJeremy L Thompson 2496eaf62fffSJeremy L Thompson // Cleanup 24972b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&q_data)); 24982b730f8bSJeremy L Thompson CeedCall(CeedBasisDestroy(&fdm_basis)); 24992b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&rstr_qd_i)); 25002b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&qf_fdm)); 2501eaf62fffSJeremy L Thompson 2502eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2503eaf62fffSJeremy L Thompson } 2504eaf62fffSJeremy L Thompson 2505eaf62fffSJeremy L Thompson /// @} 2506