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) { 381c66c397SJeremy L Thompson char *source_path_with_name = NULL; 391c66c397SJeremy L Thompson 409e77b9c8SJeremy L Thompson // Check if NULL qf passed in 419e77b9c8SJeremy L Thompson if (!qf) return CEED_ERROR_SUCCESS; 429e77b9c8SJeremy L Thompson 43d04bbc78SJeremy L Thompson CeedDebug256(qf->ceed, 1, "---------- CeedOperator Fallback ----------\n"); 4413f886e9SJeremy L Thompson CeedDebug(qf->ceed, "Creating fallback CeedQFunction\n"); 45d04bbc78SJeremy L Thompson 469e77b9c8SJeremy L Thompson if (qf->source_path) { 472b730f8bSJeremy L Thompson size_t path_len = strlen(qf->source_path), name_len = strlen(qf->kernel_name); 482b730f8bSJeremy L Thompson CeedCall(CeedCalloc(path_len + name_len + 2, &source_path_with_name)); 499e77b9c8SJeremy L Thompson memcpy(source_path_with_name, qf->source_path, path_len); 509e77b9c8SJeremy L Thompson memcpy(&source_path_with_name[path_len], ":", 1); 519e77b9c8SJeremy L Thompson memcpy(&source_path_with_name[path_len + 1], qf->kernel_name, name_len); 529e77b9c8SJeremy L Thompson } else { 532b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, &source_path_with_name)); 549e77b9c8SJeremy L Thompson } 559e77b9c8SJeremy L Thompson 562b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateInterior(fallback_ceed, qf->vec_length, qf->function, source_path_with_name, qf_fallback)); 579e77b9c8SJeremy L Thompson { 589e77b9c8SJeremy L Thompson CeedQFunctionContext ctx; 599e77b9c8SJeremy L Thompson 602b730f8bSJeremy L Thompson CeedCall(CeedQFunctionGetContext(qf, &ctx)); 612b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetContext(*qf_fallback, ctx)); 629e77b9c8SJeremy L Thompson } 639e77b9c8SJeremy L Thompson for (CeedInt i = 0; i < qf->num_input_fields; i++) { 642b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(*qf_fallback, qf->input_fields[i]->field_name, qf->input_fields[i]->size, qf->input_fields[i]->eval_mode)); 659e77b9c8SJeremy L Thompson } 669e77b9c8SJeremy L Thompson for (CeedInt i = 0; i < qf->num_output_fields; i++) { 672b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddOutput(*qf_fallback, qf->output_fields[i]->field_name, qf->output_fields[i]->size, qf->output_fields[i]->eval_mode)); 689e77b9c8SJeremy L Thompson } 692b730f8bSJeremy L Thompson CeedCall(CeedFree(&source_path_with_name)); 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) { 839e77b9c8SJeremy L Thompson Ceed ceed_fallback; 841c66c397SJeremy L Thompson bool is_composite; 851c66c397SJeremy L Thompson CeedOperator op_fallback; 86eaf62fffSJeremy L Thompson 87805fe78eSJeremy L Thompson // Check not already created 88805fe78eSJeremy L Thompson if (op->op_fallback) return CEED_ERROR_SUCCESS; 89805fe78eSJeremy L Thompson 90eaf62fffSJeremy L Thompson // Fallback Ceed 912b730f8bSJeremy L Thompson CeedCall(CeedGetOperatorFallbackCeed(op->ceed, &ceed_fallback)); 92d04bbc78SJeremy L Thompson if (!ceed_fallback) return CEED_ERROR_SUCCESS; 93d04bbc78SJeremy L Thompson 94d04bbc78SJeremy L Thompson CeedDebug256(op->ceed, 1, "---------- CeedOperator Fallback ----------\n"); 9513f886e9SJeremy L Thompson CeedDebug(op->ceed, "Creating fallback CeedOperator\n"); 96eaf62fffSJeremy L Thompson 97eaf62fffSJeremy L Thompson // Clone Op 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; 1141c66c397SJeremy L Thompson 1152b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateFallback(ceed_fallback, op->qf, &qf_fallback)); 1162b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateFallback(ceed_fallback, op->dqf, &dqf_fallback)); 1172b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateFallback(ceed_fallback, op->dqfT, &dqfT_fallback)); 1182b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(ceed_fallback, qf_fallback, dqf_fallback, dqfT_fallback, &op_fallback)); 119805fe78eSJeremy L Thompson for (CeedInt i = 0; i < op->qf->num_input_fields; i++) { 120437c7c90SJeremy L Thompson CeedCall(CeedOperatorSetField(op_fallback, op->input_fields[i]->field_name, op->input_fields[i]->elem_rstr, op->input_fields[i]->basis, 1212b730f8bSJeremy L Thompson op->input_fields[i]->vec)); 122805fe78eSJeremy L Thompson } 123805fe78eSJeremy L Thompson for (CeedInt i = 0; i < op->qf->num_output_fields; i++) { 124437c7c90SJeremy L Thompson CeedCall(CeedOperatorSetField(op_fallback, op->output_fields[i]->field_name, op->output_fields[i]->elem_rstr, op->output_fields[i]->basis, 1252b730f8bSJeremy L Thompson op->output_fields[i]->vec)); 126805fe78eSJeremy L Thompson } 1272b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataReferenceCopy(op->qf_assembled, &op_fallback->qf_assembled)); 128febe2972SJeremy L Thompson if (op_fallback->num_qpts == 0) CeedCall(CeedOperatorSetNumQuadraturePoints(op_fallback, op->num_qpts)); 1299e77b9c8SJeremy L Thompson // Cleanup 1302b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&qf_fallback)); 1312b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&dqf_fallback)); 1322b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&dqfT_fallback)); 133805fe78eSJeremy L Thompson } 1342b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetName(op_fallback, op->name)); 1352b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op_fallback)); 136b05f7e9fSJeremy L Thompson // Note: No ref-counting here so we don't get caught in a reference loop. 137b05f7e9fSJeremy L Thompson // The op holds the only reference to op_fallback and is responsible for deleting itself and op_fallback. 138805fe78eSJeremy L Thompson op->op_fallback = op_fallback; 139b05f7e9fSJeremy L Thompson op_fallback->op_fallback_parent = op; 140eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 141eaf62fffSJeremy L Thompson } 142eaf62fffSJeremy L Thompson 143eaf62fffSJeremy L Thompson /** 144ea61e9acSJeremy L Thompson @brief Retrieve fallback CeedOperator with a reference Ceed for advanced CeedOperator functionality 145d04bbc78SJeremy L Thompson 146d04bbc78SJeremy L Thompson @param[in] op CeedOperator to retrieve fallback for 147d04bbc78SJeremy L Thompson @param[out] op_fallback Fallback CeedOperator 148d04bbc78SJeremy L Thompson 149d04bbc78SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 150d04bbc78SJeremy L Thompson 151d04bbc78SJeremy L Thompson @ref Developer 152d04bbc78SJeremy L Thompson **/ 153d04bbc78SJeremy L Thompson int CeedOperatorGetFallback(CeedOperator op, CeedOperator *op_fallback) { 154d04bbc78SJeremy L Thompson // Create if needed 1551c66c397SJeremy L Thompson if (!op->op_fallback) CeedCall(CeedOperatorCreateFallback(op)); 156d04bbc78SJeremy L Thompson if (op->op_fallback) { 157d04bbc78SJeremy L Thompson bool is_debug; 158d04bbc78SJeremy L Thompson 1592b730f8bSJeremy L Thompson CeedCall(CeedIsDebug(op->ceed, &is_debug)); 160d04bbc78SJeremy L Thompson if (is_debug) { 161b275c451SJeremy L Thompson Ceed ceed, ceed_fallback; 162d04bbc78SJeremy L Thompson const char *resource, *resource_fallback; 163d04bbc78SJeremy L Thompson 164b275c451SJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 165b275c451SJeremy L Thompson CeedCall(CeedGetOperatorFallbackCeed(ceed, &ceed_fallback)); 166b275c451SJeremy L Thompson CeedCall(CeedGetResource(ceed, &resource)); 1672b730f8bSJeremy L Thompson CeedCall(CeedGetResource(ceed_fallback, &resource_fallback)); 168d04bbc78SJeremy L Thompson 16923d4529eSJeremy L Thompson CeedDebug256(ceed, CEED_DEBUG_COLOR_SUCCESS, "---------- CeedOperator Fallback ----------\n"); 170b275c451SJeremy L Thompson CeedDebug(ceed, "Falling back from %s operator at address %ld to %s operator at address %ld\n", resource, op, resource_fallback, 1712b730f8bSJeremy L Thompson op->op_fallback); 172d04bbc78SJeremy L Thompson } 173d04bbc78SJeremy L Thompson } 174d04bbc78SJeremy L Thompson *op_fallback = op->op_fallback; 175d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 176d04bbc78SJeremy L Thompson } 177d04bbc78SJeremy L Thompson 178d04bbc78SJeremy L Thompson /** 1792e8f5c67SJeremy L Thompson @brief Get the parent CeedOperator for a fallback CeedOperator 180bb229da9SJeremy L Thompson 181bb229da9SJeremy L Thompson @param[in] op CeedOperator context 182bb229da9SJeremy L Thompson @param[out] parent Variable to store parent CeedOperator context 183bb229da9SJeremy L Thompson 184bb229da9SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 185bb229da9SJeremy L Thompson 186bb229da9SJeremy L Thompson @ref Developer 187bb229da9SJeremy L Thompson **/ 188bb229da9SJeremy L Thompson int CeedOperatorGetFallbackParent(CeedOperator op, CeedOperator *parent) { 189bb229da9SJeremy L Thompson *parent = op->op_fallback_parent ? op->op_fallback_parent : NULL; 190bb229da9SJeremy L Thompson return CEED_ERROR_SUCCESS; 191bb229da9SJeremy L Thompson } 192bb229da9SJeremy L Thompson 193bb229da9SJeremy L Thompson /** 1942e8f5c67SJeremy L Thompson @brief Get the Ceed context of the parent CeedOperator for a fallback CeedOperator 195bb229da9SJeremy L Thompson 196bb229da9SJeremy L Thompson @param[in] op CeedOperator context 197bb229da9SJeremy L Thompson @param[out] parent Variable to store parent Ceed context 198bb229da9SJeremy L Thompson 199bb229da9SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 200bb229da9SJeremy L Thompson 201bb229da9SJeremy L Thompson @ref Developer 202bb229da9SJeremy L Thompson **/ 203bb229da9SJeremy L Thompson int CeedOperatorGetFallbackParentCeed(CeedOperator op, Ceed *parent) { 204e984cf9aSJeremy L Thompson *parent = op->op_fallback_parent ? op->op_fallback_parent->ceed : op->ceed; 205bb229da9SJeremy L Thompson return CEED_ERROR_SUCCESS; 206bb229da9SJeremy L Thompson } 207bb229da9SJeremy L Thompson 208bb229da9SJeremy L Thompson /** 209eaf62fffSJeremy L Thompson @brief Select correct basis matrix pointer based on CeedEvalMode 210eaf62fffSJeremy L Thompson 211352a5e7cSSebastian Grimberg @param[in] basis CeedBasis from which to get the basis matrix 212eaf62fffSJeremy L Thompson @param[in] eval_mode Current basis evaluation mode 213eaf62fffSJeremy L Thompson @param[in] identity Pointer to identity matrix 214eaf62fffSJeremy L Thompson @param[out] basis_ptr Basis pointer to set 215eaf62fffSJeremy L Thompson 216eaf62fffSJeremy L Thompson @ref Developer 217eaf62fffSJeremy L Thompson **/ 218352a5e7cSSebastian Grimberg static inline int CeedOperatorGetBasisPointer(CeedBasis basis, CeedEvalMode eval_mode, const CeedScalar *identity, const CeedScalar **basis_ptr) { 219eaf62fffSJeremy L Thompson switch (eval_mode) { 220eaf62fffSJeremy L Thompson case CEED_EVAL_NONE: 221eaf62fffSJeremy L Thompson *basis_ptr = identity; 222eaf62fffSJeremy L Thompson break; 223eaf62fffSJeremy L Thompson case CEED_EVAL_INTERP: 224352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetInterp(basis, basis_ptr)); 225eaf62fffSJeremy L Thompson break; 226eaf62fffSJeremy L Thompson case CEED_EVAL_GRAD: 227352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetGrad(basis, basis_ptr)); 228352a5e7cSSebastian Grimberg break; 229352a5e7cSSebastian Grimberg case CEED_EVAL_DIV: 230352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetDiv(basis, basis_ptr)); 231352a5e7cSSebastian Grimberg break; 232352a5e7cSSebastian Grimberg case CEED_EVAL_CURL: 233352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetCurl(basis, basis_ptr)); 234eaf62fffSJeremy L Thompson break; 235eaf62fffSJeremy L Thompson case CEED_EVAL_WEIGHT: 236eaf62fffSJeremy L Thompson break; // Caught by QF Assembly 237eaf62fffSJeremy L Thompson } 238ed9e99e6SJeremy L Thompson assert(*basis_ptr != NULL); 239352a5e7cSSebastian Grimberg return CEED_ERROR_SUCCESS; 240eaf62fffSJeremy L Thompson } 241eaf62fffSJeremy L Thompson 242eaf62fffSJeremy L Thompson /** 243eaf62fffSJeremy L Thompson @brief Core logic for assembling operator diagonal or point block diagonal 244eaf62fffSJeremy L Thompson 245eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble point block diagonal 246ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else CEED_REQUEST_IMMEDIATE 247bd83916cSSebastian Grimberg @param[in] is_point_block Boolean flag to assemble diagonal or point block diagonal 248eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled diagonal 249eaf62fffSJeremy L Thompson 250eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 251eaf62fffSJeremy L Thompson 252eaf62fffSJeremy L Thompson @ref Developer 253eaf62fffSJeremy L Thompson **/ 254bd83916cSSebastian Grimberg static inline int CeedSingleOperatorAssembleAddDiagonal_Core(CeedOperator op, CeedRequest *request, const bool is_point_block, CeedVector assembled) { 255eaf62fffSJeremy L Thompson Ceed ceed; 256*506b1a0cSSebastian Grimberg bool is_composite; 257*506b1a0cSSebastian Grimberg 258*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorGetCeed(op, &ceed)); 259*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorIsComposite(op, &is_composite)); 260*506b1a0cSSebastian Grimberg CeedCheck(!is_composite, ceed, CEED_ERROR_UNSUPPORTED, "Composite operator not supported"); 261*506b1a0cSSebastian Grimberg 262*506b1a0cSSebastian Grimberg // Assemble QFunction 263*506b1a0cSSebastian Grimberg CeedInt layout_qf[3]; 264437c7c90SJeremy L Thompson const CeedScalar *assembled_qf_array; 265c5f45aeaSJeremy L Thompson CeedVector assembled_qf = NULL; 266c5f45aeaSJeremy L Thompson CeedElemRestriction assembled_elem_rstr = NULL; 267437c7c90SJeremy L Thompson 268437c7c90SJeremy L Thompson CeedCall(CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled_qf, &assembled_elem_rstr, request)); 269*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetELayout(assembled_elem_rstr, &layout_qf)); 270437c7c90SJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&assembled_elem_rstr)); 271437c7c90SJeremy L Thompson CeedCall(CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array)); 272eaf62fffSJeremy L Thompson 273ed9e99e6SJeremy L Thompson // Get assembly data 274437c7c90SJeremy L Thompson const CeedEvalMode **eval_modes_in, **eval_modes_out; 275*506b1a0cSSebastian Grimberg CeedInt num_active_bases_in, *num_eval_modes_in, num_active_bases_out, *num_eval_modes_out; 276437c7c90SJeremy L Thompson CeedSize **eval_mode_offsets_in, **eval_mode_offsets_out, num_output_components; 277*506b1a0cSSebastian Grimberg CeedBasis *active_bases_in, *active_bases_out; 278*506b1a0cSSebastian Grimberg CeedElemRestriction *active_elem_rstrs_in, *active_elem_rstrs_out; 2791c66c397SJeremy L Thompson CeedOperatorAssemblyData data; 2801c66c397SJeremy L Thompson 281437c7c90SJeremy L Thompson CeedCall(CeedOperatorGetOperatorAssemblyData(op, &data)); 282*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorAssemblyDataGetEvalModes(data, &num_active_bases_in, &num_eval_modes_in, &eval_modes_in, &eval_mode_offsets_in, 283*506b1a0cSSebastian Grimberg &num_active_bases_out, &num_eval_modes_out, &eval_modes_out, &eval_mode_offsets_out, 284*506b1a0cSSebastian Grimberg &num_output_components)); 285*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorAssemblyDataGetBases(data, NULL, &active_bases_in, NULL, NULL, &active_bases_out, NULL)); 286*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorAssemblyDataGetElemRestrictions(data, NULL, &active_elem_rstrs_in, NULL, &active_elem_rstrs_out)); 287*506b1a0cSSebastian Grimberg 288*506b1a0cSSebastian Grimberg CeedCheck(num_active_bases_in == num_active_bases_out, ceed, CEED_ERROR_UNSUPPORTED, 289*506b1a0cSSebastian Grimberg "Cannot assemble operator diagonal with different numbers of input and output active bases"); 290437c7c90SJeremy L Thompson 291437c7c90SJeremy L Thompson // Loop over all active bases 292*506b1a0cSSebastian Grimberg for (CeedInt b = 0; b < num_active_bases_in; b++) { 2931c66c397SJeremy L Thompson bool has_eval_none = false; 294*506b1a0cSSebastian Grimberg CeedInt num_elem, num_nodes, num_qpts, num_comp; 2951c66c397SJeremy L Thompson CeedScalar *elem_diag_array, *identity = NULL; 2961c66c397SJeremy L Thompson CeedVector elem_diag; 2977c1dbaffSSebastian Grimberg CeedElemRestriction diag_elem_rstr; 2981c66c397SJeremy L Thompson 299*506b1a0cSSebastian Grimberg CeedCheck(active_elem_rstrs_in[b] == active_elem_rstrs_out[b], ceed, CEED_ERROR_UNSUPPORTED, 300*506b1a0cSSebastian Grimberg "Cannot assemble operator diagonal with different input and output active element restrictions"); 301*506b1a0cSSebastian Grimberg 3021c66c397SJeremy L Thompson // Assemble point block diagonal restriction, if needed 303bd83916cSSebastian Grimberg if (is_point_block) { 304*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorCreateActivePointBlockRestriction(active_elem_rstrs_in[b], &diag_elem_rstr)); 3057c1dbaffSSebastian Grimberg } else { 306*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionCreateUnsignedCopy(active_elem_rstrs_in[b], &diag_elem_rstr)); 307eaf62fffSJeremy L Thompson } 308eaf62fffSJeremy L Thompson 309eaf62fffSJeremy L Thompson // Create diagonal vector 310437c7c90SJeremy L Thompson CeedCall(CeedElemRestrictionCreateVector(diag_elem_rstr, NULL, &elem_diag)); 311eaf62fffSJeremy L Thompson 312eaf62fffSJeremy L Thompson // Assemble element operator diagonals 3132b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(elem_diag, 0.0)); 3142b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArray(elem_diag, CEED_MEM_HOST, &elem_diag_array)); 315437c7c90SJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(diag_elem_rstr, &num_elem)); 316*506b1a0cSSebastian Grimberg CeedCall(CeedBasisGetNumNodes(active_bases_in[b], &num_nodes)); 317*506b1a0cSSebastian Grimberg CeedCall(CeedBasisGetNumComponents(active_bases_in[b], &num_comp)); 318*506b1a0cSSebastian Grimberg if (active_bases_in[b] == CEED_BASIS_NONE) num_qpts = num_nodes; 319*506b1a0cSSebastian Grimberg else CeedCall(CeedBasisGetNumQuadraturePoints(active_bases_in[b], &num_qpts)); 320*506b1a0cSSebastian Grimberg 321*506b1a0cSSebastian Grimberg if (active_bases_in[b] != active_bases_out[b]) { 322*506b1a0cSSebastian Grimberg CeedInt num_nodes_out, num_qpts_out, num_comp_out; 323*506b1a0cSSebastian Grimberg 324*506b1a0cSSebastian Grimberg CeedCall(CeedBasisGetNumNodes(active_bases_out[b], &num_nodes_out)); 325*506b1a0cSSebastian Grimberg CeedCheck(num_nodes == num_nodes_out, ceed, CEED_ERROR_UNSUPPORTED, "Active input and output bases must have the same number of nodes"); 326*506b1a0cSSebastian Grimberg CeedCall(CeedBasisGetNumComponents(active_bases_out[b], &num_comp_out)); 327*506b1a0cSSebastian Grimberg CeedCheck(num_comp == num_comp_out, ceed, CEED_ERROR_UNSUPPORTED, "Active input and output bases must have the same number of components"); 328*506b1a0cSSebastian Grimberg if (active_bases_out[b] == CEED_BASIS_NONE) num_qpts_out = num_nodes_out; 329*506b1a0cSSebastian Grimberg else CeedCall(CeedBasisGetNumQuadraturePoints(active_bases_out[b], &num_qpts_out)); 330*506b1a0cSSebastian Grimberg CeedCheck(num_qpts == num_qpts_out, ceed, CEED_ERROR_UNSUPPORTED, 331*506b1a0cSSebastian Grimberg "Active input and output bases must have the same number of quadrature points"); 332*506b1a0cSSebastian Grimberg } 333ed9e99e6SJeremy L Thompson 334352a5e7cSSebastian Grimberg // Construct identity matrix for basis if required 335437c7c90SJeremy L Thompson for (CeedInt i = 0; i < num_eval_modes_in[b]; i++) { 336437c7c90SJeremy L Thompson has_eval_none = has_eval_none || (eval_modes_in[b][i] == CEED_EVAL_NONE); 337ed9e99e6SJeremy L Thompson } 338437c7c90SJeremy L Thompson for (CeedInt i = 0; i < num_eval_modes_out[b]; i++) { 339437c7c90SJeremy L Thompson has_eval_none = has_eval_none || (eval_modes_out[b][i] == CEED_EVAL_NONE); 340ed9e99e6SJeremy L Thompson } 341ed9e99e6SJeremy L Thompson if (has_eval_none) { 3422b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_qpts * num_nodes, &identity)); 3432b730f8bSJeremy L Thompson for (CeedInt i = 0; i < (num_nodes < num_qpts ? num_nodes : num_qpts); i++) identity[i * num_nodes + i] = 1.0; 344eaf62fffSJeremy L Thompson } 345352a5e7cSSebastian Grimberg 346eaf62fffSJeremy L Thompson // Compute the diagonal of B^T D B 347eaf62fffSJeremy L Thompson // Each element 348b94338b9SJed Brown for (CeedSize e = 0; e < num_elem; e++) { 349eaf62fffSJeremy L Thompson // Each basis eval mode pair 350352a5e7cSSebastian Grimberg CeedInt d_out = 0, q_comp_out; 351352a5e7cSSebastian Grimberg CeedEvalMode eval_mode_out_prev = CEED_EVAL_NONE; 3521c66c397SJeremy L Thompson 353437c7c90SJeremy L Thompson for (CeedInt e_out = 0; e_out < num_eval_modes_out[b]; e_out++) { 3541c66c397SJeremy L Thompson CeedInt d_in = 0, q_comp_in; 355437c7c90SJeremy L Thompson const CeedScalar *B_t = NULL; 3561c66c397SJeremy L Thompson CeedEvalMode eval_mode_in_prev = CEED_EVAL_NONE; 3571c66c397SJeremy L Thompson 358*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorGetBasisPointer(active_bases_out[b], eval_modes_out[b][e_out], identity, &B_t)); 359*506b1a0cSSebastian Grimberg CeedCall(CeedBasisGetNumQuadratureComponents(active_bases_out[b], eval_modes_out[b][e_out], &q_comp_out)); 360352a5e7cSSebastian Grimberg if (q_comp_out > 1) { 361352a5e7cSSebastian Grimberg if (e_out == 0 || eval_modes_out[b][e_out] != eval_mode_out_prev) d_out = 0; 362352a5e7cSSebastian Grimberg else B_t = &B_t[(++d_out) * num_qpts * num_nodes]; 363352a5e7cSSebastian Grimberg } 364352a5e7cSSebastian Grimberg eval_mode_out_prev = eval_modes_out[b][e_out]; 365352a5e7cSSebastian Grimberg 366437c7c90SJeremy L Thompson for (CeedInt e_in = 0; e_in < num_eval_modes_in[b]; e_in++) { 367437c7c90SJeremy L Thompson const CeedScalar *B = NULL; 3681c66c397SJeremy L Thompson 369*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorGetBasisPointer(active_bases_in[b], eval_modes_in[b][e_in], identity, &B)); 370*506b1a0cSSebastian Grimberg CeedCall(CeedBasisGetNumQuadratureComponents(active_bases_in[b], eval_modes_in[b][e_in], &q_comp_in)); 371352a5e7cSSebastian Grimberg if (q_comp_in > 1) { 372352a5e7cSSebastian Grimberg if (e_in == 0 || eval_modes_in[b][e_in] != eval_mode_in_prev) d_in = 0; 373352a5e7cSSebastian Grimberg else B = &B[(++d_in) * num_qpts * num_nodes]; 374352a5e7cSSebastian Grimberg } 375352a5e7cSSebastian Grimberg eval_mode_in_prev = eval_modes_in[b][e_in]; 376352a5e7cSSebastian Grimberg 377eaf62fffSJeremy L Thompson // Each component 378*506b1a0cSSebastian Grimberg for (CeedInt c_out = 0; c_out < num_comp; c_out++) { 379437c7c90SJeremy L Thompson // Each qpt/node pair 3802b730f8bSJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 381bd83916cSSebastian Grimberg if (is_point_block) { 382eaf62fffSJeremy L Thompson // Point Block Diagonal 383*506b1a0cSSebastian Grimberg for (CeedInt c_in = 0; c_in < num_comp; c_in++) { 384b94338b9SJed Brown const CeedSize c_offset = (eval_mode_offsets_in[b][e_in] + c_in) * num_output_components + eval_mode_offsets_out[b][e_out] + c_out; 385*506b1a0cSSebastian Grimberg const CeedScalar qf_value = assembled_qf_array[q * layout_qf[0] + c_offset * layout_qf[1] + e * layout_qf[2]]; 3861c66c397SJeremy L Thompson 3872b730f8bSJeremy L Thompson for (CeedInt n = 0; n < num_nodes; n++) { 388*506b1a0cSSebastian Grimberg elem_diag_array[((e * num_comp + c_out) * num_comp + c_in) * num_nodes + n] += 389437c7c90SJeremy L Thompson B_t[q * num_nodes + n] * qf_value * B[q * num_nodes + n]; 390eaf62fffSJeremy L Thompson } 3912b730f8bSJeremy L Thompson } 392eaf62fffSJeremy L Thompson } else { 393eaf62fffSJeremy L Thompson // Diagonal Only 394437c7c90SJeremy 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; 395*506b1a0cSSebastian Grimberg const CeedScalar qf_value = assembled_qf_array[q * layout_qf[0] + c_offset * layout_qf[1] + e * layout_qf[2]]; 3961c66c397SJeremy L Thompson 3972b730f8bSJeremy L Thompson for (CeedInt n = 0; n < num_nodes; n++) { 398*506b1a0cSSebastian Grimberg elem_diag_array[(e * num_comp + c_out) * num_nodes + n] += B_t[q * num_nodes + n] * qf_value * B[q * num_nodes + n]; 399eaf62fffSJeremy L Thompson } 400eaf62fffSJeremy L Thompson } 401eaf62fffSJeremy L Thompson } 402eaf62fffSJeremy L Thompson } 4032b730f8bSJeremy L Thompson } 4042b730f8bSJeremy L Thompson } 4052b730f8bSJeremy L Thompson } 4062b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArray(elem_diag, &elem_diag_array)); 407eaf62fffSJeremy L Thompson 408eaf62fffSJeremy L Thompson // Assemble local operator diagonal 4097c1dbaffSSebastian Grimberg CeedCall(CeedElemRestrictionApply(diag_elem_rstr, CEED_TRANSPOSE, elem_diag, assembled, request)); 410eaf62fffSJeremy L Thompson 411eaf62fffSJeremy L Thompson // Cleanup 4127c1dbaffSSebastian Grimberg CeedCall(CeedElemRestrictionDestroy(&diag_elem_rstr)); 4132b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&elem_diag)); 4142b730f8bSJeremy L Thompson CeedCall(CeedFree(&identity)); 415437c7c90SJeremy L Thompson } 416437c7c90SJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array)); 417437c7c90SJeremy L Thompson CeedCall(CeedVectorDestroy(&assembled_qf)); 418eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 419eaf62fffSJeremy L Thompson } 420eaf62fffSJeremy L Thompson 421eaf62fffSJeremy L Thompson /** 422eaf62fffSJeremy L Thompson @brief Core logic for assembling composite operator diagonal 423eaf62fffSJeremy L Thompson 424eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble point block diagonal 425ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else CEED_REQUEST_IMMEDIATE 426bd83916cSSebastian Grimberg @param[in] is_point_block Boolean flag to assemble diagonal or point block diagonal 427eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled diagonal 428eaf62fffSJeremy L Thompson 429eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 430eaf62fffSJeremy L Thompson 431eaf62fffSJeremy L Thompson @ref Developer 432eaf62fffSJeremy L Thompson **/ 433bd83916cSSebastian Grimberg static inline int CeedCompositeOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedRequest *request, const bool is_point_block, 434eaf62fffSJeremy L Thompson CeedVector assembled) { 435eaf62fffSJeremy L Thompson CeedInt num_sub; 436eaf62fffSJeremy L Thompson CeedOperator *suboperators; 4371c66c397SJeremy L Thompson 438c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub)); 439c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetSubList(op, &suboperators)); 440eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_sub; i++) { 441bd83916cSSebastian Grimberg if (is_point_block) { 4422b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddPointBlockDiagonal(suboperators[i], assembled, request)); 4436aa95790SJeremy L Thompson } else { 4442b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddDiagonal(suboperators[i], assembled, request)); 4456aa95790SJeremy L Thompson } 446eaf62fffSJeremy L Thompson } 447eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 448eaf62fffSJeremy L Thompson } 449eaf62fffSJeremy L Thompson 450eaf62fffSJeremy L Thompson /** 451eaf62fffSJeremy L Thompson @brief Build nonzero pattern for non-composite operator 452eaf62fffSJeremy L Thompson 453eaf62fffSJeremy L Thompson Users should generally use CeedOperatorLinearAssembleSymbolic() 454eaf62fffSJeremy L Thompson 455eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble nonzero pattern 456eaf62fffSJeremy L Thompson @param[in] offset Offset for number of entries 457eaf62fffSJeremy L Thompson @param[out] rows Row number for each entry 458eaf62fffSJeremy L Thompson @param[out] cols Column number for each entry 459eaf62fffSJeremy L Thompson 460eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 461eaf62fffSJeremy L Thompson 462eaf62fffSJeremy L Thompson @ref Developer 463eaf62fffSJeremy L Thompson **/ 4642b730f8bSJeremy L Thompson static int CeedSingleOperatorAssembleSymbolic(CeedOperator op, CeedInt offset, CeedInt *rows, CeedInt *cols) { 465f3d47e36SJeremy L Thompson Ceed ceed; 466f3d47e36SJeremy L Thompson bool is_composite; 467*506b1a0cSSebastian Grimberg CeedSize num_nodes_in, num_nodes_out, count = 0; 468*506b1a0cSSebastian Grimberg CeedInt num_elem_in, elem_size_in, num_comp_in, layout_er_in[3]; 469*506b1a0cSSebastian Grimberg CeedInt num_elem_out, elem_size_out, num_comp_out, layout_er_out[3], local_num_entries; 4701c66c397SJeremy L Thompson CeedScalar *array; 471*506b1a0cSSebastian Grimberg const CeedScalar *elem_dof_a_in, *elem_dof_a_out; 472*506b1a0cSSebastian Grimberg CeedVector index_vec_in, index_vec_out, elem_dof_in, elem_dof_out; 473*506b1a0cSSebastian Grimberg CeedElemRestriction elem_rstr_in, elem_rstr_out, index_elem_rstr_in, index_elem_rstr_out; 4741c66c397SJeremy L Thompson 475f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 476f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 4776574a04fSJeremy L Thompson CeedCheck(!is_composite, ceed, CEED_ERROR_UNSUPPORTED, "Composite operator not supported"); 478eaf62fffSJeremy L Thompson 479*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorGetActiveVectorLengths(op, &num_nodes_in, &num_nodes_out)); 480*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorGetActiveElemRestrictions(op, &elem_rstr_in, &elem_rstr_out)); 481*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetNumElements(elem_rstr_in, &num_elem_in)); 482*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetElementSize(elem_rstr_in, &elem_size_in)); 483*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetNumComponents(elem_rstr_in, &num_comp_in)); 484*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetELayout(elem_rstr_in, &layout_er_in)); 485eaf62fffSJeremy L Thompson 486*506b1a0cSSebastian Grimberg // Determine elem_dof relation for input 487*506b1a0cSSebastian Grimberg CeedCall(CeedVectorCreate(ceed, num_nodes_in, &index_vec_in)); 488*506b1a0cSSebastian Grimberg CeedCall(CeedVectorGetArrayWrite(index_vec_in, CEED_MEM_HOST, &array)); 489*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < num_nodes_in; i++) array[i] = i; 490*506b1a0cSSebastian Grimberg CeedCall(CeedVectorRestoreArray(index_vec_in, &array)); 491*506b1a0cSSebastian Grimberg CeedCall(CeedVectorCreate(ceed, num_elem_in * elem_size_in * num_comp_in, &elem_dof_in)); 492*506b1a0cSSebastian Grimberg CeedCall(CeedVectorSetValue(elem_dof_in, 0.0)); 493*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionCreateUnorientedCopy(elem_rstr_in, &index_elem_rstr_in)); 494*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionApply(index_elem_rstr_in, CEED_NOTRANSPOSE, index_vec_in, elem_dof_in, CEED_REQUEST_IMMEDIATE)); 495*506b1a0cSSebastian Grimberg CeedCall(CeedVectorGetArrayRead(elem_dof_in, CEED_MEM_HOST, &elem_dof_a_in)); 496*506b1a0cSSebastian Grimberg CeedCall(CeedVectorDestroy(&index_vec_in)); 497*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionDestroy(&index_elem_rstr_in)); 498*506b1a0cSSebastian Grimberg 499*506b1a0cSSebastian Grimberg if (elem_rstr_in != elem_rstr_out) { 500*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetNumElements(elem_rstr_out, &num_elem_out)); 501*506b1a0cSSebastian Grimberg CeedCheck(num_elem_in == num_elem_out, ceed, CEED_ERROR_UNSUPPORTED, 502*506b1a0cSSebastian Grimberg "Active input and output operator restrictions must have the same number of elements"); 503*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetElementSize(elem_rstr_out, &elem_size_out)); 504*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetNumComponents(elem_rstr_out, &num_comp_out)); 505*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetELayout(elem_rstr_out, &layout_er_out)); 506*506b1a0cSSebastian Grimberg 507*506b1a0cSSebastian Grimberg // Determine elem_dof relation for output 508*506b1a0cSSebastian Grimberg CeedCall(CeedVectorCreate(ceed, num_nodes_out, &index_vec_out)); 509*506b1a0cSSebastian Grimberg CeedCall(CeedVectorGetArrayWrite(index_vec_out, CEED_MEM_HOST, &array)); 510*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < num_nodes_out; i++) array[i] = i; 511*506b1a0cSSebastian Grimberg CeedCall(CeedVectorRestoreArray(index_vec_out, &array)); 512*506b1a0cSSebastian Grimberg CeedCall(CeedVectorCreate(ceed, num_elem_out * elem_size_out * num_comp_out, &elem_dof_out)); 513*506b1a0cSSebastian Grimberg CeedCall(CeedVectorSetValue(elem_dof_out, 0.0)); 514*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionCreateUnorientedCopy(elem_rstr_out, &index_elem_rstr_out)); 515*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionApply(index_elem_rstr_out, CEED_NOTRANSPOSE, index_vec_out, elem_dof_out, CEED_REQUEST_IMMEDIATE)); 516*506b1a0cSSebastian Grimberg CeedCall(CeedVectorGetArrayRead(elem_dof_out, CEED_MEM_HOST, &elem_dof_a_out)); 517*506b1a0cSSebastian Grimberg CeedCall(CeedVectorDestroy(&index_vec_out)); 518*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionDestroy(&index_elem_rstr_out)); 519*506b1a0cSSebastian Grimberg } else { 520*506b1a0cSSebastian Grimberg num_elem_out = num_elem_in; 521*506b1a0cSSebastian Grimberg elem_size_out = elem_size_in; 522*506b1a0cSSebastian Grimberg num_comp_out = num_comp_in; 523*506b1a0cSSebastian Grimberg layout_er_out[0] = layout_er_in[0]; 524*506b1a0cSSebastian Grimberg layout_er_out[1] = layout_er_in[1]; 525*506b1a0cSSebastian Grimberg layout_er_out[2] = layout_er_in[2]; 526*506b1a0cSSebastian Grimberg elem_dof_a_out = elem_dof_a_in; 527*506b1a0cSSebastian Grimberg } 528*506b1a0cSSebastian Grimberg local_num_entries = elem_size_out * num_comp_out * elem_size_in * num_comp_in * num_elem_in; 529eaf62fffSJeremy L Thompson 530eaf62fffSJeremy L Thompson // Determine i, j locations for element matrices 531*506b1a0cSSebastian Grimberg for (CeedInt e = 0; e < num_elem_in; e++) { 532*506b1a0cSSebastian Grimberg for (CeedInt comp_in = 0; comp_in < num_comp_in; comp_in++) { 533*506b1a0cSSebastian Grimberg for (CeedInt comp_out = 0; comp_out < num_comp_out; comp_out++) { 534*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < elem_size_out; i++) { 535*506b1a0cSSebastian Grimberg for (CeedInt j = 0; j < elem_size_in; j++) { 536*506b1a0cSSebastian Grimberg const CeedInt elem_dof_index_row = i * layout_er_out[0] + comp_out * layout_er_out[1] + e * layout_er_out[2]; 537*506b1a0cSSebastian Grimberg const CeedInt elem_dof_index_col = j * layout_er_in[0] + comp_in * layout_er_in[1] + e * layout_er_in[2]; 538*506b1a0cSSebastian Grimberg const CeedInt row = elem_dof_a_out[elem_dof_index_row]; 539*506b1a0cSSebastian Grimberg const CeedInt col = elem_dof_a_in[elem_dof_index_col]; 540eaf62fffSJeremy L Thompson 541eaf62fffSJeremy L Thompson rows[offset + count] = row; 542eaf62fffSJeremy L Thompson cols[offset + count] = col; 543eaf62fffSJeremy L Thompson count++; 544eaf62fffSJeremy L Thompson } 545eaf62fffSJeremy L Thompson } 546eaf62fffSJeremy L Thompson } 547eaf62fffSJeremy L Thompson } 548eaf62fffSJeremy L Thompson } 5496574a04fSJeremy L Thompson CeedCheck(count == local_num_entries, ceed, CEED_ERROR_MAJOR, "Error computing assembled entries"); 550*506b1a0cSSebastian Grimberg CeedCall(CeedVectorRestoreArrayRead(elem_dof_in, &elem_dof_a_in)); 551*506b1a0cSSebastian Grimberg CeedCall(CeedVectorDestroy(&elem_dof_in)); 552*506b1a0cSSebastian Grimberg if (elem_rstr_in != elem_rstr_out) { 553*506b1a0cSSebastian Grimberg CeedCall(CeedVectorRestoreArrayRead(elem_dof_out, &elem_dof_a_out)); 554*506b1a0cSSebastian Grimberg CeedCall(CeedVectorDestroy(&elem_dof_out)); 555*506b1a0cSSebastian Grimberg } 556eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 557eaf62fffSJeremy L Thompson } 558eaf62fffSJeremy L Thompson 559eaf62fffSJeremy L Thompson /** 560eaf62fffSJeremy L Thompson @brief Assemble nonzero entries for non-composite operator 561eaf62fffSJeremy L Thompson 562eaf62fffSJeremy L Thompson Users should generally use CeedOperatorLinearAssemble() 563eaf62fffSJeremy L Thompson 564eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 565ea61e9acSJeremy L Thompson @param[in] offset Offset for number of entries 566eaf62fffSJeremy L Thompson @param[out] values Values to assemble into matrix 567eaf62fffSJeremy L Thompson 568eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 569eaf62fffSJeremy L Thompson 570eaf62fffSJeremy L Thompson @ref Developer 571eaf62fffSJeremy L Thompson **/ 5722b730f8bSJeremy L Thompson static int CeedSingleOperatorAssemble(CeedOperator op, CeedInt offset, CeedVector values) { 573f3d47e36SJeremy L Thompson Ceed ceed; 574f3d47e36SJeremy L Thompson bool is_composite; 5751c66c397SJeremy L Thompson 576f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 577f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 5786574a04fSJeremy L Thompson CeedCheck(!is_composite, ceed, CEED_ERROR_UNSUPPORTED, "Composite operator not supported"); 579f3d47e36SJeremy L Thompson 580f3d47e36SJeremy L Thompson // Early exit for empty operator 581f3d47e36SJeremy L Thompson { 582f3d47e36SJeremy L Thompson CeedInt num_elem = 0; 583f3d47e36SJeremy L Thompson 584f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 585f3d47e36SJeremy L Thompson if (num_elem == 0) return CEED_ERROR_SUCCESS; 586f3d47e36SJeremy L Thompson } 587eaf62fffSJeremy L Thompson 588cefa2673SJeremy L Thompson if (op->LinearAssembleSingle) { 589cefa2673SJeremy L Thompson // Backend version 5902b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleSingle(op, offset, values)); 591cefa2673SJeremy L Thompson return CEED_ERROR_SUCCESS; 592cefa2673SJeremy L Thompson } else { 593cefa2673SJeremy L Thompson // Operator fallback 594cefa2673SJeremy L Thompson CeedOperator op_fallback; 595cefa2673SJeremy L Thompson 5962b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 597cefa2673SJeremy L Thompson if (op_fallback) { 5982b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemble(op_fallback, offset, values)); 599cefa2673SJeremy L Thompson return CEED_ERROR_SUCCESS; 600cefa2673SJeremy L Thompson } 601cefa2673SJeremy L Thompson } 602cefa2673SJeremy L Thompson 603eaf62fffSJeremy L Thompson // Assemble QFunction 604*506b1a0cSSebastian Grimberg CeedInt layout_qf[3]; 6051c66c397SJeremy L Thompson const CeedScalar *assembled_qf_array; 606c5f45aeaSJeremy L Thompson CeedVector assembled_qf = NULL; 607*506b1a0cSSebastian Grimberg CeedElemRestriction assembled_elem_rstr = NULL; 608eaf62fffSJeremy L Thompson 609*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled_qf, &assembled_elem_rstr, CEED_REQUEST_IMMEDIATE)); 610*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetELayout(assembled_elem_rstr, &layout_qf)); 611*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionDestroy(&assembled_elem_rstr)); 612*506b1a0cSSebastian Grimberg CeedCall(CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array)); 613eaf62fffSJeremy L Thompson 614ed9e99e6SJeremy L Thompson // Get assembly data 615*506b1a0cSSebastian Grimberg CeedInt num_elem_in, elem_size_in, num_comp_in, num_qpts_in; 616*506b1a0cSSebastian Grimberg CeedInt num_elem_out, elem_size_out, num_comp_out, num_qpts_out, local_num_entries; 617*506b1a0cSSebastian Grimberg const CeedEvalMode **eval_modes_in, **eval_modes_out; 618*506b1a0cSSebastian Grimberg CeedInt num_active_bases_in, *num_eval_modes_in, num_active_bases_out, *num_eval_modes_out; 619*506b1a0cSSebastian Grimberg CeedBasis *active_bases_in, *active_bases_out, basis_in, basis_out; 620*506b1a0cSSebastian Grimberg const CeedScalar **B_mats_in, **B_mats_out, *B_mat_in, *B_mat_out; 621*506b1a0cSSebastian Grimberg CeedElemRestriction elem_rstr_in, elem_rstr_out; 622*506b1a0cSSebastian Grimberg CeedRestrictionType elem_rstr_type_in, elem_rstr_type_out; 623*506b1a0cSSebastian Grimberg const bool *elem_rstr_orients_in = NULL, *elem_rstr_orients_out = NULL; 624*506b1a0cSSebastian Grimberg const CeedInt8 *elem_rstr_curl_orients_in = NULL, *elem_rstr_curl_orients_out = NULL; 625*506b1a0cSSebastian Grimberg CeedOperatorAssemblyData data; 626eaf62fffSJeremy L Thompson 627*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorGetOperatorAssemblyData(op, &data)); 628*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorAssemblyDataGetEvalModes(data, &num_active_bases_in, &num_eval_modes_in, &eval_modes_in, NULL, &num_active_bases_out, 629*506b1a0cSSebastian Grimberg &num_eval_modes_out, &eval_modes_out, NULL, NULL)); 630*506b1a0cSSebastian Grimberg 631*506b1a0cSSebastian Grimberg CeedCheck(num_active_bases_in == num_active_bases_out && num_active_bases_in == 1, ceed, CEED_ERROR_UNSUPPORTED, 632*506b1a0cSSebastian Grimberg "Cannot assemble operator with multiple active bases"); 6336574a04fSJeremy L Thompson CeedCheck(num_eval_modes_in[0] > 0 && num_eval_modes_out[0] > 0, ceed, CEED_ERROR_UNSUPPORTED, "Cannot assemble operator without inputs/outputs"); 634eaf62fffSJeremy L Thompson 635*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorAssemblyDataGetBases(data, NULL, &active_bases_in, &B_mats_in, NULL, &active_bases_out, &B_mats_out)); 636*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorGetActiveElemRestrictions(op, &elem_rstr_in, &elem_rstr_out)); 637*506b1a0cSSebastian Grimberg basis_in = active_bases_in[0]; 638*506b1a0cSSebastian Grimberg basis_out = active_bases_out[0]; 639*506b1a0cSSebastian Grimberg B_mat_in = B_mats_in[0]; 640*506b1a0cSSebastian Grimberg B_mat_out = B_mats_out[0]; 641eaf62fffSJeremy L Thompson 642*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetNumElements(elem_rstr_in, &num_elem_in)); 643*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetElementSize(elem_rstr_in, &elem_size_in)); 644*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetNumComponents(elem_rstr_in, &num_comp_in)); 645*506b1a0cSSebastian Grimberg if (basis_in == CEED_BASIS_NONE) num_qpts_in = elem_size_in; 646*506b1a0cSSebastian Grimberg else CeedCall(CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts_in)); 647*506b1a0cSSebastian Grimberg 648*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetType(elem_rstr_in, &elem_rstr_type_in)); 649*506b1a0cSSebastian Grimberg if (elem_rstr_type_in == CEED_RESTRICTION_ORIENTED) { 650*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetOrientations(elem_rstr_in, CEED_MEM_HOST, &elem_rstr_orients_in)); 651*506b1a0cSSebastian Grimberg } else if (elem_rstr_type_in == CEED_RESTRICTION_CURL_ORIENTED) { 652*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetCurlOrientations(elem_rstr_in, CEED_MEM_HOST, &elem_rstr_curl_orients_in)); 6537c1dbaffSSebastian Grimberg } 6547c1dbaffSSebastian Grimberg 655*506b1a0cSSebastian Grimberg if (elem_rstr_in != elem_rstr_out) { 656*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetNumElements(elem_rstr_out, &num_elem_out)); 657*506b1a0cSSebastian Grimberg CeedCheck(num_elem_in == num_elem_out, ceed, CEED_ERROR_UNSUPPORTED, 658*506b1a0cSSebastian Grimberg "Active input and output operator restrictions must have the same number of elements"); 659*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetElementSize(elem_rstr_out, &elem_size_out)); 660*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetNumComponents(elem_rstr_out, &num_comp_out)); 661*506b1a0cSSebastian Grimberg if (basis_out == CEED_BASIS_NONE) num_qpts_out = elem_size_out; 662*506b1a0cSSebastian Grimberg else CeedCall(CeedBasisGetNumQuadraturePoints(basis_out, &num_qpts_out)); 663*506b1a0cSSebastian Grimberg CeedCheck(num_qpts_in == num_qpts_out, ceed, CEED_ERROR_UNSUPPORTED, 664*506b1a0cSSebastian Grimberg "Active input and output bases must have the same number of quadrature points"); 665eaf62fffSJeremy L Thompson 666*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetType(elem_rstr_out, &elem_rstr_type_out)); 667*506b1a0cSSebastian Grimberg if (elem_rstr_type_out == CEED_RESTRICTION_ORIENTED) { 668*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetOrientations(elem_rstr_out, CEED_MEM_HOST, &elem_rstr_orients_out)); 669*506b1a0cSSebastian Grimberg } else if (elem_rstr_type_out == CEED_RESTRICTION_CURL_ORIENTED) { 670*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetCurlOrientations(elem_rstr_out, CEED_MEM_HOST, &elem_rstr_curl_orients_out)); 671*506b1a0cSSebastian Grimberg } 672*506b1a0cSSebastian Grimberg } else { 673*506b1a0cSSebastian Grimberg num_elem_out = num_elem_in; 674*506b1a0cSSebastian Grimberg elem_size_out = elem_size_in; 675*506b1a0cSSebastian Grimberg num_comp_out = num_comp_in; 676*506b1a0cSSebastian Grimberg num_qpts_out = num_qpts_in; 677*506b1a0cSSebastian Grimberg 678*506b1a0cSSebastian Grimberg elem_rstr_orients_out = elem_rstr_orients_in; 679*506b1a0cSSebastian Grimberg elem_rstr_curl_orients_out = elem_rstr_curl_orients_in; 680*506b1a0cSSebastian Grimberg } 681*506b1a0cSSebastian Grimberg local_num_entries = elem_size_out * num_comp_out * elem_size_in * num_comp_in * num_elem_in; 682*506b1a0cSSebastian Grimberg 683*506b1a0cSSebastian Grimberg // Loop over elements and put in data structure 6847c1dbaffSSebastian Grimberg // We store B_mat_in, B_mat_out, BTD, elem_mat in row-major order 6851c66c397SJeremy L Thompson CeedSize count = 0; 686*506b1a0cSSebastian Grimberg CeedScalar *vals, BTD_mat[elem_size_out * num_qpts_in * num_eval_modes_in[0]], elem_mat[elem_size_out * elem_size_in], *elem_mat_b = NULL; 687*506b1a0cSSebastian Grimberg 688*506b1a0cSSebastian Grimberg if (elem_rstr_curl_orients_in || elem_rstr_curl_orients_out) CeedCall(CeedCalloc(elem_size_out * elem_size_in, &elem_mat_b)); 6891c66c397SJeremy L Thompson 69028ec399dSJeremy L Thompson CeedCall(CeedVectorGetArray(values, CEED_MEM_HOST, &vals)); 691*506b1a0cSSebastian Grimberg for (CeedSize e = 0; e < num_elem_in; e++) { 692*506b1a0cSSebastian Grimberg for (CeedInt comp_in = 0; comp_in < num_comp_in; comp_in++) { 693*506b1a0cSSebastian Grimberg for (CeedInt comp_out = 0; comp_out < num_comp_out; comp_out++) { 694ed9e99e6SJeremy L Thompson // Compute B^T*D 695*506b1a0cSSebastian Grimberg for (CeedSize n = 0; n < elem_size_out; n++) { 696*506b1a0cSSebastian Grimberg for (CeedSize q = 0; q < num_qpts_in; q++) { 697437c7c90SJeremy L Thompson for (CeedInt e_in = 0; e_in < num_eval_modes_in[0]; e_in++) { 698*506b1a0cSSebastian Grimberg const CeedSize btd_index = n * (num_qpts_in * num_eval_modes_in[0]) + q * num_eval_modes_in[0] + e_in; 699067fd99fSJeremy L Thompson CeedScalar sum = 0.0; 7001c66c397SJeremy L Thompson 701437c7c90SJeremy L Thompson for (CeedInt e_out = 0; e_out < num_eval_modes_out[0]; e_out++) { 702*506b1a0cSSebastian Grimberg const CeedSize b_out_index = (q * num_eval_modes_out[0] + e_out) * elem_size_out + n; 703*506b1a0cSSebastian Grimberg const CeedSize eval_mode_index = ((e_in * num_comp_in + comp_in) * num_eval_modes_out[0] + e_out) * num_comp_out + comp_out; 704b94338b9SJed Brown const CeedSize qf_index = q * layout_qf[0] + eval_mode_index * layout_qf[1] + e * layout_qf[2]; 7051c66c397SJeremy L Thompson 706067fd99fSJeremy L Thompson sum += B_mat_out[b_out_index] * assembled_qf_array[qf_index]; 707eaf62fffSJeremy L Thompson } 708067fd99fSJeremy L Thompson BTD_mat[btd_index] = sum; 709ed9e99e6SJeremy L Thompson } 710ed9e99e6SJeremy L Thompson } 711eaf62fffSJeremy L Thompson } 7127c1dbaffSSebastian Grimberg 7137c1dbaffSSebastian Grimberg // Form element matrix itself (for each block component) 714*506b1a0cSSebastian Grimberg CeedCall(CeedMatrixMatrixMultiply(ceed, BTD_mat, B_mat_in, elem_mat, elem_size_out, elem_size_in, num_qpts_in * num_eval_modes_in[0])); 715eaf62fffSJeremy L Thompson 7167c1dbaffSSebastian Grimberg // Transform the element matrix if required 717*506b1a0cSSebastian Grimberg if (elem_rstr_orients_out) { 718*506b1a0cSSebastian Grimberg const bool *elem_orients = &elem_rstr_orients_out[e * elem_size_out]; 7191c66c397SJeremy L Thompson 720*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < elem_size_out; i++) { 721*506b1a0cSSebastian Grimberg const double orient = elem_orients[i] ? -1.0 : 1.0; 722*506b1a0cSSebastian Grimberg 723*506b1a0cSSebastian Grimberg for (CeedInt j = 0; j < elem_size_in; j++) { 724*506b1a0cSSebastian Grimberg elem_mat[i * elem_size_in + j] *= orient; 7257c1dbaffSSebastian Grimberg } 7267c1dbaffSSebastian Grimberg } 727*506b1a0cSSebastian Grimberg } else if (elem_rstr_curl_orients_out) { 728*506b1a0cSSebastian Grimberg const CeedInt8 *elem_curl_orients = &elem_rstr_curl_orients_out[e * 3 * elem_size_out]; 7291c66c397SJeremy L Thompson 7307c1dbaffSSebastian Grimberg // T^T*(B^T*D*B) 731*506b1a0cSSebastian Grimberg memcpy(elem_mat_b, elem_mat, elem_size_out * elem_size_in * sizeof(CeedScalar)); 732*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < elem_size_out; i++) { 733*506b1a0cSSebastian Grimberg for (CeedInt j = 0; j < elem_size_in; j++) { 734*506b1a0cSSebastian Grimberg elem_mat[i * elem_size_in + j] = elem_mat_b[i * elem_size_in + j] * elem_curl_orients[3 * i + 1] + 735*506b1a0cSSebastian Grimberg (i > 0 ? elem_mat_b[(i - 1) * elem_size_in + j] * elem_curl_orients[3 * i - 1] : 0.0) + 736*506b1a0cSSebastian Grimberg (i < elem_size_out - 1 ? elem_mat_b[(i + 1) * elem_size_in + j] * elem_curl_orients[3 * i + 3] : 0.0); 7377c1dbaffSSebastian Grimberg } 7387c1dbaffSSebastian Grimberg } 739*506b1a0cSSebastian Grimberg } 740*506b1a0cSSebastian Grimberg if (elem_rstr_orients_in) { 741*506b1a0cSSebastian Grimberg const bool *elem_orients = &elem_rstr_orients_in[e * elem_size_in]; 742*506b1a0cSSebastian Grimberg 743*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < elem_size_out; i++) { 744*506b1a0cSSebastian Grimberg for (CeedInt j = 0; j < elem_size_in; j++) { 745*506b1a0cSSebastian Grimberg elem_mat[i * elem_size_in + j] *= elem_orients[j] ? -1.0 : 1.0; 746*506b1a0cSSebastian Grimberg } 747*506b1a0cSSebastian Grimberg } 748*506b1a0cSSebastian Grimberg } else if (elem_rstr_curl_orients_in) { 749*506b1a0cSSebastian Grimberg const CeedInt8 *elem_curl_orients = &elem_rstr_curl_orients_in[e * 3 * elem_size_in]; 750*506b1a0cSSebastian Grimberg 751*506b1a0cSSebastian Grimberg // (B^T*D*B)*T 752*506b1a0cSSebastian Grimberg memcpy(elem_mat_b, elem_mat, elem_size_out * elem_size_in * sizeof(CeedScalar)); 753*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < elem_size_out; i++) { 754*506b1a0cSSebastian Grimberg for (CeedInt j = 0; j < elem_size_in; j++) { 755*506b1a0cSSebastian Grimberg elem_mat[i * elem_size_in + j] = elem_mat_b[i * elem_size_in + j] * elem_curl_orients[3 * j + 1] + 756*506b1a0cSSebastian Grimberg (j > 0 ? elem_mat_b[i * elem_size_in + j - 1] * elem_curl_orients[3 * j - 1] : 0.0) + 757*506b1a0cSSebastian Grimberg (j < elem_size_in - 1 ? elem_mat_b[i * elem_size_in + j + 1] * elem_curl_orients[3 * j + 3] : 0.0); 7587c1dbaffSSebastian Grimberg } 7597c1dbaffSSebastian Grimberg } 7607c1dbaffSSebastian Grimberg } 7617c1dbaffSSebastian Grimberg 7627c1dbaffSSebastian Grimberg // Put element matrix in coordinate data structure 763*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < elem_size_out; i++) { 764*506b1a0cSSebastian Grimberg for (CeedInt j = 0; j < elem_size_in; j++) { 765*506b1a0cSSebastian Grimberg vals[offset + count] = elem_mat[i * elem_size_in + j]; 766eaf62fffSJeremy L Thompson count++; 767eaf62fffSJeremy L Thompson } 768eaf62fffSJeremy L Thompson } 769eaf62fffSJeremy L Thompson } 770eaf62fffSJeremy L Thompson } 771eaf62fffSJeremy L Thompson } 7726574a04fSJeremy L Thompson CeedCheck(count == local_num_entries, ceed, CEED_ERROR_MAJOR, "Error computing entries"); 7732b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArray(values, &vals)); 774eaf62fffSJeremy L Thompson 775*506b1a0cSSebastian Grimberg // Cleanup 776*506b1a0cSSebastian Grimberg CeedCall(CeedFree(&elem_mat_b)); 777*506b1a0cSSebastian Grimberg if (elem_rstr_type_in == CEED_RESTRICTION_ORIENTED) { 778*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionRestoreOrientations(elem_rstr_in, &elem_rstr_orients_in)); 779*506b1a0cSSebastian Grimberg } else if (elem_rstr_type_in == CEED_RESTRICTION_CURL_ORIENTED) { 780*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionRestoreCurlOrientations(elem_rstr_in, &elem_rstr_curl_orients_in)); 781*506b1a0cSSebastian Grimberg } 782*506b1a0cSSebastian Grimberg if (elem_rstr_in != elem_rstr_out) { 783*506b1a0cSSebastian Grimberg if (elem_rstr_type_out == CEED_RESTRICTION_ORIENTED) { 784*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionRestoreOrientations(elem_rstr_out, &elem_rstr_orients_out)); 785*506b1a0cSSebastian Grimberg } else if (elem_rstr_type_out == CEED_RESTRICTION_CURL_ORIENTED) { 786*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionRestoreCurlOrientations(elem_rstr_out, &elem_rstr_curl_orients_out)); 787*506b1a0cSSebastian Grimberg } 788*506b1a0cSSebastian Grimberg } 7892b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array)); 7902b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&assembled_qf)); 791eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 792eaf62fffSJeremy L Thompson } 793eaf62fffSJeremy L Thompson 794eaf62fffSJeremy L Thompson /** 795eaf62fffSJeremy L Thompson @brief Count number of entries for assembled CeedOperator 796eaf62fffSJeremy L Thompson 797eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 798eaf62fffSJeremy L Thompson @param[out] num_entries Number of entries in assembled representation 799eaf62fffSJeremy L Thompson 800eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 801eaf62fffSJeremy L Thompson 802eaf62fffSJeremy L Thompson @ref Utility 803eaf62fffSJeremy L Thompson **/ 804b94338b9SJed Brown static int CeedSingleOperatorAssemblyCountEntries(CeedOperator op, CeedSize *num_entries) { 805b275c451SJeremy L Thompson bool is_composite; 806*506b1a0cSSebastian Grimberg CeedInt num_elem_in, elem_size_in, num_comp_in, num_elem_out, elem_size_out, num_comp_out; 807*506b1a0cSSebastian Grimberg CeedElemRestriction rstr_in, rstr_out; 808eaf62fffSJeremy L Thompson 809b275c451SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 8106574a04fSJeremy L Thompson CeedCheck(!is_composite, op->ceed, CEED_ERROR_UNSUPPORTED, "Composite operator not supported"); 811*506b1a0cSSebastian Grimberg 812*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorGetActiveElemRestrictions(op, &rstr_in, &rstr_out)); 813*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetNumElements(rstr_in, &num_elem_in)); 814*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetElementSize(rstr_in, &elem_size_in)); 815*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetNumComponents(rstr_in, &num_comp_in)); 816*506b1a0cSSebastian Grimberg if (rstr_in != rstr_out) { 817*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetNumElements(rstr_out, &num_elem_out)); 818*506b1a0cSSebastian Grimberg CeedCheck(num_elem_in == num_elem_out, op->ceed, CEED_ERROR_UNSUPPORTED, 819*506b1a0cSSebastian Grimberg "Active input and output operator restrictions must have the same number of elements"); 820*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetElementSize(rstr_out, &elem_size_out)); 821*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetNumComponents(rstr_out, &num_comp_out)); 822*506b1a0cSSebastian Grimberg } else { 823*506b1a0cSSebastian Grimberg num_elem_out = num_elem_in; 824*506b1a0cSSebastian Grimberg elem_size_out = elem_size_in; 825*506b1a0cSSebastian Grimberg num_comp_out = num_comp_in; 826*506b1a0cSSebastian Grimberg } 827*506b1a0cSSebastian Grimberg *num_entries = (CeedSize)elem_size_in * num_comp_in * elem_size_out * num_comp_out * num_elem_in; 828eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 829eaf62fffSJeremy L Thompson } 830eaf62fffSJeremy L Thompson 831eaf62fffSJeremy L Thompson /** 832ea61e9acSJeremy L Thompson @brief Common code for creating a multigrid coarse operator and level transfer operators for a CeedOperator 833eaf62fffSJeremy L Thompson 834eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 83585bb9dcfSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter, or NULL if not creating prolongation/restriction operators 836eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 837eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 83885bb9dcfSJeremy L Thompson @param[in] basis_c_to_f Basis for coarse to fine interpolation, or NULL if not creating prolongation/restriction operators 839eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 84085bb9dcfSJeremy L Thompson @param[out] op_prolong Coarse to fine operator, or NULL 8417758292fSSebastian Grimberg @param[out] op_restrict Fine to coarse operator, or NULL 842eaf62fffSJeremy L Thompson 843eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 844eaf62fffSJeremy L Thompson 845eaf62fffSJeremy L Thompson @ref Developer 846eaf62fffSJeremy L Thompson **/ 8472b730f8bSJeremy L Thompson static int CeedSingleOperatorMultigridLevel(CeedOperator op_fine, CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 8487758292fSSebastian Grimberg CeedBasis basis_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong, CeedOperator *op_restrict) { 8491c66c397SJeremy L Thompson bool is_composite; 850eaf62fffSJeremy L Thompson Ceed ceed; 8511c66c397SJeremy L Thompson CeedInt num_comp; 85285bb9dcfSJeremy L Thompson CeedVector mult_vec = NULL; 8531c66c397SJeremy L Thompson CeedElemRestriction rstr_p_mult_fine = NULL, rstr_fine = NULL; 8541c66c397SJeremy L Thompson 8552b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op_fine, &ceed)); 856eaf62fffSJeremy L Thompson 857eaf62fffSJeremy L Thompson // Check for composite operator 8582b730f8bSJeremy L Thompson CeedCall(CeedOperatorIsComposite(op_fine, &is_composite)); 8596574a04fSJeremy L Thompson CeedCheck(!is_composite, ceed, CEED_ERROR_UNSUPPORTED, "Automatic multigrid setup for composite operators not supported"); 860eaf62fffSJeremy L Thompson 861eaf62fffSJeremy L Thompson // Coarse Grid 8622b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(ceed, op_fine->qf, op_fine->dqf, op_fine->dqfT, op_coarse)); 863eaf62fffSJeremy L Thompson // -- Clone input fields 86492ae7e47SJeremy L Thompson for (CeedInt i = 0; i < op_fine->qf->num_input_fields; i++) { 865eaf62fffSJeremy L Thompson if (op_fine->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 866437c7c90SJeremy L Thompson rstr_fine = op_fine->input_fields[i]->elem_rstr; 8672b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name, rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE)); 868eaf62fffSJeremy L Thompson } else { 869437c7c90SJeremy L Thompson CeedCall(CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name, op_fine->input_fields[i]->elem_rstr, 8702b730f8bSJeremy L Thompson op_fine->input_fields[i]->basis, op_fine->input_fields[i]->vec)); 871eaf62fffSJeremy L Thompson } 872eaf62fffSJeremy L Thompson } 873eaf62fffSJeremy L Thompson // -- Clone output fields 87492ae7e47SJeremy L Thompson for (CeedInt i = 0; i < op_fine->qf->num_output_fields; i++) { 875eaf62fffSJeremy L Thompson if (op_fine->output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 8762b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name, rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE)); 877eaf62fffSJeremy L Thompson } else { 878437c7c90SJeremy L Thompson CeedCall(CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name, op_fine->output_fields[i]->elem_rstr, 8792b730f8bSJeremy L Thompson op_fine->output_fields[i]->basis, op_fine->output_fields[i]->vec)); 880eaf62fffSJeremy L Thompson } 881eaf62fffSJeremy L Thompson } 882af99e877SJeremy L Thompson // -- Clone QFunctionAssemblyData 8832b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataReferenceCopy(op_fine->qf_assembled, &(*op_coarse)->qf_assembled)); 884eaf62fffSJeremy L Thompson 885eaf62fffSJeremy L Thompson // Multiplicity vector 8867758292fSSebastian Grimberg if (op_restrict || op_prolong) { 88785bb9dcfSJeremy L Thompson CeedVector mult_e_vec; 8881c66c397SJeremy L Thompson CeedRestrictionType rstr_type; 88985bb9dcfSJeremy L Thompson 8907c1dbaffSSebastian Grimberg CeedCall(CeedElemRestrictionGetType(rstr_fine, &rstr_type)); 8917c1dbaffSSebastian Grimberg CeedCheck(rstr_type != CEED_RESTRICTION_CURL_ORIENTED, ceed, CEED_ERROR_UNSUPPORTED, 8927c1dbaffSSebastian Grimberg "Element restrictions created with CeedElemRestrictionCreateCurlOriented are not supported"); 8936574a04fSJeremy L Thompson CeedCheck(p_mult_fine, ceed, CEED_ERROR_INCOMPATIBLE, "Prolongation or restriction operator creation requires fine grid multiplicity vector"); 8947c1dbaffSSebastian Grimberg CeedCall(CeedElemRestrictionCreateUnsignedCopy(rstr_fine, &rstr_p_mult_fine)); 8952b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionCreateVector(rstr_fine, &mult_vec, &mult_e_vec)); 8962b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(mult_e_vec, 0.0)); 897c17ec2beSJeremy L Thompson CeedCall(CeedElemRestrictionApply(rstr_p_mult_fine, CEED_NOTRANSPOSE, p_mult_fine, mult_e_vec, CEED_REQUEST_IMMEDIATE)); 8982b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(mult_vec, 0.0)); 899c17ec2beSJeremy L Thompson CeedCall(CeedElemRestrictionApply(rstr_p_mult_fine, CEED_TRANSPOSE, mult_e_vec, mult_vec, CEED_REQUEST_IMMEDIATE)); 9002b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&mult_e_vec)); 9012b730f8bSJeremy L Thompson CeedCall(CeedVectorReciprocal(mult_vec)); 90285bb9dcfSJeremy L Thompson } 903eaf62fffSJeremy L Thompson 904addd79feSZach Atkins // Clone name 905addd79feSZach Atkins bool has_name = op_fine->name; 906addd79feSZach Atkins size_t name_len = op_fine->name ? strlen(op_fine->name) : 0; 907addd79feSZach Atkins CeedCall(CeedOperatorSetName(*op_coarse, op_fine->name)); 908addd79feSZach Atkins 9097758292fSSebastian Grimberg // Check that coarse to fine basis is provided if prolong/restrict operators are requested 9107758292fSSebastian Grimberg CeedCheck(basis_c_to_f || (!op_restrict && !op_prolong), ceed, CEED_ERROR_INCOMPATIBLE, 9116574a04fSJeremy L Thompson "Prolongation or restriction operator creation requires coarse-to-fine basis"); 91283d6adf3SZach Atkins 91385bb9dcfSJeremy L Thompson // Restriction/Prolongation Operators 9142b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumComponents(basis_coarse, &num_comp)); 915addd79feSZach Atkins 916addd79feSZach Atkins // Restriction 9177758292fSSebastian Grimberg if (op_restrict) { 918eaf62fffSJeremy L Thompson CeedInt *num_comp_r_data; 91985bb9dcfSJeremy L Thompson CeedQFunctionContext ctx_r; 9207758292fSSebastian Grimberg CeedQFunction qf_restrict; 92185bb9dcfSJeremy L Thompson 9227758292fSSebastian Grimberg CeedCall(CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_restrict)); 9232b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, &num_comp_r_data)); 924eaf62fffSJeremy L Thompson num_comp_r_data[0] = num_comp; 9252b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextCreate(ceed, &ctx_r)); 9262b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextSetData(ctx_r, CEED_MEM_HOST, CEED_OWN_POINTER, sizeof(*num_comp_r_data), num_comp_r_data)); 9277758292fSSebastian Grimberg CeedCall(CeedQFunctionSetContext(qf_restrict, ctx_r)); 9282b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextDestroy(&ctx_r)); 9297758292fSSebastian Grimberg CeedCall(CeedQFunctionAddInput(qf_restrict, "input", num_comp, CEED_EVAL_NONE)); 9307758292fSSebastian Grimberg CeedCall(CeedQFunctionAddInput(qf_restrict, "scale", num_comp, CEED_EVAL_NONE)); 9317758292fSSebastian Grimberg CeedCall(CeedQFunctionAddOutput(qf_restrict, "output", num_comp, CEED_EVAL_INTERP)); 9327758292fSSebastian Grimberg CeedCall(CeedQFunctionSetUserFlopsEstimate(qf_restrict, num_comp)); 933eaf62fffSJeremy L Thompson 9347758292fSSebastian Grimberg CeedCall(CeedOperatorCreate(ceed, qf_restrict, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, op_restrict)); 9357758292fSSebastian Grimberg CeedCall(CeedOperatorSetField(*op_restrict, "input", rstr_fine, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE)); 9367758292fSSebastian Grimberg CeedCall(CeedOperatorSetField(*op_restrict, "scale", rstr_p_mult_fine, CEED_BASIS_NONE, mult_vec)); 9377758292fSSebastian Grimberg CeedCall(CeedOperatorSetField(*op_restrict, "output", rstr_coarse, basis_c_to_f, CEED_VECTOR_ACTIVE)); 938eaf62fffSJeremy L Thompson 939addd79feSZach Atkins // Set name 940addd79feSZach Atkins char *restriction_name; 9411c66c397SJeremy L Thompson 942addd79feSZach Atkins CeedCall(CeedCalloc(17 + name_len, &restriction_name)); 943addd79feSZach Atkins sprintf(restriction_name, "restriction%s%s", has_name ? " for " : "", has_name ? op_fine->name : ""); 9447758292fSSebastian Grimberg CeedCall(CeedOperatorSetName(*op_restrict, restriction_name)); 945addd79feSZach Atkins CeedCall(CeedFree(&restriction_name)); 946addd79feSZach Atkins 947addd79feSZach Atkins // Check 9487758292fSSebastian Grimberg CeedCall(CeedOperatorCheckReady(*op_restrict)); 949addd79feSZach Atkins 950addd79feSZach Atkins // Cleanup 9517758292fSSebastian Grimberg CeedCall(CeedQFunctionDestroy(&qf_restrict)); 952addd79feSZach Atkins } 953addd79feSZach Atkins 954eaf62fffSJeremy L Thompson // Prolongation 955addd79feSZach Atkins if (op_prolong) { 956eaf62fffSJeremy L Thompson CeedInt *num_comp_p_data; 95785bb9dcfSJeremy L Thompson CeedQFunctionContext ctx_p; 9581c66c397SJeremy L Thompson CeedQFunction qf_prolong; 95985bb9dcfSJeremy L Thompson 96085bb9dcfSJeremy L Thompson CeedCall(CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_prolong)); 9612b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, &num_comp_p_data)); 962eaf62fffSJeremy L Thompson num_comp_p_data[0] = num_comp; 9632b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextCreate(ceed, &ctx_p)); 9642b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextSetData(ctx_p, CEED_MEM_HOST, CEED_OWN_POINTER, sizeof(*num_comp_p_data), num_comp_p_data)); 9652b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetContext(qf_prolong, ctx_p)); 9662b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextDestroy(&ctx_p)); 9672b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_prolong, "input", num_comp, CEED_EVAL_INTERP)); 9682b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_prolong, "scale", num_comp, CEED_EVAL_NONE)); 9692b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddOutput(qf_prolong, "output", num_comp, CEED_EVAL_NONE)); 9702b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetUserFlopsEstimate(qf_prolong, num_comp)); 971eaf62fffSJeremy L Thompson 9722b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(ceed, qf_prolong, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, op_prolong)); 9732b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_prolong, "input", rstr_coarse, basis_c_to_f, CEED_VECTOR_ACTIVE)); 974356036faSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_prolong, "scale", rstr_p_mult_fine, CEED_BASIS_NONE, mult_vec)); 975356036faSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_prolong, "output", rstr_fine, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE)); 976eaf62fffSJeremy L Thompson 977addd79feSZach Atkins // Set name 978ea6b5821SJeremy L Thompson char *prolongation_name; 9791c66c397SJeremy L Thompson 9802b730f8bSJeremy L Thompson CeedCall(CeedCalloc(18 + name_len, &prolongation_name)); 9812b730f8bSJeremy L Thompson sprintf(prolongation_name, "prolongation%s%s", has_name ? " for " : "", has_name ? op_fine->name : ""); 9822b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetName(*op_prolong, prolongation_name)); 9832b730f8bSJeremy L Thompson CeedCall(CeedFree(&prolongation_name)); 984addd79feSZach Atkins 985addd79feSZach Atkins // Check 986addd79feSZach Atkins CeedCall(CeedOperatorCheckReady(*op_prolong)); 987addd79feSZach Atkins 988addd79feSZach Atkins // Cleanup 989addd79feSZach Atkins CeedCall(CeedQFunctionDestroy(&qf_prolong)); 990ea6b5821SJeremy L Thompson } 991ea6b5821SJeremy L Thompson 99258e4b056SJeremy L Thompson // Check 99358e4b056SJeremy L Thompson CeedCall(CeedOperatorCheckReady(*op_coarse)); 99458e4b056SJeremy L Thompson 995eaf62fffSJeremy L Thompson // Cleanup 9962b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&mult_vec)); 997c17ec2beSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&rstr_p_mult_fine)); 9982b730f8bSJeremy L Thompson CeedCall(CeedBasisDestroy(&basis_c_to_f)); 999eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1000eaf62fffSJeremy L Thompson } 1001eaf62fffSJeremy L Thompson 1002eaf62fffSJeremy L Thompson /** 1003eaf62fffSJeremy L Thompson @brief Build 1D mass matrix and Laplacian with perturbation 1004eaf62fffSJeremy L Thompson 1005eaf62fffSJeremy L Thompson @param[in] interp_1d Interpolation matrix in one dimension 1006eaf62fffSJeremy L Thompson @param[in] grad_1d Gradient matrix in one dimension 1007eaf62fffSJeremy L Thompson @param[in] q_weight_1d Quadrature weights in one dimension 1008eaf62fffSJeremy L Thompson @param[in] P_1d Number of basis nodes in one dimension 1009eaf62fffSJeremy L Thompson @param[in] Q_1d Number of quadrature points in one dimension 1010eaf62fffSJeremy L Thompson @param[in] dim Dimension of basis 1011eaf62fffSJeremy L Thompson @param[out] mass Assembled mass matrix in one dimension 1012eaf62fffSJeremy L Thompson @param[out] laplace Assembled perturbed Laplacian in one dimension 1013eaf62fffSJeremy L Thompson 1014eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1015eaf62fffSJeremy L Thompson 1016eaf62fffSJeremy L Thompson @ref Developer 1017eaf62fffSJeremy L Thompson **/ 10182c2ea1dbSJeremy L Thompson CeedPragmaOptimizeOff 10192c2ea1dbSJeremy L Thompson static int CeedBuildMassLaplace(const CeedScalar *interp_1d, const CeedScalar *grad_1d, const CeedScalar *q_weight_1d, CeedInt P_1d, CeedInt Q_1d, 10202c2ea1dbSJeremy L Thompson CeedInt dim, CeedScalar *mass, CeedScalar *laplace) { 10212b730f8bSJeremy L Thompson for (CeedInt i = 0; i < P_1d; i++) { 1022eaf62fffSJeremy L Thompson for (CeedInt j = 0; j < P_1d; j++) { 1023eaf62fffSJeremy L Thompson CeedScalar sum = 0.0; 10242b730f8bSJeremy 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]; 1025eaf62fffSJeremy L Thompson mass[i + j * P_1d] = sum; 1026eaf62fffSJeremy L Thompson } 10272b730f8bSJeremy L Thompson } 1028eaf62fffSJeremy L Thompson // -- Laplacian 10292b730f8bSJeremy L Thompson for (CeedInt i = 0; i < P_1d; i++) { 1030eaf62fffSJeremy L Thompson for (CeedInt j = 0; j < P_1d; j++) { 1031eaf62fffSJeremy L Thompson CeedScalar sum = 0.0; 10321c66c397SJeremy L Thompson 10332b730f8bSJeremy 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]; 1034eaf62fffSJeremy L Thompson laplace[i + j * P_1d] = sum; 1035eaf62fffSJeremy L Thompson } 10362b730f8bSJeremy L Thompson } 1037eaf62fffSJeremy L Thompson CeedScalar perturbation = dim > 2 ? 1e-6 : 1e-4; 10382b730f8bSJeremy L Thompson for (CeedInt i = 0; i < P_1d; i++) laplace[i + P_1d * i] += perturbation; 1039eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1040eaf62fffSJeremy L Thompson } 10412c2ea1dbSJeremy L Thompson CeedPragmaOptimizeOn 1042eaf62fffSJeremy L Thompson 1043eaf62fffSJeremy L Thompson /// @} 1044eaf62fffSJeremy L Thompson 1045eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 1046480fae85SJeremy L Thompson /// CeedOperator Backend API 1047480fae85SJeremy L Thompson /// ---------------------------------------------------------------------------- 1048480fae85SJeremy L Thompson /// @addtogroup CeedOperatorBackend 1049480fae85SJeremy L Thompson /// @{ 1050480fae85SJeremy L Thompson 1051480fae85SJeremy L Thompson /** 1052*506b1a0cSSebastian Grimberg @brief Create point block restriction for active operator field 1053*506b1a0cSSebastian Grimberg 1054*506b1a0cSSebastian Grimberg @param[in] rstr Original CeedElemRestriction for active field 1055*506b1a0cSSebastian Grimberg @param[out] point_block_rstr Address of the variable where the newly created CeedElemRestriction will be stored 1056*506b1a0cSSebastian Grimberg 1057*506b1a0cSSebastian Grimberg @return An error code: 0 - success, otherwise - failure 1058*506b1a0cSSebastian Grimberg 1059*506b1a0cSSebastian Grimberg @ref Backend 1060*506b1a0cSSebastian Grimberg **/ 1061*506b1a0cSSebastian Grimberg int CeedOperatorCreateActivePointBlockRestriction(CeedElemRestriction rstr, CeedElemRestriction *point_block_rstr) { 1062*506b1a0cSSebastian Grimberg Ceed ceed; 1063*506b1a0cSSebastian Grimberg CeedInt num_elem, num_comp, shift, elem_size, comp_stride, *point_block_offsets; 1064*506b1a0cSSebastian Grimberg CeedSize l_size; 1065*506b1a0cSSebastian Grimberg const CeedInt *offsets; 1066*506b1a0cSSebastian Grimberg 1067*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1068*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets)); 1069*506b1a0cSSebastian Grimberg 1070*506b1a0cSSebastian Grimberg // Expand offsets 1071*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1072*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1073*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 1074*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetCompStride(rstr, &comp_stride)); 1075*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size)); 1076*506b1a0cSSebastian Grimberg shift = num_comp; 1077*506b1a0cSSebastian Grimberg if (comp_stride != 1) shift *= num_comp; 1078*506b1a0cSSebastian Grimberg CeedCall(CeedCalloc(num_elem * elem_size, &point_block_offsets)); 1079*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < num_elem * elem_size; i++) { 1080*506b1a0cSSebastian Grimberg point_block_offsets[i] = offsets[i] * shift; 1081*506b1a0cSSebastian Grimberg } 1082*506b1a0cSSebastian Grimberg 1083*506b1a0cSSebastian Grimberg // Create new restriction 1084*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionCreate(ceed, num_elem, elem_size, num_comp * num_comp, 1, l_size * num_comp, CEED_MEM_HOST, CEED_OWN_POINTER, 1085*506b1a0cSSebastian Grimberg point_block_offsets, point_block_rstr)); 1086*506b1a0cSSebastian Grimberg 1087*506b1a0cSSebastian Grimberg // Cleanup 1088*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionRestoreOffsets(rstr, &offsets)); 1089*506b1a0cSSebastian Grimberg return CEED_ERROR_SUCCESS; 1090*506b1a0cSSebastian Grimberg } 1091*506b1a0cSSebastian Grimberg 1092*506b1a0cSSebastian Grimberg /** 1093480fae85SJeremy L Thompson @brief Create object holding CeedQFunction assembly data for CeedOperator 1094480fae85SJeremy L Thompson 1095480fae85SJeremy L Thompson @param[in] ceed A Ceed object where the CeedQFunctionAssemblyData will be created 1096ea61e9acSJeremy L Thompson @param[out] data Address of the variable where the newly created CeedQFunctionAssemblyData will be stored 1097480fae85SJeremy L Thompson 1098480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1099480fae85SJeremy L Thompson 1100480fae85SJeremy L Thompson @ref Backend 1101480fae85SJeremy L Thompson **/ 1102ea61e9acSJeremy L Thompson int CeedQFunctionAssemblyDataCreate(Ceed ceed, CeedQFunctionAssemblyData *data) { 11032b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, data)); 1104480fae85SJeremy L Thompson (*data)->ref_count = 1; 1105480fae85SJeremy L Thompson (*data)->ceed = ceed; 11062b730f8bSJeremy L Thompson CeedCall(CeedReference(ceed)); 1107480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1108480fae85SJeremy L Thompson } 1109480fae85SJeremy L Thompson 1110480fae85SJeremy L Thompson /** 1111480fae85SJeremy L Thompson @brief Increment the reference counter for a CeedQFunctionAssemblyData 1112480fae85SJeremy L Thompson 1113ea61e9acSJeremy L Thompson @param[in,out] data CeedQFunctionAssemblyData to increment the reference counter 1114480fae85SJeremy L Thompson 1115480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1116480fae85SJeremy L Thompson 1117480fae85SJeremy L Thompson @ref Backend 1118480fae85SJeremy L Thompson **/ 1119480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataReference(CeedQFunctionAssemblyData data) { 1120480fae85SJeremy L Thompson data->ref_count++; 1121480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1122480fae85SJeremy L Thompson } 1123480fae85SJeremy L Thompson 1124480fae85SJeremy L Thompson /** 1125beecbf24SJeremy L Thompson @brief Set re-use of CeedQFunctionAssemblyData 11268b919e6bSJeremy L Thompson 1127ea61e9acSJeremy L Thompson @param[in,out] data CeedQFunctionAssemblyData to mark for reuse 1128ea61e9acSJeremy L Thompson @param[in] reuse_data Boolean flag indicating data re-use 11298b919e6bSJeremy L Thompson 11308b919e6bSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 11318b919e6bSJeremy L Thompson 11328b919e6bSJeremy L Thompson @ref Backend 11338b919e6bSJeremy L Thompson **/ 11342b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataSetReuse(CeedQFunctionAssemblyData data, bool reuse_data) { 1135beecbf24SJeremy L Thompson data->reuse_data = reuse_data; 1136beecbf24SJeremy L Thompson data->needs_data_update = true; 1137beecbf24SJeremy L Thompson return CEED_ERROR_SUCCESS; 1138beecbf24SJeremy L Thompson } 1139beecbf24SJeremy L Thompson 1140beecbf24SJeremy L Thompson /** 1141beecbf24SJeremy L Thompson @brief Mark QFunctionAssemblyData as stale 1142beecbf24SJeremy L Thompson 1143ea61e9acSJeremy L Thompson @param[in,out] data CeedQFunctionAssemblyData to mark as stale 1144ea61e9acSJeremy L Thompson @param[in] needs_data_update Boolean flag indicating if update is needed or completed 1145beecbf24SJeremy L Thompson 1146beecbf24SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1147beecbf24SJeremy L Thompson 1148beecbf24SJeremy L Thompson @ref Backend 1149beecbf24SJeremy L Thompson **/ 11502b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataSetUpdateNeeded(CeedQFunctionAssemblyData data, bool needs_data_update) { 1151beecbf24SJeremy L Thompson data->needs_data_update = needs_data_update; 11528b919e6bSJeremy L Thompson return CEED_ERROR_SUCCESS; 11538b919e6bSJeremy L Thompson } 11548b919e6bSJeremy L Thompson 11558b919e6bSJeremy L Thompson /** 11568b919e6bSJeremy L Thompson @brief Determine if QFunctionAssemblyData needs update 11578b919e6bSJeremy L Thompson 11588b919e6bSJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to mark as stale 11598b919e6bSJeremy L Thompson @param[out] is_update_needed Boolean flag indicating if re-assembly is required 11608b919e6bSJeremy L Thompson 11618b919e6bSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 11628b919e6bSJeremy L Thompson 11638b919e6bSJeremy L Thompson @ref Backend 11648b919e6bSJeremy L Thompson **/ 11652b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataIsUpdateNeeded(CeedQFunctionAssemblyData data, bool *is_update_needed) { 1166beecbf24SJeremy L Thompson *is_update_needed = !data->reuse_data || data->needs_data_update; 11678b919e6bSJeremy L Thompson return CEED_ERROR_SUCCESS; 11688b919e6bSJeremy L Thompson } 11698b919e6bSJeremy L Thompson 11708b919e6bSJeremy L Thompson /** 1171ea61e9acSJeremy L Thompson @brief Copy the pointer to a CeedQFunctionAssemblyData. 11724385fb7fSSebastian Grimberg 1173ea61e9acSJeremy L Thompson Both pointers should be destroyed with `CeedCeedQFunctionAssemblyDataDestroy()`. 1174512bb800SJeremy L Thompson 1175512bb800SJeremy 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 1176512bb800SJeremy L Thompson CeedQFunctionAssemblyData. This CeedQFunctionAssemblyData will be destroyed if `data_copy` is the only reference to this 1177512bb800SJeremy L Thompson CeedQFunctionAssemblyData. 1178480fae85SJeremy L Thompson 1179ea61e9acSJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to copy reference to 1180ea61e9acSJeremy L Thompson @param[in,out] data_copy Variable to store copied reference 1181480fae85SJeremy L Thompson 1182480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1183480fae85SJeremy L Thompson 1184480fae85SJeremy L Thompson @ref Backend 1185480fae85SJeremy L Thompson **/ 11862b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataReferenceCopy(CeedQFunctionAssemblyData data, CeedQFunctionAssemblyData *data_copy) { 11872b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataReference(data)); 11882b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataDestroy(data_copy)); 1189480fae85SJeremy L Thompson *data_copy = data; 1190480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1191480fae85SJeremy L Thompson } 1192480fae85SJeremy L Thompson 1193480fae85SJeremy L Thompson /** 1194480fae85SJeremy L Thompson @brief Get setup status for internal objects for CeedQFunctionAssemblyData 1195480fae85SJeremy L Thompson 1196ea61e9acSJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to retrieve status 1197480fae85SJeremy L Thompson @param[out] is_setup Boolean flag for setup status 1198480fae85SJeremy L Thompson 1199480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1200480fae85SJeremy L Thompson 1201480fae85SJeremy L Thompson @ref Backend 1202480fae85SJeremy L Thompson **/ 12032b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataIsSetup(CeedQFunctionAssemblyData data, bool *is_setup) { 1204480fae85SJeremy L Thompson *is_setup = data->is_setup; 1205480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1206480fae85SJeremy L Thompson } 1207480fae85SJeremy L Thompson 1208480fae85SJeremy L Thompson /** 1209480fae85SJeremy L Thompson @brief Set internal objects for CeedQFunctionAssemblyData 1210480fae85SJeremy L Thompson 1211ea61e9acSJeremy L Thompson @param[in,out] data CeedQFunctionAssemblyData to set objects 1212480fae85SJeremy L Thompson @param[in] vec CeedVector to store assembled CeedQFunction at quadrature points 1213480fae85SJeremy L Thompson @param[in] rstr CeedElemRestriction for CeedVector containing assembled CeedQFunction 1214480fae85SJeremy L Thompson 1215480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1216480fae85SJeremy L Thompson 1217480fae85SJeremy L Thompson @ref Backend 1218480fae85SJeremy L Thompson **/ 12192b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataSetObjects(CeedQFunctionAssemblyData data, CeedVector vec, CeedElemRestriction rstr) { 12202b730f8bSJeremy L Thompson CeedCall(CeedVectorReferenceCopy(vec, &data->vec)); 12212b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionReferenceCopy(rstr, &data->rstr)); 1222480fae85SJeremy L Thompson 1223480fae85SJeremy L Thompson data->is_setup = true; 1224480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1225480fae85SJeremy L Thompson } 1226480fae85SJeremy L Thompson 12272b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataGetObjects(CeedQFunctionAssemblyData data, CeedVector *vec, CeedElemRestriction *rstr) { 12286574a04fSJeremy L Thompson CeedCheck(data->is_setup, data->ceed, CEED_ERROR_INCOMPLETE, "Internal objects not set; must call CeedQFunctionAssemblyDataSetObjects first."); 1229480fae85SJeremy L Thompson 12302b730f8bSJeremy L Thompson CeedCall(CeedVectorReferenceCopy(data->vec, vec)); 12312b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionReferenceCopy(data->rstr, rstr)); 1232480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1233480fae85SJeremy L Thompson } 1234480fae85SJeremy L Thompson 1235480fae85SJeremy L Thompson /** 1236480fae85SJeremy L Thompson @brief Destroy CeedQFunctionAssemblyData 1237480fae85SJeremy L Thompson 1238ea61e9acSJeremy L Thompson @param[in,out] data CeedQFunctionAssemblyData to destroy 1239480fae85SJeremy L Thompson 1240480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1241480fae85SJeremy L Thompson 1242480fae85SJeremy L Thompson @ref Backend 1243480fae85SJeremy L Thompson **/ 1244480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataDestroy(CeedQFunctionAssemblyData *data) { 1245ad6481ceSJeremy L Thompson if (!*data || --(*data)->ref_count > 0) { 1246ad6481ceSJeremy L Thompson *data = NULL; 1247ad6481ceSJeremy L Thompson return CEED_ERROR_SUCCESS; 1248ad6481ceSJeremy L Thompson } 12492b730f8bSJeremy L Thompson CeedCall(CeedDestroy(&(*data)->ceed)); 12502b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&(*data)->vec)); 12512b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&(*data)->rstr)); 1252480fae85SJeremy L Thompson 12532b730f8bSJeremy L Thompson CeedCall(CeedFree(data)); 1254480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1255480fae85SJeremy L Thompson } 1256480fae85SJeremy L Thompson 1257ed9e99e6SJeremy L Thompson /** 1258ed9e99e6SJeremy L Thompson @brief Get CeedOperatorAssemblyData 1259ed9e99e6SJeremy L Thompson 1260ed9e99e6SJeremy L Thompson @param[in] op CeedOperator to assemble 1261ed9e99e6SJeremy L Thompson @param[out] data CeedQFunctionAssemblyData 1262ed9e99e6SJeremy L Thompson 1263ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1264ed9e99e6SJeremy L Thompson 1265ed9e99e6SJeremy L Thompson @ref Backend 1266ed9e99e6SJeremy L Thompson **/ 12672b730f8bSJeremy L Thompson int CeedOperatorGetOperatorAssemblyData(CeedOperator op, CeedOperatorAssemblyData *data) { 1268ed9e99e6SJeremy L Thompson if (!op->op_assembled) { 1269ed9e99e6SJeremy L Thompson CeedOperatorAssemblyData data; 1270ed9e99e6SJeremy L Thompson 12712b730f8bSJeremy L Thompson CeedCall(CeedOperatorAssemblyDataCreate(op->ceed, op, &data)); 1272ed9e99e6SJeremy L Thompson op->op_assembled = data; 1273ed9e99e6SJeremy L Thompson } 1274ed9e99e6SJeremy L Thompson *data = op->op_assembled; 1275ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1276ed9e99e6SJeremy L Thompson } 1277ed9e99e6SJeremy L Thompson 1278ed9e99e6SJeremy L Thompson /** 1279ba746a46SJeremy L Thompson @brief Create object holding CeedOperator assembly data. 1280ba746a46SJeremy L Thompson 1281ba746a46SJeremy L Thompson The CeedOperatorAssemblyData holds an array with references to every active CeedBasis used in the CeedOperator. 1282ba746a46SJeremy L Thompson An array with references to the corresponding active CeedElemRestrictions is also stored. 1283ba746a46SJeremy L Thompson For each active CeedBasis, the CeedOperatorAssemblyData holds an array of all input and output CeedEvalModes for this CeedBasis. 1284ba746a46SJeremy L Thompson The CeedOperatorAssemblyData holds an array of offsets for indexing into the assembled CeedQFunction arrays to the row representing each 1285ba746a46SJeremy L Thompson CeedEvalMode. 1286ba746a46SJeremy L Thompson The number of input columns across all active bases for the assembled CeedQFunction is also stored. 1287ba746a46SJeremy L Thompson Lastly, the CeedOperatorAssembly data holds assembled matrices representing the full action of the CeedBasis for all CeedEvalModes. 1288ed9e99e6SJeremy L Thompson 1289ea61e9acSJeremy L Thompson @param[in] ceed Ceed object where the CeedOperatorAssemblyData will be created 1290ed9e99e6SJeremy L Thompson @param[in] op CeedOperator to be assembled 1291ea61e9acSJeremy L Thompson @param[out] data Address of the variable where the newly created CeedOperatorAssemblyData will be stored 1292ed9e99e6SJeremy L Thompson 1293ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1294ed9e99e6SJeremy L Thompson 1295ed9e99e6SJeremy L Thompson @ref Backend 1296ed9e99e6SJeremy L Thompson **/ 12972b730f8bSJeremy L Thompson int CeedOperatorAssemblyDataCreate(Ceed ceed, CeedOperator op, CeedOperatorAssemblyData *data) { 1298*506b1a0cSSebastian Grimberg CeedInt num_active_bases_in = 0, num_active_bases_out = 0, offset = 0; 1299*506b1a0cSSebastian Grimberg CeedInt num_input_fields, *num_eval_modes_in = NULL, num_output_fields, *num_eval_modes_out = NULL; 13001c66c397SJeremy L Thompson CeedSize **eval_mode_offsets_in = NULL, **eval_mode_offsets_out = NULL; 13011c66c397SJeremy L Thompson CeedEvalMode **eval_modes_in = NULL, **eval_modes_out = NULL; 13021c66c397SJeremy L Thompson CeedQFunctionField *qf_fields; 13031c66c397SJeremy L Thompson CeedQFunction qf; 13041c66c397SJeremy L Thompson CeedOperatorField *op_fields; 130501f0e615SJames Wright bool is_composite; 130601f0e615SJames Wright 130701f0e615SJames Wright CeedCall(CeedOperatorIsComposite(op, &is_composite)); 130801f0e615SJames Wright CeedCheck(!is_composite, ceed, CEED_ERROR_INCOMPATIBLE, "Can only create CeedOperator assembly data for non-composite operators."); 1309437c7c90SJeremy L Thompson 1310437c7c90SJeremy L Thompson // Allocate 13112b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, data)); 1312ed9e99e6SJeremy L Thompson (*data)->ceed = ceed; 13132b730f8bSJeremy L Thompson CeedCall(CeedReference(ceed)); 1314ed9e99e6SJeremy L Thompson 1315ed9e99e6SJeremy L Thompson // Build OperatorAssembly data 13162b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetQFunction(op, &qf)); 13172b730f8bSJeremy L Thompson CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, &qf_fields, NULL, NULL)); 13182b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFields(op, NULL, &op_fields, NULL, NULL)); 1319ed9e99e6SJeremy L Thompson 1320ed9e99e6SJeremy L Thompson // Determine active input basis 1321ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < num_input_fields; i++) { 1322ed9e99e6SJeremy L Thompson CeedVector vec; 13231c66c397SJeremy L Thompson 13242b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetVector(op_fields[i], &vec)); 1325ed9e99e6SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 13267c1dbaffSSebastian Grimberg CeedInt index = -1, num_comp, q_comp; 13271c66c397SJeremy L Thompson CeedEvalMode eval_mode; 13281c66c397SJeremy L Thompson CeedBasis basis_in = NULL; 13291c66c397SJeremy L Thompson 13302b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetBasis(op_fields[i], &basis_in)); 13312b730f8bSJeremy L Thompson CeedCall(CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode)); 1332352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumComponents(basis_in, &num_comp)); 1333352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumQuadratureComponents(basis_in, eval_mode, &q_comp)); 1334*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < num_active_bases_in; i++) { 1335*506b1a0cSSebastian Grimberg if ((*data)->active_bases_in[i] == basis_in) index = i; 1336437c7c90SJeremy L Thompson } 1337437c7c90SJeremy L Thompson if (index == -1) { 1338437c7c90SJeremy L Thompson CeedElemRestriction elem_rstr_in; 13391c66c397SJeremy L Thompson 1340*506b1a0cSSebastian Grimberg index = num_active_bases_in; 1341*506b1a0cSSebastian Grimberg CeedCall(CeedRealloc(num_active_bases_in + 1, &(*data)->active_bases_in)); 1342*506b1a0cSSebastian Grimberg (*data)->active_bases_in[num_active_bases_in] = NULL; 1343*506b1a0cSSebastian Grimberg CeedCall(CeedBasisReferenceCopy(basis_in, &(*data)->active_bases_in[num_active_bases_in])); 1344*506b1a0cSSebastian Grimberg CeedCall(CeedRealloc(num_active_bases_in + 1, &(*data)->active_elem_rstrs_in)); 1345*506b1a0cSSebastian Grimberg (*data)->active_elem_rstrs_in[num_active_bases_in] = NULL; 1346437c7c90SJeremy L Thompson CeedCall(CeedOperatorFieldGetElemRestriction(op_fields[i], &elem_rstr_in)); 1347*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionReferenceCopy(elem_rstr_in, &(*data)->active_elem_rstrs_in[num_active_bases_in])); 1348*506b1a0cSSebastian Grimberg CeedCall(CeedRealloc(num_active_bases_in + 1, &num_eval_modes_in)); 1349437c7c90SJeremy L Thompson num_eval_modes_in[index] = 0; 1350*506b1a0cSSebastian Grimberg CeedCall(CeedRealloc(num_active_bases_in + 1, &eval_modes_in)); 1351437c7c90SJeremy L Thompson eval_modes_in[index] = NULL; 1352*506b1a0cSSebastian Grimberg CeedCall(CeedRealloc(num_active_bases_in + 1, &eval_mode_offsets_in)); 1353437c7c90SJeremy L Thompson eval_mode_offsets_in[index] = NULL; 1354*506b1a0cSSebastian Grimberg CeedCall(CeedRealloc(num_active_bases_in + 1, &(*data)->assembled_bases_in)); 1355437c7c90SJeremy L Thompson (*data)->assembled_bases_in[index] = NULL; 1356*506b1a0cSSebastian Grimberg num_active_bases_in++; 1357437c7c90SJeremy L Thompson } 1358352a5e7cSSebastian Grimberg if (eval_mode != CEED_EVAL_WEIGHT) { 1359352a5e7cSSebastian Grimberg // q_comp = 1 if CEED_EVAL_NONE, CEED_EVAL_WEIGHT caught by QF Assembly 1360352a5e7cSSebastian Grimberg CeedCall(CeedRealloc(num_eval_modes_in[index] + q_comp, &eval_modes_in[index])); 1361352a5e7cSSebastian Grimberg CeedCall(CeedRealloc(num_eval_modes_in[index] + q_comp, &eval_mode_offsets_in[index])); 1362352a5e7cSSebastian Grimberg for (CeedInt d = 0; d < q_comp; d++) { 1363437c7c90SJeremy L Thompson eval_modes_in[index][num_eval_modes_in[index] + d] = eval_mode; 1364437c7c90SJeremy L Thompson eval_mode_offsets_in[index][num_eval_modes_in[index] + d] = offset; 1365352a5e7cSSebastian Grimberg offset += num_comp; 1366ed9e99e6SJeremy L Thompson } 1367352a5e7cSSebastian Grimberg num_eval_modes_in[index] += q_comp; 1368ed9e99e6SJeremy L Thompson } 1369ed9e99e6SJeremy L Thompson } 1370ed9e99e6SJeremy L Thompson } 1371ed9e99e6SJeremy L Thompson 1372ed9e99e6SJeremy L Thompson // Determine active output basis 13732b730f8bSJeremy L Thompson CeedCall(CeedQFunctionGetFields(qf, NULL, NULL, &num_output_fields, &qf_fields)); 13742b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFields(op, NULL, NULL, NULL, &op_fields)); 1375437c7c90SJeremy L Thompson offset = 0; 1376ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < num_output_fields; i++) { 1377ed9e99e6SJeremy L Thompson CeedVector vec; 13781c66c397SJeremy L Thompson 13792b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetVector(op_fields[i], &vec)); 1380ed9e99e6SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 13817c1dbaffSSebastian Grimberg CeedInt index = -1, num_comp, q_comp; 13821c66c397SJeremy L Thompson CeedEvalMode eval_mode; 13831c66c397SJeremy L Thompson CeedBasis basis_out = NULL; 13841c66c397SJeremy L Thompson 1385437c7c90SJeremy L Thompson CeedCall(CeedOperatorFieldGetBasis(op_fields[i], &basis_out)); 13862b730f8bSJeremy L Thompson CeedCall(CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode)); 1387352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumComponents(basis_out, &num_comp)); 1388352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumQuadratureComponents(basis_out, eval_mode, &q_comp)); 1389*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < num_active_bases_out; i++) { 1390*506b1a0cSSebastian Grimberg if ((*data)->active_bases_out[i] == basis_out) index = i; 1391437c7c90SJeremy L Thompson } 1392437c7c90SJeremy L Thompson if (index == -1) { 1393437c7c90SJeremy L Thompson CeedElemRestriction elem_rstr_out; 13941c66c397SJeremy L Thompson 1395*506b1a0cSSebastian Grimberg index = num_active_bases_out; 1396*506b1a0cSSebastian Grimberg CeedCall(CeedRealloc(num_active_bases_out + 1, &(*data)->active_bases_out)); 1397*506b1a0cSSebastian Grimberg (*data)->active_bases_out[num_active_bases_out] = NULL; 1398*506b1a0cSSebastian Grimberg CeedCall(CeedBasisReferenceCopy(basis_out, &(*data)->active_bases_out[num_active_bases_out])); 1399*506b1a0cSSebastian Grimberg CeedCall(CeedRealloc(num_active_bases_out + 1, &(*data)->active_elem_rstrs_out)); 1400*506b1a0cSSebastian Grimberg (*data)->active_elem_rstrs_out[num_active_bases_out] = NULL; 1401437c7c90SJeremy L Thompson CeedCall(CeedOperatorFieldGetElemRestriction(op_fields[i], &elem_rstr_out)); 1402*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionReferenceCopy(elem_rstr_out, &(*data)->active_elem_rstrs_out[num_active_bases_out])); 1403*506b1a0cSSebastian Grimberg CeedCall(CeedRealloc(num_active_bases_out + 1, &num_eval_modes_out)); 1404437c7c90SJeremy L Thompson num_eval_modes_out[index] = 0; 1405*506b1a0cSSebastian Grimberg CeedCall(CeedRealloc(num_active_bases_out + 1, &eval_modes_out)); 1406437c7c90SJeremy L Thompson eval_modes_out[index] = NULL; 1407*506b1a0cSSebastian Grimberg CeedCall(CeedRealloc(num_active_bases_out + 1, &eval_mode_offsets_out)); 1408437c7c90SJeremy L Thompson eval_mode_offsets_out[index] = NULL; 1409*506b1a0cSSebastian Grimberg CeedCall(CeedRealloc(num_active_bases_out + 1, &(*data)->assembled_bases_out)); 1410437c7c90SJeremy L Thompson (*data)->assembled_bases_out[index] = NULL; 1411*506b1a0cSSebastian Grimberg num_active_bases_out++; 1412437c7c90SJeremy L Thompson } 1413352a5e7cSSebastian Grimberg if (eval_mode != CEED_EVAL_WEIGHT) { 1414352a5e7cSSebastian Grimberg // q_comp = 1 if CEED_EVAL_NONE, CEED_EVAL_WEIGHT caught by QF Assembly 1415352a5e7cSSebastian Grimberg CeedCall(CeedRealloc(num_eval_modes_out[index] + q_comp, &eval_modes_out[index])); 1416352a5e7cSSebastian Grimberg CeedCall(CeedRealloc(num_eval_modes_out[index] + q_comp, &eval_mode_offsets_out[index])); 1417352a5e7cSSebastian Grimberg for (CeedInt d = 0; d < q_comp; d++) { 1418437c7c90SJeremy L Thompson eval_modes_out[index][num_eval_modes_out[index] + d] = eval_mode; 1419437c7c90SJeremy L Thompson eval_mode_offsets_out[index][num_eval_modes_out[index] + d] = offset; 1420352a5e7cSSebastian Grimberg offset += num_comp; 1421ed9e99e6SJeremy L Thompson } 1422352a5e7cSSebastian Grimberg num_eval_modes_out[index] += q_comp; 1423ed9e99e6SJeremy L Thompson } 1424ed9e99e6SJeremy L Thompson } 1425ed9e99e6SJeremy L Thompson } 1426*506b1a0cSSebastian Grimberg (*data)->num_active_bases_in = num_active_bases_in; 142727789c4aSJed Brown (*data)->num_eval_modes_in = num_eval_modes_in; 142827789c4aSJed Brown (*data)->eval_modes_in = eval_modes_in; 142927789c4aSJed Brown (*data)->eval_mode_offsets_in = eval_mode_offsets_in; 1430*506b1a0cSSebastian Grimberg (*data)->num_active_bases_out = num_active_bases_out; 1431437c7c90SJeremy L Thompson (*data)->num_eval_modes_out = num_eval_modes_out; 1432437c7c90SJeremy L Thompson (*data)->eval_modes_out = eval_modes_out; 1433437c7c90SJeremy L Thompson (*data)->eval_mode_offsets_out = eval_mode_offsets_out; 1434*506b1a0cSSebastian Grimberg (*data)->num_output_components = offset; 1435ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1436ed9e99e6SJeremy L Thompson } 1437ed9e99e6SJeremy L Thompson 1438ed9e99e6SJeremy L Thompson /** 1439ba746a46SJeremy L Thompson @brief Get CeedOperator CeedEvalModes for assembly. 1440ba746a46SJeremy L Thompson 1441ba746a46SJeremy L Thompson Note: See CeedOperatorAssemblyDataCreate for a full description of the data stored in this object. 1442ed9e99e6SJeremy L Thompson 1443ed9e99e6SJeremy L Thompson @param[in] data CeedOperatorAssemblyData 1444*506b1a0cSSebastian Grimberg @param[out] num_active_bases_in Total number of active bases for input 1445c5d0f995SJed Brown @param[out] num_eval_modes_in Pointer to hold array of numbers of input CeedEvalModes, or NULL. 1446ba746a46SJeremy L Thompson `eval_modes_in[0]` holds an array of eval modes for the first active basis. 1447c5d0f995SJed Brown @param[out] eval_modes_in Pointer to hold arrays of input CeedEvalModes, or NULL. 1448ba746a46SJeremy L Thompson @param[out] eval_mode_offsets_in Pointer to hold arrays of input offsets at each quadrature point. 1449*506b1a0cSSebastian Grimberg @param[out] num_active_bases_out Total number of active bases for output 1450c5d0f995SJed Brown @param[out] num_eval_modes_out Pointer to hold array of numbers of output CeedEvalModes, or NULL 1451c5d0f995SJed Brown @param[out] eval_modes_out Pointer to hold arrays of output CeedEvalModes, or NULL. 1452437c7c90SJeremy L Thompson @param[out] eval_mode_offsets_out Pointer to hold arrays of output offsets at each quadrature point 1453ba746a46SJeremy L Thompson @param[out] num_output_components The number of columns in the assembled CeedQFunction matrix for each quadrature point, 1454ba746a46SJeremy L Thompson including contributions of all active bases 1455ed9e99e6SJeremy L Thompson 1456ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1457ed9e99e6SJeremy L Thompson 1458ed9e99e6SJeremy L Thompson @ref Backend 1459ed9e99e6SJeremy L Thompson **/ 1460*506b1a0cSSebastian Grimberg int CeedOperatorAssemblyDataGetEvalModes(CeedOperatorAssemblyData data, CeedInt *num_active_bases_in, CeedInt **num_eval_modes_in, 1461*506b1a0cSSebastian Grimberg const CeedEvalMode ***eval_modes_in, CeedSize ***eval_mode_offsets_in, CeedInt *num_active_bases_out, 1462*506b1a0cSSebastian Grimberg CeedInt **num_eval_modes_out, const CeedEvalMode ***eval_modes_out, CeedSize ***eval_mode_offsets_out, 1463*506b1a0cSSebastian Grimberg CeedSize *num_output_components) { 1464*506b1a0cSSebastian Grimberg if (num_active_bases_in) *num_active_bases_in = data->num_active_bases_in; 1465437c7c90SJeremy L Thompson if (num_eval_modes_in) *num_eval_modes_in = data->num_eval_modes_in; 1466437c7c90SJeremy L Thompson if (eval_modes_in) *eval_modes_in = (const CeedEvalMode **)data->eval_modes_in; 1467437c7c90SJeremy L Thompson if (eval_mode_offsets_in) *eval_mode_offsets_in = data->eval_mode_offsets_in; 1468*506b1a0cSSebastian Grimberg if (num_active_bases_out) *num_active_bases_out = data->num_active_bases_out; 1469437c7c90SJeremy L Thompson if (num_eval_modes_out) *num_eval_modes_out = data->num_eval_modes_out; 1470437c7c90SJeremy L Thompson if (eval_modes_out) *eval_modes_out = (const CeedEvalMode **)data->eval_modes_out; 1471437c7c90SJeremy L Thompson if (eval_mode_offsets_out) *eval_mode_offsets_out = data->eval_mode_offsets_out; 1472437c7c90SJeremy L Thompson if (num_output_components) *num_output_components = data->num_output_components; 1473ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1474ed9e99e6SJeremy L Thompson } 1475ed9e99e6SJeremy L Thompson 1476ed9e99e6SJeremy L Thompson /** 1477ba746a46SJeremy L Thompson @brief Get CeedOperator CeedBasis data for assembly. 1478ba746a46SJeremy L Thompson 1479ba746a46SJeremy L Thompson Note: See CeedOperatorAssemblyDataCreate for a full description of the data stored in this object. 1480ed9e99e6SJeremy L Thompson 1481ed9e99e6SJeremy L Thompson @param[in] data CeedOperatorAssemblyData 1482*506b1a0cSSebastian Grimberg @param[out] num_active_bases_in Number of active input bases, or NULL 1483*506b1a0cSSebastian Grimberg @param[out] active_bases_in Pointer to hold active input CeedBasis, or NULL 1484437c7c90SJeremy L Thompson @param[out] assembled_bases_in Pointer to hold assembled active input B, or NULL 1485*506b1a0cSSebastian Grimberg @param[out] num_active_bases_out Number of active output bases, or NULL 1486*506b1a0cSSebastian Grimberg @param[out] active_bases_out Pointer to hold active output CeedBasis, or NULL 1487437c7c90SJeremy L Thompson @param[out] assembled_bases_out Pointer to hold assembled active output B, or NULL 1488ed9e99e6SJeremy L Thompson 1489ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1490ed9e99e6SJeremy L Thompson 1491ed9e99e6SJeremy L Thompson @ref Backend 1492ed9e99e6SJeremy L Thompson **/ 1493*506b1a0cSSebastian Grimberg int CeedOperatorAssemblyDataGetBases(CeedOperatorAssemblyData data, CeedInt *num_active_bases_in, CeedBasis **active_bases_in, 1494*506b1a0cSSebastian Grimberg const CeedScalar ***assembled_bases_in, CeedInt *num_active_bases_out, CeedBasis **active_bases_out, 1495*506b1a0cSSebastian Grimberg const CeedScalar ***assembled_bases_out) { 1496ed9e99e6SJeremy L Thompson // Assemble B_in, B_out if needed 1497437c7c90SJeremy L Thompson if (assembled_bases_in && !data->assembled_bases_in[0]) { 1498437c7c90SJeremy L Thompson CeedInt num_qpts; 1499437c7c90SJeremy L Thompson 1500*506b1a0cSSebastian Grimberg if (data->active_bases_in[0] == CEED_BASIS_NONE) CeedCall(CeedElemRestrictionGetElementSize(data->active_elem_rstrs_in[0], &num_qpts)); 1501*506b1a0cSSebastian Grimberg else CeedCall(CeedBasisGetNumQuadraturePoints(data->active_bases_in[0], &num_qpts)); 1502*506b1a0cSSebastian Grimberg for (CeedInt b = 0; b < data->num_active_bases_in; b++) { 15031c66c397SJeremy L Thompson bool has_eval_none = false; 1504352a5e7cSSebastian Grimberg CeedInt num_nodes; 1505437c7c90SJeremy L Thompson CeedScalar *B_in = NULL, *identity = NULL; 1506ed9e99e6SJeremy L Thompson 1507*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetElementSize(data->active_elem_rstrs_in[b], &num_nodes)); 1508352a5e7cSSebastian Grimberg CeedCall(CeedCalloc(num_qpts * num_nodes * data->num_eval_modes_in[b], &B_in)); 1509ed9e99e6SJeremy L Thompson 1510437c7c90SJeremy L Thompson for (CeedInt i = 0; i < data->num_eval_modes_in[b]; i++) { 1511437c7c90SJeremy L Thompson has_eval_none = has_eval_none || (data->eval_modes_in[b][i] == CEED_EVAL_NONE); 1512ed9e99e6SJeremy L Thompson } 1513ed9e99e6SJeremy L Thompson if (has_eval_none) { 1514352a5e7cSSebastian Grimberg CeedCall(CeedCalloc(num_qpts * num_nodes, &identity)); 1515352a5e7cSSebastian Grimberg for (CeedInt i = 0; i < (num_nodes < num_qpts ? num_nodes : num_qpts); i++) { 1516352a5e7cSSebastian Grimberg identity[i * num_nodes + i] = 1.0; 1517ed9e99e6SJeremy L Thompson } 1518ed9e99e6SJeremy L Thompson } 1519ed9e99e6SJeremy L Thompson 1520ed9e99e6SJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 1521352a5e7cSSebastian Grimberg for (CeedInt n = 0; n < num_nodes; n++) { 1522352a5e7cSSebastian Grimberg CeedInt d_in = 0, q_comp_in; 1523352a5e7cSSebastian Grimberg CeedEvalMode eval_mode_in_prev = CEED_EVAL_NONE; 15241c66c397SJeremy L Thompson 1525437c7c90SJeremy L Thompson for (CeedInt e_in = 0; e_in < data->num_eval_modes_in[b]; e_in++) { 1526437c7c90SJeremy L Thompson const CeedInt qq = data->num_eval_modes_in[b] * q; 1527437c7c90SJeremy L Thompson const CeedScalar *B = NULL; 15281c66c397SJeremy L Thompson 1529*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorGetBasisPointer(data->active_bases_in[b], data->eval_modes_in[b][e_in], identity, &B)); 1530*506b1a0cSSebastian Grimberg CeedCall(CeedBasisGetNumQuadratureComponents(data->active_bases_in[b], data->eval_modes_in[b][e_in], &q_comp_in)); 1531352a5e7cSSebastian Grimberg if (q_comp_in > 1) { 1532352a5e7cSSebastian Grimberg if (e_in == 0 || data->eval_modes_in[b][e_in] != eval_mode_in_prev) d_in = 0; 1533352a5e7cSSebastian Grimberg else B = &B[(++d_in) * num_qpts * num_nodes]; 1534352a5e7cSSebastian Grimberg } 1535352a5e7cSSebastian Grimberg eval_mode_in_prev = data->eval_modes_in[b][e_in]; 1536352a5e7cSSebastian Grimberg B_in[(qq + e_in) * num_nodes + n] = B[q * num_nodes + n]; 1537ed9e99e6SJeremy L Thompson } 1538ed9e99e6SJeremy L Thompson } 1539ed9e99e6SJeremy L Thompson } 15407c1dbaffSSebastian Grimberg if (identity) CeedCall(CeedFree(&identity)); 1541437c7c90SJeremy L Thompson data->assembled_bases_in[b] = B_in; 1542437c7c90SJeremy L Thompson } 1543ed9e99e6SJeremy L Thompson } 1544ed9e99e6SJeremy L Thompson 1545437c7c90SJeremy L Thompson if (assembled_bases_out && !data->assembled_bases_out[0]) { 1546437c7c90SJeremy L Thompson CeedInt num_qpts; 1547437c7c90SJeremy L Thompson 1548*506b1a0cSSebastian Grimberg if (data->active_bases_out[0] == CEED_BASIS_NONE) CeedCall(CeedElemRestrictionGetElementSize(data->active_elem_rstrs_out[0], &num_qpts)); 1549*506b1a0cSSebastian Grimberg else CeedCall(CeedBasisGetNumQuadraturePoints(data->active_bases_out[0], &num_qpts)); 1550*506b1a0cSSebastian Grimberg for (CeedInt b = 0; b < data->num_active_bases_out; b++) { 1551ed9e99e6SJeremy L Thompson bool has_eval_none = false; 15521c66c397SJeremy L Thompson CeedInt num_nodes; 1553437c7c90SJeremy L Thompson CeedScalar *B_out = NULL, *identity = NULL; 1554ed9e99e6SJeremy L Thompson 1555*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetElementSize(data->active_elem_rstrs_out[b], &num_nodes)); 1556352a5e7cSSebastian Grimberg CeedCall(CeedCalloc(num_qpts * num_nodes * data->num_eval_modes_out[b], &B_out)); 1557ed9e99e6SJeremy L Thompson 1558437c7c90SJeremy L Thompson for (CeedInt i = 0; i < data->num_eval_modes_out[b]; i++) { 1559437c7c90SJeremy L Thompson has_eval_none = has_eval_none || (data->eval_modes_out[b][i] == CEED_EVAL_NONE); 1560ed9e99e6SJeremy L Thompson } 1561ed9e99e6SJeremy L Thompson if (has_eval_none) { 1562352a5e7cSSebastian Grimberg CeedCall(CeedCalloc(num_qpts * num_nodes, &identity)); 1563352a5e7cSSebastian Grimberg for (CeedInt i = 0; i < (num_nodes < num_qpts ? num_nodes : num_qpts); i++) { 1564352a5e7cSSebastian Grimberg identity[i * num_nodes + i] = 1.0; 1565ed9e99e6SJeremy L Thompson } 1566ed9e99e6SJeremy L Thompson } 1567ed9e99e6SJeremy L Thompson 1568ed9e99e6SJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 1569352a5e7cSSebastian Grimberg for (CeedInt n = 0; n < num_nodes; n++) { 1570352a5e7cSSebastian Grimberg CeedInt d_out = 0, q_comp_out; 1571352a5e7cSSebastian Grimberg CeedEvalMode eval_mode_out_prev = CEED_EVAL_NONE; 15721c66c397SJeremy L Thompson 1573437c7c90SJeremy L Thompson for (CeedInt e_out = 0; e_out < data->num_eval_modes_out[b]; e_out++) { 1574437c7c90SJeremy L Thompson const CeedInt qq = data->num_eval_modes_out[b] * q; 1575437c7c90SJeremy L Thompson const CeedScalar *B = NULL; 15761c66c397SJeremy L Thompson 1577*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorGetBasisPointer(data->active_bases_out[b], data->eval_modes_out[b][e_out], identity, &B)); 1578*506b1a0cSSebastian Grimberg CeedCall(CeedBasisGetNumQuadratureComponents(data->active_bases_out[b], data->eval_modes_out[b][e_out], &q_comp_out)); 1579352a5e7cSSebastian Grimberg if (q_comp_out > 1) { 1580352a5e7cSSebastian Grimberg if (e_out == 0 || data->eval_modes_out[b][e_out] != eval_mode_out_prev) d_out = 0; 1581352a5e7cSSebastian Grimberg else B = &B[(++d_out) * num_qpts * num_nodes]; 1582352a5e7cSSebastian Grimberg } 1583352a5e7cSSebastian Grimberg eval_mode_out_prev = data->eval_modes_out[b][e_out]; 1584352a5e7cSSebastian Grimberg B_out[(qq + e_out) * num_nodes + n] = B[q * num_nodes + n]; 1585ed9e99e6SJeremy L Thompson } 1586ed9e99e6SJeremy L Thompson } 1587ed9e99e6SJeremy L Thompson } 15887c1dbaffSSebastian Grimberg if (identity) CeedCall(CeedFree(&identity)); 1589437c7c90SJeremy L Thompson data->assembled_bases_out[b] = B_out; 1590437c7c90SJeremy L Thompson } 1591ed9e99e6SJeremy L Thompson } 1592ed9e99e6SJeremy L Thompson 1593437c7c90SJeremy L Thompson // Pass out assembled data 1594*506b1a0cSSebastian Grimberg if (num_active_bases_in) *num_active_bases_in = data->num_active_bases_in; 1595*506b1a0cSSebastian Grimberg if (active_bases_in) *active_bases_in = data->active_bases_in; 1596437c7c90SJeremy L Thompson if (assembled_bases_in) *assembled_bases_in = (const CeedScalar **)data->assembled_bases_in; 1597*506b1a0cSSebastian Grimberg if (num_active_bases_out) *num_active_bases_out = data->num_active_bases_out; 1598*506b1a0cSSebastian Grimberg if (active_bases_out) *active_bases_out = data->active_bases_out; 1599437c7c90SJeremy L Thompson if (assembled_bases_out) *assembled_bases_out = (const CeedScalar **)data->assembled_bases_out; 1600437c7c90SJeremy L Thompson return CEED_ERROR_SUCCESS; 1601437c7c90SJeremy L Thompson } 1602437c7c90SJeremy L Thompson 1603437c7c90SJeremy L Thompson /** 1604ba746a46SJeremy L Thompson @brief Get CeedOperator CeedBasis data for assembly. 1605ba746a46SJeremy L Thompson 1606ba746a46SJeremy L Thompson Note: See CeedOperatorAssemblyDataCreate for a full description of the data stored in this object. 1607437c7c90SJeremy L Thompson 1608437c7c90SJeremy L Thompson @param[in] data CeedOperatorAssemblyData 1609*506b1a0cSSebastian Grimberg @param[out] num_active_elem_rstrs_in Number of active input element restrictions, or NULL 1610*506b1a0cSSebastian Grimberg @param[out] active_elem_rstrs_in Pointer to hold active input CeedElemRestrictions, or NULL 1611*506b1a0cSSebastian Grimberg @param[out] num_active_elem_rstrs_out Number of active output element restrictions, or NULL 1612*506b1a0cSSebastian Grimberg @param[out] active_elem_rstrs_out Pointer to hold active output CeedElemRestrictions, or NULL 1613437c7c90SJeremy L Thompson 1614437c7c90SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1615437c7c90SJeremy L Thompson 1616437c7c90SJeremy L Thompson @ref Backend 1617437c7c90SJeremy L Thompson **/ 1618*506b1a0cSSebastian Grimberg int CeedOperatorAssemblyDataGetElemRestrictions(CeedOperatorAssemblyData data, CeedInt *num_active_elem_rstrs_in, 1619*506b1a0cSSebastian Grimberg CeedElemRestriction **active_elem_rstrs_in, CeedInt *num_active_elem_rstrs_out, 1620*506b1a0cSSebastian Grimberg CeedElemRestriction **active_elem_rstrs_out) { 1621*506b1a0cSSebastian Grimberg if (num_active_elem_rstrs_in) *num_active_elem_rstrs_in = data->num_active_bases_in; 1622*506b1a0cSSebastian Grimberg if (active_elem_rstrs_in) *active_elem_rstrs_in = data->active_elem_rstrs_in; 1623*506b1a0cSSebastian Grimberg if (num_active_elem_rstrs_out) *num_active_elem_rstrs_out = data->num_active_bases_out; 1624*506b1a0cSSebastian Grimberg if (active_elem_rstrs_out) *active_elem_rstrs_out = data->active_elem_rstrs_out; 1625ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1626ed9e99e6SJeremy L Thompson } 1627ed9e99e6SJeremy L Thompson 1628ed9e99e6SJeremy L Thompson /** 1629ed9e99e6SJeremy L Thompson @brief Destroy CeedOperatorAssemblyData 1630ed9e99e6SJeremy L Thompson 1631ea61e9acSJeremy L Thompson @param[in,out] data CeedOperatorAssemblyData to destroy 1632ed9e99e6SJeremy L Thompson 1633ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1634ed9e99e6SJeremy L Thompson 1635ed9e99e6SJeremy L Thompson @ref Backend 1636ed9e99e6SJeremy L Thompson **/ 1637ed9e99e6SJeremy L Thompson int CeedOperatorAssemblyDataDestroy(CeedOperatorAssemblyData *data) { 1638ad6481ceSJeremy L Thompson if (!*data) { 1639ad6481ceSJeremy L Thompson *data = NULL; 1640ad6481ceSJeremy L Thompson return CEED_ERROR_SUCCESS; 1641ad6481ceSJeremy L Thompson } 16422b730f8bSJeremy L Thompson CeedCall(CeedDestroy(&(*data)->ceed)); 1643*506b1a0cSSebastian Grimberg for (CeedInt b = 0; b < (*data)->num_active_bases_in; b++) { 1644*506b1a0cSSebastian Grimberg CeedCall(CeedBasisDestroy(&(*data)->active_bases_in[b])); 1645*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionDestroy(&(*data)->active_elem_rstrs_in[b])); 1646437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_modes_in[b])); 1647437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_mode_offsets_in[b])); 1648437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->assembled_bases_in[b])); 1649*506b1a0cSSebastian Grimberg } 1650*506b1a0cSSebastian Grimberg for (CeedInt b = 0; b < (*data)->num_active_bases_out; b++) { 1651*506b1a0cSSebastian Grimberg CeedCall(CeedBasisDestroy(&(*data)->active_bases_out[b])); 1652*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionDestroy(&(*data)->active_elem_rstrs_out[b])); 1653*506b1a0cSSebastian Grimberg CeedCall(CeedFree(&(*data)->eval_modes_out[b])); 1654*506b1a0cSSebastian Grimberg CeedCall(CeedFree(&(*data)->eval_mode_offsets_out[b])); 1655437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->assembled_bases_out[b])); 1656437c7c90SJeremy L Thompson } 1657*506b1a0cSSebastian Grimberg CeedCall(CeedFree(&(*data)->active_bases_in)); 1658*506b1a0cSSebastian Grimberg CeedCall(CeedFree(&(*data)->active_bases_out)); 1659*506b1a0cSSebastian Grimberg CeedCall(CeedFree(&(*data)->active_elem_rstrs_in)); 1660*506b1a0cSSebastian Grimberg CeedCall(CeedFree(&(*data)->active_elem_rstrs_out)); 1661437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->num_eval_modes_in)); 1662437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->num_eval_modes_out)); 1663437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_modes_in)); 1664437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_modes_out)); 1665437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_mode_offsets_in)); 1666437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_mode_offsets_out)); 1667437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->assembled_bases_in)); 1668437c7c90SJeremy L Thompson CeedCall(CeedFree(&(*data)->assembled_bases_out)); 1669ed9e99e6SJeremy L Thompson 16702b730f8bSJeremy L Thompson CeedCall(CeedFree(data)); 1671ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1672ed9e99e6SJeremy L Thompson } 1673ed9e99e6SJeremy L Thompson 1674480fae85SJeremy L Thompson /// @} 1675480fae85SJeremy L Thompson 1676480fae85SJeremy L Thompson /// ---------------------------------------------------------------------------- 1677eaf62fffSJeremy L Thompson /// CeedOperator Public API 1678eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 1679eaf62fffSJeremy L Thompson /// @addtogroup CeedOperatorUser 1680eaf62fffSJeremy L Thompson /// @{ 1681eaf62fffSJeremy L Thompson 1682eaf62fffSJeremy L Thompson /** 1683eaf62fffSJeremy L Thompson @brief Assemble a linear CeedQFunction associated with a CeedOperator 1684eaf62fffSJeremy L Thompson 1685ea61e9acSJeremy L Thompson This returns a CeedVector containing a matrix at each quadrature point providing the action of the CeedQFunction associated with the CeedOperator. 1686859c15bbSJames Wright The vector `assembled` is of shape `[num_elements, num_input_fields, num_output_fields, num_quad_points]` and contains column-major matrices 1687859c15bbSJames Wright representing the action of the CeedQFunction for a corresponding quadrature point on an element. 1688859c15bbSJames Wright 16899fd66db6SSebastian Grimberg Inputs and outputs are in the order provided by the user when adding CeedOperator fields. 16909fd66db6SSebastian 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 16919fd66db6SSebastian 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]. 1692eaf62fffSJeremy L Thompson 1693ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1694f04ea552SJeremy L Thompson 1695ea61e9acSJeremy L Thompson @param[in] op CeedOperator to assemble CeedQFunction 1696ea61e9acSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedQFunction at quadrature points 1697ea61e9acSJeremy L Thompson @param[out] rstr CeedElemRestriction for CeedVector containing assembled CeedQFunction 1698ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1699eaf62fffSJeremy L Thompson 1700eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1701eaf62fffSJeremy L Thompson 1702eaf62fffSJeremy L Thompson @ref User 1703eaf62fffSJeremy L Thompson **/ 17042b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) { 17052b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1706eaf62fffSJeremy L Thompson 1707eaf62fffSJeremy L Thompson if (op->LinearAssembleQFunction) { 1708d04bbc78SJeremy L Thompson // Backend version 17092b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleQFunction(op, assembled, rstr, request)); 1710eaf62fffSJeremy L Thompson } else { 1711d04bbc78SJeremy L Thompson // Operator fallback 1712d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1713d04bbc78SJeremy L Thompson 17142b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 17156574a04fSJeremy L Thompson if (op_fallback) CeedCall(CeedOperatorLinearAssembleQFunction(op_fallback, assembled, rstr, request)); 17166574a04fSJeremy L Thompson else return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedOperatorLinearAssembleQFunction"); 171770a7ffb3SJeremy L Thompson } 1718eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1719eaf62fffSJeremy L Thompson } 172070a7ffb3SJeremy L Thompson 172170a7ffb3SJeremy L Thompson /** 1722ea61e9acSJeremy L Thompson @brief Assemble CeedQFunction and store result internally. 17234385fb7fSSebastian Grimberg 1724ea61e9acSJeremy L Thompson Return copied references of stored data to the caller. 1725ea61e9acSJeremy L Thompson Caller is responsible for ownership and destruction of the copied references. 1726ea61e9acSJeremy L Thompson See also @ref CeedOperatorLinearAssembleQFunction 172770a7ffb3SJeremy L Thompson 1728c5f45aeaSJeremy L Thompson Note: If the value of `assembled` or `rstr` passed to this function are non-NULL, then it is assumed that they hold valid pointers. 1729c5f45aeaSJeremy L Thompson These objects will be destroyed if `*assembled` or `*rstr` is the only reference to the object. 1730c5f45aeaSJeremy L Thompson 1731ea61e9acSJeremy L Thompson @param[in] op CeedOperator to assemble CeedQFunction 1732ea61e9acSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedQFunction at quadrature points 1733ea61e9acSJeremy L Thompson @param[out] rstr CeedElemRestriction for CeedVector containing assembledCeedQFunction 1734ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 173570a7ffb3SJeremy L Thompson 173670a7ffb3SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 173770a7ffb3SJeremy L Thompson 173870a7ffb3SJeremy L Thompson @ref User 173970a7ffb3SJeremy L Thompson **/ 17402b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleQFunctionBuildOrUpdate(CeedOperator op, CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) { 1741b05f7e9fSJeremy L Thompson int (*LinearAssembleQFunctionUpdate)(CeedOperator, CeedVector, CeedElemRestriction, CeedRequest *) = NULL; 1742b05f7e9fSJeremy L Thompson CeedOperator op_assemble = NULL; 1743bb229da9SJeremy L Thompson CeedOperator op_fallback_parent = NULL; 1744b05f7e9fSJeremy L Thompson 17452b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 174670a7ffb3SJeremy L Thompson 1747b05f7e9fSJeremy L Thompson // Determine if fallback parent or operator has implementation 1748bb229da9SJeremy L Thompson CeedCall(CeedOperatorGetFallbackParent(op, &op_fallback_parent)); 1749bb229da9SJeremy L Thompson if (op_fallback_parent && op_fallback_parent->LinearAssembleQFunctionUpdate) { 1750b05f7e9fSJeremy L Thompson // -- Backend version for op fallback parent is faster, if it exists 1751bb229da9SJeremy L Thompson LinearAssembleQFunctionUpdate = op_fallback_parent->LinearAssembleQFunctionUpdate; 1752bb229da9SJeremy L Thompson op_assemble = op_fallback_parent; 1753b05f7e9fSJeremy L Thompson } else if (op->LinearAssembleQFunctionUpdate) { 1754b05f7e9fSJeremy L Thompson // -- Backend version for op 1755b05f7e9fSJeremy L Thompson LinearAssembleQFunctionUpdate = op->LinearAssembleQFunctionUpdate; 1756b05f7e9fSJeremy L Thompson op_assemble = op; 1757b05f7e9fSJeremy L Thompson } 1758b05f7e9fSJeremy L Thompson 1759b05f7e9fSJeremy L Thompson // Assemble QFunction 1760b05f7e9fSJeremy L Thompson if (LinearAssembleQFunctionUpdate) { 1761b05f7e9fSJeremy L Thompson // Backend or fallback parent version 1762480fae85SJeremy L Thompson bool qf_assembled_is_setup; 17632efa2d85SJeremy L Thompson CeedVector assembled_vec = NULL; 17642efa2d85SJeremy L Thompson CeedElemRestriction assembled_rstr = NULL; 1765480fae85SJeremy L Thompson 17662b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataIsSetup(op->qf_assembled, &qf_assembled_is_setup)); 1767480fae85SJeremy L Thompson if (qf_assembled_is_setup) { 1768d04bbc78SJeremy L Thompson bool update_needed; 1769d04bbc78SJeremy L Thompson 17702b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataGetObjects(op->qf_assembled, &assembled_vec, &assembled_rstr)); 17712b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataIsUpdateNeeded(op->qf_assembled, &update_needed)); 1772b05f7e9fSJeremy L Thompson if (update_needed) CeedCall(LinearAssembleQFunctionUpdate(op_assemble, assembled_vec, assembled_rstr, request)); 177370a7ffb3SJeremy L Thompson } else { 1774b05f7e9fSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleQFunction(op_assemble, &assembled_vec, &assembled_rstr, request)); 17752b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataSetObjects(op->qf_assembled, assembled_vec, assembled_rstr)); 177670a7ffb3SJeremy L Thompson } 17772b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, false)); 17782efa2d85SJeremy L Thompson 1779d04bbc78SJeremy L Thompson // Copy reference from internally held copy 17802b730f8bSJeremy L Thompson CeedCall(CeedVectorReferenceCopy(assembled_vec, assembled)); 17812b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionReferenceCopy(assembled_rstr, rstr)); 1782c5f45aeaSJeremy L Thompson CeedCall(CeedVectorDestroy(&assembled_vec)); 17832b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&assembled_rstr)); 178470a7ffb3SJeremy L Thompson } else { 1785d04bbc78SJeremy L Thompson // Operator fallback 1786d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1787d04bbc78SJeremy L Thompson 17882b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 17896574a04fSJeremy L Thompson if (op_fallback) CeedCall(CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op_fallback, assembled, rstr, request)); 17906574a04fSJeremy L Thompson else return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedOperatorLinearAssembleQFunctionUpdate"); 179170a7ffb3SJeremy L Thompson } 179270a7ffb3SJeremy L Thompson return CEED_ERROR_SUCCESS; 1793eaf62fffSJeremy L Thompson } 1794eaf62fffSJeremy L Thompson 1795eaf62fffSJeremy L Thompson /** 1796eaf62fffSJeremy L Thompson @brief Assemble the diagonal of a square linear CeedOperator 1797eaf62fffSJeremy L Thompson 1798eaf62fffSJeremy L Thompson This overwrites a CeedVector with the diagonal of a linear CeedOperator. 1799eaf62fffSJeremy L Thompson 1800ea61e9acSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and composite CeedOperators with single field sub-operators are supported. 1801eaf62fffSJeremy L Thompson 1802ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1803f04ea552SJeremy L Thompson 1804ea61e9acSJeremy L Thompson @param[in] op CeedOperator to assemble CeedQFunction 1805eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator diagonal 1806ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1807eaf62fffSJeremy L Thompson 1808eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1809eaf62fffSJeremy L Thompson 1810eaf62fffSJeremy L Thompson @ref User 1811eaf62fffSJeremy L Thompson **/ 18122b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled, CeedRequest *request) { 1813f3d47e36SJeremy L Thompson bool is_composite; 18141c66c397SJeremy L Thompson CeedSize input_size = 0, output_size = 0; 18151c66c397SJeremy L Thompson 18162b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1817f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1818eaf62fffSJeremy L Thompson 18192b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 18206574a04fSJeremy L Thompson CeedCheck(input_size == output_size, op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1821c9366a6bSJeremy L Thompson 1822f3d47e36SJeremy L Thompson // Early exit for empty operator 1823f3d47e36SJeremy L Thompson if (!is_composite) { 1824f3d47e36SJeremy L Thompson CeedInt num_elem = 0; 1825f3d47e36SJeremy L Thompson 1826f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 1827f3d47e36SJeremy L Thompson if (num_elem == 0) return CEED_ERROR_SUCCESS; 1828f3d47e36SJeremy L Thompson } 1829f3d47e36SJeremy L Thompson 1830eaf62fffSJeremy L Thompson if (op->LinearAssembleDiagonal) { 1831d04bbc78SJeremy L Thompson // Backend version 18322b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleDiagonal(op, assembled, request)); 1833eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1834eaf62fffSJeremy L Thompson } else if (op->LinearAssembleAddDiagonal) { 1835d04bbc78SJeremy L Thompson // Backend version with zeroing first 18362b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(assembled, 0.0)); 18372b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleAddDiagonal(op, assembled, request)); 1838eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1839eaf62fffSJeremy L Thompson } else { 1840d04bbc78SJeremy L Thompson // Operator fallback 1841d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1842d04bbc78SJeremy L Thompson 18432b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1844d04bbc78SJeremy L Thompson if (op_fallback) { 18452b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleDiagonal(op_fallback, assembled, request)); 1846eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1847eaf62fffSJeremy L Thompson } 1848eaf62fffSJeremy L Thompson } 1849eaf62fffSJeremy L Thompson // Default interface implementation 18502b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(assembled, 0.0)); 18512b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddDiagonal(op, assembled, request)); 1852eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1853eaf62fffSJeremy L Thompson } 1854eaf62fffSJeremy L Thompson 1855eaf62fffSJeremy L Thompson /** 1856eaf62fffSJeremy L Thompson @brief Assemble the diagonal of a square linear CeedOperator 1857eaf62fffSJeremy L Thompson 1858eaf62fffSJeremy L Thompson This sums into a CeedVector the diagonal of a linear CeedOperator. 1859eaf62fffSJeremy L Thompson 1860ea61e9acSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and composite CeedOperators with single field sub-operators are supported. 1861eaf62fffSJeremy L Thompson 1862ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1863f04ea552SJeremy L Thompson 1864ea61e9acSJeremy L Thompson @param[in] op CeedOperator to assemble CeedQFunction 1865eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator diagonal 1866ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1867eaf62fffSJeremy L Thompson 1868eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1869eaf62fffSJeremy L Thompson 1870eaf62fffSJeremy L Thompson @ref User 1871eaf62fffSJeremy L Thompson **/ 18722b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled, CeedRequest *request) { 1873f3d47e36SJeremy L Thompson bool is_composite; 18741c66c397SJeremy L Thompson CeedSize input_size = 0, output_size = 0; 18751c66c397SJeremy L Thompson 18762b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1877f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1878eaf62fffSJeremy L Thompson 18792b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 18806574a04fSJeremy L Thompson CeedCheck(input_size == output_size, op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1881c9366a6bSJeremy L Thompson 1882f3d47e36SJeremy L Thompson // Early exit for empty operator 1883f3d47e36SJeremy L Thompson if (!is_composite) { 1884f3d47e36SJeremy L Thompson CeedInt num_elem = 0; 1885f3d47e36SJeremy L Thompson 1886f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 1887f3d47e36SJeremy L Thompson if (num_elem == 0) return CEED_ERROR_SUCCESS; 1888f3d47e36SJeremy L Thompson } 1889f3d47e36SJeremy L Thompson 1890eaf62fffSJeremy L Thompson if (op->LinearAssembleAddDiagonal) { 1891d04bbc78SJeremy L Thompson // Backend version 18922b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleAddDiagonal(op, assembled, request)); 1893eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1894eaf62fffSJeremy L Thompson } else { 1895d04bbc78SJeremy L Thompson // Operator fallback 1896d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1897d04bbc78SJeremy L Thompson 18982b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1899d04bbc78SJeremy L Thompson if (op_fallback) { 19002b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddDiagonal(op_fallback, assembled, request)); 1901eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1902eaf62fffSJeremy L Thompson } 1903eaf62fffSJeremy L Thompson } 1904eaf62fffSJeremy L Thompson // Default interface implementation 1905eaf62fffSJeremy L Thompson if (is_composite) { 19062b730f8bSJeremy L Thompson CeedCall(CeedCompositeOperatorLinearAssembleAddDiagonal(op, request, false, assembled)); 1907eaf62fffSJeremy L Thompson } else { 19082b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssembleAddDiagonal_Core(op, request, false, assembled)); 1909eaf62fffSJeremy L Thompson } 1910d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 1911eaf62fffSJeremy L Thompson } 1912eaf62fffSJeremy L Thompson 1913eaf62fffSJeremy L Thompson /** 191401f0e615SJames Wright @brief Fully assemble the point-block diagonal pattern of a linear operator. 191501f0e615SJames Wright 191601f0e615SJames Wright Expected to be used in conjunction with CeedOperatorLinearAssemblePointBlockDiagonal(). 191701f0e615SJames Wright 191801f0e615SJames Wright 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 191901f0e615SJames Wright matrix in entry (i, j). 192001f0e615SJames Wright Note that the (i, j) pairs are unique. 192101f0e615SJames Wright This function returns the number of entries and their (i, j) locations, while CeedOperatorLinearAssemblePointBlockDiagonal() provides the values in 192201f0e615SJames Wright the same ordering. 192301f0e615SJames Wright 192401f0e615SJames Wright This will generally be slow unless your operator is low-order. 192501f0e615SJames Wright 192601f0e615SJames Wright Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 192701f0e615SJames Wright 192801f0e615SJames Wright @param[in] op CeedOperator to assemble 192901f0e615SJames Wright @param[out] num_entries Number of entries in coordinate nonzero pattern 193001f0e615SJames Wright @param[out] rows Row number for each entry 193101f0e615SJames Wright @param[out] cols Column number for each entry 193201f0e615SJames Wright 193301f0e615SJames Wright @ref User 193401f0e615SJames Wright **/ 193501f0e615SJames Wright int CeedOperatorLinearAssemblePointBlockDiagonalSymbolic(CeedOperator op, CeedSize *num_entries, CeedInt **rows, CeedInt **cols) { 193601f0e615SJames Wright Ceed ceed; 193701f0e615SJames Wright bool is_composite; 193801f0e615SJames Wright CeedInt num_active_components, num_sub_operators; 193901f0e615SJames Wright CeedOperator *sub_operators; 194001f0e615SJames Wright 194101f0e615SJames Wright CeedCall(CeedOperatorGetCeed(op, &ceed)); 194201f0e615SJames Wright CeedCall(CeedOperatorIsComposite(op, &is_composite)); 194301f0e615SJames Wright 194401f0e615SJames Wright CeedSize input_size = 0, output_size = 0; 194501f0e615SJames Wright CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 194601f0e615SJames Wright CeedCheck(input_size == output_size, ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 194701f0e615SJames Wright 194801f0e615SJames Wright if (is_composite) { 194901f0e615SJames Wright CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub_operators)); 195001f0e615SJames Wright CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 195101f0e615SJames Wright } else { 195201f0e615SJames Wright sub_operators = &op; 195301f0e615SJames Wright num_sub_operators = 1; 195401f0e615SJames Wright } 195501f0e615SJames Wright 1956*506b1a0cSSebastian Grimberg // Verify operator can be assembled correctly 1957*506b1a0cSSebastian Grimberg { 195801f0e615SJames Wright CeedOperatorAssemblyData data; 1959*506b1a0cSSebastian Grimberg CeedInt num_active_elem_rstrs, comp_stride; 196001f0e615SJames Wright CeedElemRestriction *active_elem_rstrs; 196101f0e615SJames Wright 196201f0e615SJames Wright // Get initial values to check against 196301f0e615SJames Wright CeedCall(CeedOperatorGetOperatorAssemblyData(sub_operators[0], &data)); 1964*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorAssemblyDataGetElemRestrictions(data, &num_active_elem_rstrs, &active_elem_rstrs, NULL, NULL)); 196501f0e615SJames Wright CeedCall(CeedElemRestrictionGetCompStride(active_elem_rstrs[0], &comp_stride)); 196601f0e615SJames Wright CeedCall(CeedElemRestrictionGetNumComponents(active_elem_rstrs[0], &num_active_components)); 196701f0e615SJames Wright 1968*506b1a0cSSebastian Grimberg // Verify that all active element restrictions have same component stride and number of components 196901f0e615SJames Wright for (CeedInt k = 0; k < num_sub_operators; k++) { 197001f0e615SJames Wright CeedCall(CeedOperatorGetOperatorAssemblyData(sub_operators[k], &data)); 1971*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorAssemblyDataGetElemRestrictions(data, &num_active_elem_rstrs, &active_elem_rstrs, NULL, NULL)); 197201f0e615SJames Wright for (CeedInt i = 0; i < num_active_elem_rstrs; i++) { 1973*506b1a0cSSebastian Grimberg CeedInt comp_stride_sub, num_active_components_sub; 1974*506b1a0cSSebastian Grimberg 197501f0e615SJames Wright CeedCall(CeedElemRestrictionGetCompStride(active_elem_rstrs[i], &comp_stride_sub)); 197601f0e615SJames Wright CeedCheck(comp_stride == comp_stride_sub, ceed, CEED_ERROR_DIMENSION, 197701f0e615SJames Wright "Active element restrictions must have the same component stride: %d vs %d", comp_stride, comp_stride_sub); 197801f0e615SJames Wright CeedCall(CeedElemRestrictionGetNumComponents(active_elem_rstrs[i], &num_active_components_sub)); 197901f0e615SJames Wright CeedCheck(num_active_components == num_active_components_sub, ceed, CEED_ERROR_INCOMPATIBLE, 198001f0e615SJames Wright "All suboperators must have the same number of output components"); 198101f0e615SJames Wright } 198201f0e615SJames Wright } 198301f0e615SJames Wright } 198401f0e615SJames Wright *num_entries = input_size * num_active_components; 198501f0e615SJames Wright CeedCall(CeedCalloc(*num_entries, rows)); 198601f0e615SJames Wright CeedCall(CeedCalloc(*num_entries, cols)); 198701f0e615SJames Wright 198801f0e615SJames Wright for (CeedInt o = 0; o < num_sub_operators; o++) { 1989*506b1a0cSSebastian Grimberg CeedElemRestriction active_elem_rstr, point_block_active_elem_rstr; 199001f0e615SJames Wright CeedInt comp_stride, num_elem, elem_size; 1991*506b1a0cSSebastian Grimberg const CeedInt *offsets, *point_block_offsets; 199201f0e615SJames Wright 199301f0e615SJames Wright CeedCall(CeedOperatorGetActiveElemRestriction(sub_operators[o], &active_elem_rstr)); 199401f0e615SJames Wright CeedCall(CeedElemRestrictionGetCompStride(active_elem_rstr, &comp_stride)); 199501f0e615SJames Wright CeedCall(CeedElemRestrictionGetNumElements(active_elem_rstr, &num_elem)); 199601f0e615SJames Wright CeedCall(CeedElemRestrictionGetElementSize(active_elem_rstr, &elem_size)); 199701f0e615SJames Wright CeedCall(CeedElemRestrictionGetOffsets(active_elem_rstr, CEED_MEM_HOST, &offsets)); 199801f0e615SJames Wright 1999*506b1a0cSSebastian Grimberg CeedCall(CeedOperatorCreateActivePointBlockRestriction(active_elem_rstr, &point_block_active_elem_rstr)); 2000*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionGetOffsets(point_block_active_elem_rstr, CEED_MEM_HOST, &point_block_offsets)); 200101f0e615SJames Wright 200201f0e615SJames Wright for (CeedSize i = 0; i < num_elem * elem_size; i++) { 200301f0e615SJames Wright for (CeedInt c_out = 0; c_out < num_active_components; c_out++) { 200401f0e615SJames Wright for (CeedInt c_in = 0; c_in < num_active_components; c_in++) { 2005*506b1a0cSSebastian Grimberg (*rows)[point_block_offsets[i] + c_out * num_active_components + c_in] = offsets[i] + c_out * comp_stride; 2006*506b1a0cSSebastian Grimberg (*cols)[point_block_offsets[i] + c_out * num_active_components + c_in] = offsets[i] + c_in * comp_stride; 200701f0e615SJames Wright } 200801f0e615SJames Wright } 200901f0e615SJames Wright } 201001f0e615SJames Wright 201101f0e615SJames Wright CeedCall(CeedElemRestrictionRestoreOffsets(active_elem_rstr, &offsets)); 2012*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionRestoreOffsets(point_block_active_elem_rstr, &point_block_offsets)); 2013*506b1a0cSSebastian Grimberg CeedCall(CeedElemRestrictionDestroy(&point_block_active_elem_rstr)); 201401f0e615SJames Wright } 201501f0e615SJames Wright return CEED_ERROR_SUCCESS; 201601f0e615SJames Wright } 201701f0e615SJames Wright 201801f0e615SJames Wright /** 2019eaf62fffSJeremy L Thompson @brief Assemble the point block diagonal of a square linear CeedOperator 2020eaf62fffSJeremy L Thompson 2021ea61e9acSJeremy L Thompson This overwrites a CeedVector with the point block diagonal of a linear CeedOperator. 2022eaf62fffSJeremy L Thompson 2023ea61e9acSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and composite CeedOperators with single field sub-operators are supported. 2024eaf62fffSJeremy L Thompson 2025ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 2026f04ea552SJeremy L Thompson 2027ea61e9acSJeremy L Thompson @param[in] op CeedOperator to assemble CeedQFunction 2028ea61e9acSJeremy 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 2029ea61e9acSJeremy 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, 2030ea61e9acSJeremy L Thompson component in]. 2031ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 2032eaf62fffSJeremy L Thompson 2033eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2034eaf62fffSJeremy L Thompson 2035eaf62fffSJeremy L Thompson @ref User 2036eaf62fffSJeremy L Thompson **/ 20372b730f8bSJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op, CeedVector assembled, CeedRequest *request) { 2038f3d47e36SJeremy L Thompson bool is_composite; 20391c66c397SJeremy L Thompson CeedSize input_size = 0, output_size = 0; 20401c66c397SJeremy L Thompson 20412b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 2042f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 2043eaf62fffSJeremy L Thompson 20442b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 20456574a04fSJeremy L Thompson CeedCheck(input_size == output_size, op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 2046c9366a6bSJeremy L Thompson 2047f3d47e36SJeremy L Thompson // Early exit for empty operator 2048f3d47e36SJeremy L Thompson if (!is_composite) { 2049f3d47e36SJeremy L Thompson CeedInt num_elem = 0; 2050f3d47e36SJeremy L Thompson 2051f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 2052f3d47e36SJeremy L Thompson if (num_elem == 0) return CEED_ERROR_SUCCESS; 2053f3d47e36SJeremy L Thompson } 2054f3d47e36SJeremy L Thompson 2055eaf62fffSJeremy L Thompson if (op->LinearAssemblePointBlockDiagonal) { 2056d04bbc78SJeremy L Thompson // Backend version 20572b730f8bSJeremy L Thompson CeedCall(op->LinearAssemblePointBlockDiagonal(op, assembled, request)); 2058eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2059eaf62fffSJeremy L Thompson } else if (op->LinearAssembleAddPointBlockDiagonal) { 2060d04bbc78SJeremy L Thompson // Backend version with zeroing first 20612b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(assembled, 0.0)); 20622b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, request)); 2063eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2064eaf62fffSJeremy L Thompson } else { 2065d04bbc78SJeremy L Thompson // Operator fallback 2066d04bbc78SJeremy L Thompson CeedOperator op_fallback; 2067d04bbc78SJeremy L Thompson 20682b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 2069d04bbc78SJeremy L Thompson if (op_fallback) { 20702b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssemblePointBlockDiagonal(op_fallback, assembled, request)); 2071eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2072eaf62fffSJeremy L Thompson } 2073eaf62fffSJeremy L Thompson } 2074eaf62fffSJeremy L Thompson // Default interface implementation 20752b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(assembled, 0.0)); 20762b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, request)); 2077eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2078eaf62fffSJeremy L Thompson } 2079eaf62fffSJeremy L Thompson 2080eaf62fffSJeremy L Thompson /** 2081eaf62fffSJeremy L Thompson @brief Assemble the point block diagonal of a square linear CeedOperator 2082eaf62fffSJeremy L Thompson 2083ea61e9acSJeremy L Thompson This sums into a CeedVector with the point block diagonal of a linear CeedOperator. 2084eaf62fffSJeremy L Thompson 2085ea61e9acSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and composite CeedOperators with single field sub-operators are supported. 2086eaf62fffSJeremy L Thompson 2087ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 2088f04ea552SJeremy L Thompson 2089ea61e9acSJeremy L Thompson @param[in] op CeedOperator to assemble CeedQFunction 2090ea61e9acSJeremy 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 2091ea61e9acSJeremy 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, 2092ea61e9acSJeremy L Thompson component in]. 2093ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 2094eaf62fffSJeremy L Thompson 2095eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2096eaf62fffSJeremy L Thompson 2097eaf62fffSJeremy L Thompson @ref User 2098eaf62fffSJeremy L Thompson **/ 20992b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op, CeedVector assembled, CeedRequest *request) { 2100f3d47e36SJeremy L Thompson bool is_composite; 21011c66c397SJeremy L Thompson CeedSize input_size = 0, output_size = 0; 21021c66c397SJeremy L Thompson 21032b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 2104f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 2105eaf62fffSJeremy L Thompson 21062b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 21076574a04fSJeremy L Thompson CeedCheck(input_size == output_size, op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 2108c9366a6bSJeremy L Thompson 2109f3d47e36SJeremy L Thompson // Early exit for empty operator 2110f3d47e36SJeremy L Thompson if (!is_composite) { 2111f3d47e36SJeremy L Thompson CeedInt num_elem = 0; 2112f3d47e36SJeremy L Thompson 2113f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 2114f3d47e36SJeremy L Thompson if (num_elem == 0) return CEED_ERROR_SUCCESS; 2115f3d47e36SJeremy L Thompson } 2116f3d47e36SJeremy L Thompson 2117eaf62fffSJeremy L Thompson if (op->LinearAssembleAddPointBlockDiagonal) { 2118d04bbc78SJeremy L Thompson // Backend version 21192b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleAddPointBlockDiagonal(op, assembled, request)); 2120eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2121eaf62fffSJeremy L Thompson } else { 2122d04bbc78SJeremy L Thompson // Operator fallback 2123d04bbc78SJeremy L Thompson CeedOperator op_fallback; 2124d04bbc78SJeremy L Thompson 21252b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 2126d04bbc78SJeremy L Thompson if (op_fallback) { 21272b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddPointBlockDiagonal(op_fallback, assembled, request)); 2128eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2129eaf62fffSJeremy L Thompson } 2130eaf62fffSJeremy L Thompson } 2131ea61e9acSJeremy L Thompson // Default interface implementation 2132eaf62fffSJeremy L Thompson if (is_composite) { 21332b730f8bSJeremy L Thompson CeedCall(CeedCompositeOperatorLinearAssembleAddDiagonal(op, request, true, assembled)); 2134eaf62fffSJeremy L Thompson } else { 21352b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssembleAddDiagonal_Core(op, request, true, assembled)); 2136eaf62fffSJeremy L Thompson } 2137d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 2138eaf62fffSJeremy L Thompson } 2139eaf62fffSJeremy L Thompson 2140eaf62fffSJeremy L Thompson /** 2141eaf62fffSJeremy L Thompson @brief Fully assemble the nonzero pattern of a linear operator. 2142eaf62fffSJeremy L Thompson 2143ea61e9acSJeremy L Thompson Expected to be used in conjunction with CeedOperatorLinearAssemble(). 2144eaf62fffSJeremy L Thompson 2145ea61e9acSJeremy 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 21469fd66db6SSebastian Grimberg matrix in entry (i, j). 21479fd66db6SSebastian Grimberg Note that the (i, j) pairs are not unique and may repeat. 21489fd66db6SSebastian Grimberg This function returns the number of entries and their (i, j) locations, while CeedOperatorLinearAssemble() provides the values in the same ordering. 2149eaf62fffSJeremy L Thompson 2150eaf62fffSJeremy L Thompson This will generally be slow unless your operator is low-order. 2151eaf62fffSJeremy L Thompson 2152ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 2153f04ea552SJeremy L Thompson 2154eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 2155eaf62fffSJeremy L Thompson @param[out] num_entries Number of entries in coordinate nonzero pattern 2156eaf62fffSJeremy L Thompson @param[out] rows Row number for each entry 2157eaf62fffSJeremy L Thompson @param[out] cols Column number for each entry 2158eaf62fffSJeremy L Thompson 2159eaf62fffSJeremy L Thompson @ref User 2160eaf62fffSJeremy L Thompson **/ 21612b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleSymbolic(CeedOperator op, CeedSize *num_entries, CeedInt **rows, CeedInt **cols) { 21621c66c397SJeremy L Thompson bool is_composite; 21631c66c397SJeremy L Thompson CeedInt num_suboperators, offset = 0; 2164b94338b9SJed Brown CeedSize single_entries; 2165eaf62fffSJeremy L Thompson CeedOperator *sub_operators; 21661c66c397SJeremy L Thompson 21672b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 2168f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 2169eaf62fffSJeremy L Thompson 2170eaf62fffSJeremy L Thompson if (op->LinearAssembleSymbolic) { 2171d04bbc78SJeremy L Thompson // Backend version 21722b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleSymbolic(op, num_entries, rows, cols)); 2173eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2174eaf62fffSJeremy L Thompson } else { 2175d04bbc78SJeremy L Thompson // Operator fallback 2176d04bbc78SJeremy L Thompson CeedOperator op_fallback; 2177d04bbc78SJeremy L Thompson 21782b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 2179d04bbc78SJeremy L Thompson if (op_fallback) { 21802b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleSymbolic(op_fallback, num_entries, rows, cols)); 2181eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2182eaf62fffSJeremy L Thompson } 2183eaf62fffSJeremy L Thompson } 2184eaf62fffSJeremy L Thompson 2185eaf62fffSJeremy L Thompson // Default interface implementation 2186eaf62fffSJeremy L Thompson 2187*506b1a0cSSebastian Grimberg // Count entries and allocate rows, cols arrays 2188eaf62fffSJeremy L Thompson *num_entries = 0; 2189eaf62fffSJeremy L Thompson if (is_composite) { 2190c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 2191c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 219292ae7e47SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; ++k) { 21932b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemblyCountEntries(sub_operators[k], &single_entries)); 2194eaf62fffSJeremy L Thompson *num_entries += single_entries; 2195eaf62fffSJeremy L Thompson } 2196eaf62fffSJeremy L Thompson } else { 21972b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemblyCountEntries(op, &single_entries)); 2198eaf62fffSJeremy L Thompson *num_entries += single_entries; 2199eaf62fffSJeremy L Thompson } 22002b730f8bSJeremy L Thompson CeedCall(CeedCalloc(*num_entries, rows)); 22012b730f8bSJeremy L Thompson CeedCall(CeedCalloc(*num_entries, cols)); 2202eaf62fffSJeremy L Thompson 2203*506b1a0cSSebastian Grimberg // Assemble nonzero locations 2204eaf62fffSJeremy L Thompson if (is_composite) { 2205c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 2206c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 220792ae7e47SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; ++k) { 22082b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssembleSymbolic(sub_operators[k], offset, *rows, *cols)); 22092b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemblyCountEntries(sub_operators[k], &single_entries)); 2210eaf62fffSJeremy L Thompson offset += single_entries; 2211eaf62fffSJeremy L Thompson } 2212eaf62fffSJeremy L Thompson } else { 22132b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssembleSymbolic(op, offset, *rows, *cols)); 2214eaf62fffSJeremy L Thompson } 2215eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2216eaf62fffSJeremy L Thompson } 2217eaf62fffSJeremy L Thompson 2218eaf62fffSJeremy L Thompson /** 2219eaf62fffSJeremy L Thompson @brief Fully assemble the nonzero entries of a linear operator. 2220eaf62fffSJeremy L Thompson 2221ea61e9acSJeremy L Thompson Expected to be used in conjunction with CeedOperatorLinearAssembleSymbolic(). 2222eaf62fffSJeremy L Thompson 2223ea61e9acSJeremy 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 22249fd66db6SSebastian Grimberg matrix in entry (i, j). 22259fd66db6SSebastian Grimberg Note that the (i, j) pairs are not unique and may repeat. 22269fd66db6SSebastian Grimberg This function returns the values of the nonzero entries to be added, their (i, j) locations are provided by CeedOperatorLinearAssembleSymbolic() 2227eaf62fffSJeremy L Thompson 2228eaf62fffSJeremy L Thompson This will generally be slow unless your operator is low-order. 2229eaf62fffSJeremy L Thompson 2230ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 2231f04ea552SJeremy L Thompson 2232eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 2233eaf62fffSJeremy L Thompson @param[out] values Values to assemble into matrix 2234eaf62fffSJeremy L Thompson 2235eaf62fffSJeremy L Thompson @ref User 2236eaf62fffSJeremy L Thompson **/ 2237eaf62fffSJeremy L Thompson int CeedOperatorLinearAssemble(CeedOperator op, CeedVector values) { 22381c66c397SJeremy L Thompson bool is_composite; 22391c66c397SJeremy L Thompson CeedInt num_suboperators, offset = 0; 2240b94338b9SJed Brown CeedSize single_entries = 0; 2241eaf62fffSJeremy L Thompson CeedOperator *sub_operators; 22421c66c397SJeremy L Thompson 22432b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 2244f3d47e36SJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 2245f3d47e36SJeremy L Thompson 2246f3d47e36SJeremy L Thompson // Early exit for empty operator 2247f3d47e36SJeremy L Thompson if (!is_composite) { 2248f3d47e36SJeremy L Thompson CeedInt num_elem = 0; 2249f3d47e36SJeremy L Thompson 2250f3d47e36SJeremy L Thompson CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 2251f3d47e36SJeremy L Thompson if (num_elem == 0) return CEED_ERROR_SUCCESS; 2252f3d47e36SJeremy L Thompson } 2253eaf62fffSJeremy L Thompson 2254eaf62fffSJeremy L Thompson if (op->LinearAssemble) { 2255d04bbc78SJeremy L Thompson // Backend version 22562b730f8bSJeremy L Thompson CeedCall(op->LinearAssemble(op, values)); 2257eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2258eaf62fffSJeremy L Thompson } else { 2259d04bbc78SJeremy L Thompson // Operator fallback 2260d04bbc78SJeremy L Thompson CeedOperator op_fallback; 2261d04bbc78SJeremy L Thompson 22622b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 2263d04bbc78SJeremy L Thompson if (op_fallback) { 22642b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssemble(op_fallback, values)); 2265eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2266eaf62fffSJeremy L Thompson } 2267eaf62fffSJeremy L Thompson } 2268eaf62fffSJeremy L Thompson 2269eaf62fffSJeremy L Thompson // Default interface implementation 227028ec399dSJeremy L Thompson CeedCall(CeedVectorSetValue(values, 0.0)); 2271eaf62fffSJeremy L Thompson if (is_composite) { 2272c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 2273c6ebc35dSJeremy L Thompson CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 2274cefa2673SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; k++) { 22752b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemble(sub_operators[k], offset, values)); 22762b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemblyCountEntries(sub_operators[k], &single_entries)); 2277eaf62fffSJeremy L Thompson offset += single_entries; 2278eaf62fffSJeremy L Thompson } 2279eaf62fffSJeremy L Thompson } else { 22802b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemble(op, offset, values)); 2281eaf62fffSJeremy L Thompson } 2282eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2283eaf62fffSJeremy L Thompson } 2284eaf62fffSJeremy L Thompson 2285eaf62fffSJeremy L Thompson /** 228675f0d5a4SJeremy L Thompson @brief Get the multiplicity of nodes across suboperators in a composite CeedOperator 228775f0d5a4SJeremy L Thompson 228875f0d5a4SJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 228975f0d5a4SJeremy L Thompson 229075f0d5a4SJeremy L Thompson @param[in] op Composite CeedOperator 229175f0d5a4SJeremy L Thompson @param[in] num_skip_indices Number of suboperators to skip 229275f0d5a4SJeremy L Thompson @param[in] skip_indices Array of indices of suboperators to skip 229375f0d5a4SJeremy L Thompson @param[out] mult Vector to store multiplicity (of size l_size) 229475f0d5a4SJeremy L Thompson 229575f0d5a4SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 229675f0d5a4SJeremy L Thompson 229775f0d5a4SJeremy L Thompson @ref User 229875f0d5a4SJeremy L Thompson **/ 229975f0d5a4SJeremy L Thompson int CeedCompositeOperatorGetMultiplicity(CeedOperator op, CeedInt num_skip_indices, CeedInt *skip_indices, CeedVector mult) { 230075f0d5a4SJeremy L Thompson Ceed ceed; 2301b275c451SJeremy L Thompson CeedInt num_suboperators; 230275f0d5a4SJeremy L Thompson CeedSize l_vec_len; 230375f0d5a4SJeremy L Thompson CeedScalar *mult_array; 230475f0d5a4SJeremy L Thompson CeedVector ones_l_vec; 23057c1dbaffSSebastian Grimberg CeedElemRestriction elem_rstr, mult_elem_rstr; 2306b275c451SJeremy L Thompson CeedOperator *sub_operators; 230775f0d5a4SJeremy L Thompson 23081c66c397SJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 23091c66c397SJeremy L Thompson 231075f0d5a4SJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 231175f0d5a4SJeremy L Thompson 231275f0d5a4SJeremy L Thompson // Zero mult vector 231375f0d5a4SJeremy L Thompson CeedCall(CeedVectorSetValue(mult, 0.0)); 231475f0d5a4SJeremy L Thompson 231575f0d5a4SJeremy L Thompson // Get suboperators 2316b275c451SJeremy L Thompson CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 2317b275c451SJeremy L Thompson CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 2318b275c451SJeremy L Thompson if (num_suboperators == 0) return CEED_ERROR_SUCCESS; 231975f0d5a4SJeremy L Thompson 232075f0d5a4SJeremy L Thompson // Work vector 232175f0d5a4SJeremy L Thompson CeedCall(CeedVectorGetLength(mult, &l_vec_len)); 232275f0d5a4SJeremy L Thompson CeedCall(CeedVectorCreate(ceed, l_vec_len, &ones_l_vec)); 232375f0d5a4SJeremy L Thompson CeedCall(CeedVectorSetValue(ones_l_vec, 1.0)); 232475f0d5a4SJeremy L Thompson CeedCall(CeedVectorGetArray(mult, CEED_MEM_HOST, &mult_array)); 232575f0d5a4SJeremy L Thompson 232675f0d5a4SJeremy L Thompson // Compute multiplicity across suboperators 2327b275c451SJeremy L Thompson for (CeedInt i = 0; i < num_suboperators; i++) { 232875f0d5a4SJeremy L Thompson const CeedScalar *sub_mult_array; 232975f0d5a4SJeremy L Thompson CeedVector sub_mult_l_vec, ones_e_vec; 233075f0d5a4SJeremy L Thompson 233175f0d5a4SJeremy L Thompson // -- Check for suboperator to skip 233275f0d5a4SJeremy L Thompson for (CeedInt j = 0; j < num_skip_indices; j++) { 233375f0d5a4SJeremy L Thompson if (skip_indices[j] == i) continue; 233475f0d5a4SJeremy L Thompson } 233575f0d5a4SJeremy L Thompson 233675f0d5a4SJeremy L Thompson // -- Sub operator multiplicity 2337437c7c90SJeremy L Thompson CeedCall(CeedOperatorGetActiveElemRestriction(sub_operators[i], &elem_rstr)); 23387c1dbaffSSebastian Grimberg CeedCall(CeedElemRestrictionCreateUnorientedCopy(elem_rstr, &mult_elem_rstr)); 23397c1dbaffSSebastian Grimberg CeedCall(CeedElemRestrictionCreateVector(mult_elem_rstr, &sub_mult_l_vec, &ones_e_vec)); 234075f0d5a4SJeremy L Thompson CeedCall(CeedVectorSetValue(sub_mult_l_vec, 0.0)); 23417c1dbaffSSebastian Grimberg CeedCall(CeedElemRestrictionApply(mult_elem_rstr, CEED_NOTRANSPOSE, ones_l_vec, ones_e_vec, CEED_REQUEST_IMMEDIATE)); 23427c1dbaffSSebastian Grimberg CeedCall(CeedElemRestrictionApply(mult_elem_rstr, CEED_TRANSPOSE, ones_e_vec, sub_mult_l_vec, CEED_REQUEST_IMMEDIATE)); 234375f0d5a4SJeremy L Thompson CeedCall(CeedVectorGetArrayRead(sub_mult_l_vec, CEED_MEM_HOST, &sub_mult_array)); 234475f0d5a4SJeremy L Thompson // ---- Flag every node present in the current suboperator 234575f0d5a4SJeremy L Thompson for (CeedInt j = 0; j < l_vec_len; j++) { 234675f0d5a4SJeremy L Thompson if (sub_mult_array[j] > 0.0) mult_array[j] += 1.0; 234775f0d5a4SJeremy L Thompson } 234875f0d5a4SJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(sub_mult_l_vec, &sub_mult_array)); 234975f0d5a4SJeremy L Thompson CeedCall(CeedVectorDestroy(&sub_mult_l_vec)); 235075f0d5a4SJeremy L Thompson CeedCall(CeedVectorDestroy(&ones_e_vec)); 23517c1dbaffSSebastian Grimberg CeedCall(CeedElemRestrictionDestroy(&mult_elem_rstr)); 235275f0d5a4SJeremy L Thompson } 235375f0d5a4SJeremy L Thompson CeedCall(CeedVectorRestoreArray(mult, &mult_array)); 2354811d0ccfSJeremy L Thompson CeedCall(CeedVectorDestroy(&ones_l_vec)); 235575f0d5a4SJeremy L Thompson return CEED_ERROR_SUCCESS; 235675f0d5a4SJeremy L Thompson } 235775f0d5a4SJeremy L Thompson 235875f0d5a4SJeremy L Thompson /** 2359ea61e9acSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators for a CeedOperator, creating the prolongation basis from the fine and coarse 2360ea61e9acSJeremy L Thompson grid interpolation 2361eaf62fffSJeremy L Thompson 236258e4b056SJeremy L Thompson Note: Calling this function asserts that setup is complete and sets all four CeedOperators as immutable. 2363f04ea552SJeremy L Thompson 2364eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 236585bb9dcfSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter, or NULL if not creating prolongation/restriction operators 2366eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 2367eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 2368eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 236985bb9dcfSJeremy L Thompson @param[out] op_prolong Coarse to fine operator, or NULL 23707758292fSSebastian Grimberg @param[out] op_restrict Fine to coarse operator, or NULL 2371eaf62fffSJeremy L Thompson 2372eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2373eaf62fffSJeremy L Thompson 2374eaf62fffSJeremy L Thompson @ref User 2375eaf62fffSJeremy L Thompson **/ 23762b730f8bSJeremy L Thompson int CeedOperatorMultigridLevelCreate(CeedOperator op_fine, CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 23777758292fSSebastian Grimberg CeedOperator *op_coarse, CeedOperator *op_prolong, CeedOperator *op_restrict) { 23781c66c397SJeremy L Thompson CeedBasis basis_c_to_f = NULL; 23791c66c397SJeremy L Thompson 23802b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op_fine)); 2381eaf62fffSJeremy L Thompson 238283d6adf3SZach Atkins // Build prolongation matrix, if required 23837758292fSSebastian Grimberg if (op_prolong || op_restrict) { 238483d6adf3SZach Atkins CeedBasis basis_fine; 23851c66c397SJeremy L Thompson 23862b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveBasis(op_fine, &basis_fine)); 23872b730f8bSJeremy L Thompson CeedCall(CeedBasisCreateProjection(basis_coarse, basis_fine, &basis_c_to_f)); 238883d6adf3SZach Atkins } 2389eaf62fffSJeremy L Thompson 2390f113e5dcSJeremy L Thompson // Core code 23917758292fSSebastian Grimberg CeedCall(CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, basis_coarse, basis_c_to_f, op_coarse, op_prolong, op_restrict)); 2392eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2393eaf62fffSJeremy L Thompson } 2394eaf62fffSJeremy L Thompson 2395eaf62fffSJeremy L Thompson /** 2396ea61e9acSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators for a CeedOperator with a tensor basis for the active basis 2397eaf62fffSJeremy L Thompson 239858e4b056SJeremy L Thompson Note: Calling this function asserts that setup is complete and sets all four CeedOperators as immutable. 2399f04ea552SJeremy L Thompson 2400eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 240185bb9dcfSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter, or NULL if not creating prolongation/restriction operators 2402eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 2403eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 240485bb9dcfSJeremy L Thompson @param[in] interp_c_to_f Matrix for coarse to fine interpolation, or NULL if not creating prolongation/restriction operators 2405eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 240685bb9dcfSJeremy L Thompson @param[out] op_prolong Coarse to fine operator, or NULL 24077758292fSSebastian Grimberg @param[out] op_restrict Fine to coarse operator, or NULL 2408eaf62fffSJeremy L Thompson 2409eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2410eaf62fffSJeremy L Thompson 2411eaf62fffSJeremy L Thompson @ref User 2412eaf62fffSJeremy L Thompson **/ 24132b730f8bSJeremy L Thompson int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator op_fine, CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 24142b730f8bSJeremy L Thompson const CeedScalar *interp_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong, 24157758292fSSebastian Grimberg CeedOperator *op_restrict) { 2416eaf62fffSJeremy L Thompson Ceed ceed; 24171c66c397SJeremy L Thompson CeedInt Q_f, Q_c; 24181c66c397SJeremy L Thompson CeedBasis basis_fine, basis_c_to_f = NULL; 24191c66c397SJeremy L Thompson 24201c66c397SJeremy L Thompson CeedCall(CeedOperatorCheckReady(op_fine)); 24212b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op_fine, &ceed)); 2422eaf62fffSJeremy L Thompson 2423eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 24242b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveBasis(op_fine, &basis_fine)); 24252b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f)); 24262b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c)); 24276574a04fSJeremy L Thompson CeedCheck(Q_f == Q_c, ceed, CEED_ERROR_DIMENSION, "Bases must have compatible quadrature spaces"); 2428eaf62fffSJeremy L Thompson 242983d6adf3SZach Atkins // Create coarse to fine basis, if required 24307758292fSSebastian Grimberg if (op_prolong || op_restrict) { 24311c66c397SJeremy L Thompson CeedInt dim, num_comp, num_nodes_c, P_1d_f, P_1d_c; 24321c66c397SJeremy L Thompson CeedScalar *q_ref, *q_weight, *grad; 24331c66c397SJeremy L Thompson 243483d6adf3SZach Atkins // Check if interpolation matrix is provided 24356574a04fSJeremy L Thompson CeedCheck(interp_c_to_f, ceed, CEED_ERROR_INCOMPATIBLE, 24366574a04fSJeremy L Thompson "Prolongation or restriction operator creation requires coarse-to-fine interpolation matrix"); 24372b730f8bSJeremy L Thompson CeedCall(CeedBasisGetDimension(basis_fine, &dim)); 24382b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumComponents(basis_fine, &num_comp)); 24392b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumNodes1D(basis_fine, &P_1d_f)); 24402b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c)); 24412b730f8bSJeremy L Thompson P_1d_c = dim == 1 ? num_nodes_c : dim == 2 ? sqrt(num_nodes_c) : cbrt(num_nodes_c); 24422b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d_f, &q_ref)); 24432b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d_f, &q_weight)); 24442b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d_f * P_1d_c * dim, &grad)); 24452b730f8bSJeremy 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)); 24462b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_ref)); 24472b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_weight)); 24482b730f8bSJeremy L Thompson CeedCall(CeedFree(&grad)); 244983d6adf3SZach Atkins } 2450eaf62fffSJeremy L Thompson 2451eaf62fffSJeremy L Thompson // Core code 24527758292fSSebastian Grimberg CeedCall(CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, basis_coarse, basis_c_to_f, op_coarse, op_prolong, op_restrict)); 2453eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2454eaf62fffSJeremy L Thompson } 2455eaf62fffSJeremy L Thompson 2456eaf62fffSJeremy L Thompson /** 2457ea61e9acSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators for a CeedOperator with a non-tensor basis for the active vector 2458eaf62fffSJeremy L Thompson 245958e4b056SJeremy L Thompson Note: Calling this function asserts that setup is complete and sets all four CeedOperators as immutable. 2460f04ea552SJeremy L Thompson 2461eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 246285bb9dcfSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter, or NULL if not creating prolongation/restriction operators 2463eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 2464eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 246585bb9dcfSJeremy L Thompson @param[in] interp_c_to_f Matrix for coarse to fine interpolation, or NULL if not creating prolongation/restriction operators 2466eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 246785bb9dcfSJeremy L Thompson @param[out] op_prolong Coarse to fine operator, or NULL 24687758292fSSebastian Grimberg @param[out] op_restrict Fine to coarse operator, or NULL 2469eaf62fffSJeremy L Thompson 2470eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2471eaf62fffSJeremy L Thompson 2472eaf62fffSJeremy L Thompson @ref User 2473eaf62fffSJeremy L Thompson **/ 24742b730f8bSJeremy L Thompson int CeedOperatorMultigridLevelCreateH1(CeedOperator op_fine, CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 24757758292fSSebastian Grimberg const CeedScalar *interp_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong, 24767758292fSSebastian Grimberg CeedOperator *op_restrict) { 2477eaf62fffSJeremy L Thompson Ceed ceed; 24781c66c397SJeremy L Thompson CeedInt Q_f, Q_c; 24791c66c397SJeremy L Thompson CeedBasis basis_fine, basis_c_to_f = NULL; 24801c66c397SJeremy L Thompson 24811c66c397SJeremy L Thompson CeedCall(CeedOperatorCheckReady(op_fine)); 24822b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op_fine, &ceed)); 2483eaf62fffSJeremy L Thompson 2484eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 24852b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveBasis(op_fine, &basis_fine)); 24862b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f)); 24872b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c)); 24886574a04fSJeremy L Thompson CeedCheck(Q_f == Q_c, ceed, CEED_ERROR_DIMENSION, "Bases must have compatible quadrature spaces"); 2489eaf62fffSJeremy L Thompson 2490eaf62fffSJeremy L Thompson // Coarse to fine basis 24917758292fSSebastian Grimberg if (op_prolong || op_restrict) { 24921c66c397SJeremy L Thompson CeedInt dim, num_comp, num_nodes_c, num_nodes_f; 24931c66c397SJeremy L Thompson CeedScalar *q_ref, *q_weight, *grad; 24941c66c397SJeremy L Thompson CeedElemTopology topo; 24951c66c397SJeremy L Thompson 249683d6adf3SZach Atkins // Check if interpolation matrix is provided 24976574a04fSJeremy L Thompson CeedCheck(interp_c_to_f, ceed, CEED_ERROR_INCOMPATIBLE, 24986574a04fSJeremy L Thompson "Prolongation or restriction operator creation requires coarse-to-fine interpolation matrix"); 24992b730f8bSJeremy L Thompson CeedCall(CeedBasisGetTopology(basis_fine, &topo)); 25002b730f8bSJeremy L Thompson CeedCall(CeedBasisGetDimension(basis_fine, &dim)); 25012b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumComponents(basis_fine, &num_comp)); 25022b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumNodes(basis_fine, &num_nodes_f)); 25032b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c)); 25042b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_nodes_f * dim, &q_ref)); 25052b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_nodes_f, &q_weight)); 25062b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_nodes_f * num_nodes_c * dim, &grad)); 25072b730f8bSJeremy 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)); 25082b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_ref)); 25092b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_weight)); 25102b730f8bSJeremy L Thompson CeedCall(CeedFree(&grad)); 251183d6adf3SZach Atkins } 2512eaf62fffSJeremy L Thompson 2513eaf62fffSJeremy L Thompson // Core code 25147758292fSSebastian Grimberg CeedCall(CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, basis_coarse, basis_c_to_f, op_coarse, op_prolong, op_restrict)); 2515eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2516eaf62fffSJeremy L Thompson } 2517eaf62fffSJeremy L Thompson 2518eaf62fffSJeremy L Thompson /** 2519ea61e9acSJeremy L Thompson @brief Build a FDM based approximate inverse for each element for a CeedOperator 2520eaf62fffSJeremy L Thompson 2521ea61e9acSJeremy L Thompson This returns a CeedOperator and CeedVector to apply a Fast Diagonalization Method based approximate inverse. 2522859c15bbSJames 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$. 2523859c15bbSJames Wright The assembled QFunction is used to modify the eigenvalues from simultaneous diagonalization and obtain an approximate inverse of the form \f$V^T 25249fd66db6SSebastian Grimberg \hat S V\f$. 25259fd66db6SSebastian Grimberg The CeedOperator must be linear and non-composite. 25269fd66db6SSebastian Grimberg The associated CeedQFunction must therefore also be linear. 2527eaf62fffSJeremy L Thompson 2528ea61e9acSJeremy L Thompson Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 2529f04ea552SJeremy L Thompson 2530ea61e9acSJeremy L Thompson @param[in] op CeedOperator to create element inverses 2531ea61e9acSJeremy L Thompson @param[out] fdm_inv CeedOperator to apply the action of a FDM based inverse for each element 2532ea61e9acSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 2533eaf62fffSJeremy L Thompson 2534eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2535eaf62fffSJeremy L Thompson 2536480fae85SJeremy L Thompson @ref User 2537eaf62fffSJeremy L Thompson **/ 25382b730f8bSJeremy L Thompson int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdm_inv, CeedRequest *request) { 25391c66c397SJeremy L Thompson Ceed ceed, ceed_parent; 25401c66c397SJeremy L Thompson bool interp = false, grad = false, is_tensor_basis = true; 25411c66c397SJeremy L Thompson CeedInt num_input_fields, P_1d, Q_1d, num_nodes, num_qpts, dim, num_comp = 1, num_elem = 1; 25421c66c397SJeremy L Thompson CeedSize l_size = 1; 25431c66c397SJeremy L Thompson CeedScalar *mass, *laplace, *x, *fdm_interp, *lambda, *elem_avg; 25441c66c397SJeremy L Thompson const CeedScalar *interp_1d, *grad_1d, *q_weight_1d; 25451c66c397SJeremy L Thompson CeedVector q_data; 25461c66c397SJeremy L Thompson CeedElemRestriction rstr = NULL, rstr_qd_i; 25471c66c397SJeremy L Thompson CeedBasis basis = NULL, fdm_basis; 25481c66c397SJeremy L Thompson CeedQFunctionContext ctx_fdm; 25491c66c397SJeremy L Thompson CeedQFunctionField *qf_fields; 25501c66c397SJeremy L Thompson CeedQFunction qf, qf_fdm; 25511c66c397SJeremy L Thompson CeedOperatorField *op_fields; 25521c66c397SJeremy L Thompson 25532b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 2554eaf62fffSJeremy L Thompson 2555eaf62fffSJeremy L Thompson if (op->CreateFDMElementInverse) { 2556d04bbc78SJeremy L Thompson // Backend version 25572b730f8bSJeremy L Thompson CeedCall(op->CreateFDMElementInverse(op, fdm_inv, request)); 2558eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2559eaf62fffSJeremy L Thompson } else { 2560d04bbc78SJeremy L Thompson // Operator fallback 2561d04bbc78SJeremy L Thompson CeedOperator op_fallback; 2562d04bbc78SJeremy L Thompson 25632b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 2564d04bbc78SJeremy L Thompson if (op_fallback) { 25652b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreateFDMElementInverse(op_fallback, fdm_inv, request)); 2566eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2567eaf62fffSJeremy L Thompson } 2568eaf62fffSJeremy L Thompson } 2569eaf62fffSJeremy L Thompson 2570d04bbc78SJeremy L Thompson // Default interface implementation 25712b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 2572bb229da9SJeremy L Thompson CeedCall(CeedOperatorGetFallbackParentCeed(op, &ceed_parent)); 25732b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetQFunction(op, &qf)); 2574eaf62fffSJeremy L Thompson 2575eaf62fffSJeremy L Thompson // Determine active input basis 25762b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_fields, NULL, NULL)); 25772b730f8bSJeremy L Thompson CeedCall(CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL)); 2578eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_input_fields; i++) { 2579eaf62fffSJeremy L Thompson CeedVector vec; 25801c66c397SJeremy L Thompson 25812b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetVector(op_fields[i], &vec)); 2582eaf62fffSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 2583eaf62fffSJeremy L Thompson CeedEvalMode eval_mode; 25841c66c397SJeremy L Thompson 25852b730f8bSJeremy L Thompson CeedCall(CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode)); 2586eaf62fffSJeremy L Thompson interp = interp || eval_mode == CEED_EVAL_INTERP; 2587eaf62fffSJeremy L Thompson grad = grad || eval_mode == CEED_EVAL_GRAD; 25882b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetBasis(op_fields[i], &basis)); 25892b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr)); 2590eaf62fffSJeremy L Thompson } 2591eaf62fffSJeremy L Thompson } 25926574a04fSJeremy L Thompson CeedCheck(basis, ceed, CEED_ERROR_BACKEND, "No active field set"); 25932b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumNodes1D(basis, &P_1d)); 2594352a5e7cSSebastian Grimberg CeedCall(CeedBasisGetNumNodes(basis, &num_nodes)); 25952b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d)); 25962b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis, &num_qpts)); 25972b730f8bSJeremy L Thompson CeedCall(CeedBasisGetDimension(basis, &dim)); 25982b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumComponents(basis, &num_comp)); 25992b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 26002b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size)); 2601eaf62fffSJeremy L Thompson 2602eaf62fffSJeremy L Thompson // Build and diagonalize 1D Mass and Laplacian 26036574a04fSJeremy L Thompson CeedCall(CeedBasisIsTensor(basis, &is_tensor_basis)); 26046574a04fSJeremy L Thompson CeedCheck(is_tensor_basis, ceed, CEED_ERROR_BACKEND, "FDMElementInverse only supported for tensor bases"); 26052b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &mass)); 26062b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &laplace)); 26072b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &x)); 26082b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &fdm_interp)); 26092b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d, &lambda)); 2610eaf62fffSJeremy L Thompson // -- Build matrices 26112b730f8bSJeremy L Thompson CeedCall(CeedBasisGetInterp1D(basis, &interp_1d)); 26122b730f8bSJeremy L Thompson CeedCall(CeedBasisGetGrad1D(basis, &grad_1d)); 26132b730f8bSJeremy L Thompson CeedCall(CeedBasisGetQWeights(basis, &q_weight_1d)); 26142b730f8bSJeremy L Thompson CeedCall(CeedBuildMassLaplace(interp_1d, grad_1d, q_weight_1d, P_1d, Q_1d, dim, mass, laplace)); 2615eaf62fffSJeremy L Thompson 2616eaf62fffSJeremy L Thompson // -- Diagonalize 26172b730f8bSJeremy L Thompson CeedCall(CeedSimultaneousDiagonalization(ceed, laplace, mass, x, lambda, P_1d)); 26182b730f8bSJeremy L Thompson CeedCall(CeedFree(&mass)); 26192b730f8bSJeremy L Thompson CeedCall(CeedFree(&laplace)); 26202b730f8bSJeremy L Thompson for (CeedInt i = 0; i < P_1d; i++) { 26212b730f8bSJeremy L Thompson for (CeedInt j = 0; j < P_1d; j++) fdm_interp[i + j * P_1d] = x[j + i * P_1d]; 26222b730f8bSJeremy L Thompson } 26232b730f8bSJeremy L Thompson CeedCall(CeedFree(&x)); 2624eaf62fffSJeremy L Thompson 26251c66c397SJeremy L Thompson { 26261c66c397SJeremy L Thompson CeedInt layout[3], num_modes = (interp ? 1 : 0) + (grad ? dim : 0); 26271c66c397SJeremy L Thompson CeedScalar max_norm = 0; 26281c66c397SJeremy L Thompson const CeedScalar *assembled_array, *q_weight_array; 26291c66c397SJeremy L Thompson CeedVector assembled = NULL, q_weight; 2630c5f45aeaSJeremy L Thompson CeedElemRestriction rstr_qf = NULL; 26311c66c397SJeremy L Thompson 26321c66c397SJeremy L Thompson // Assemble QFunction 26332b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled, &rstr_qf, request)); 26342b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetELayout(rstr_qf, &layout)); 26352b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&rstr_qf)); 26362b730f8bSJeremy L Thompson CeedCall(CeedVectorNorm(assembled, CEED_NORM_MAX, &max_norm)); 2637eaf62fffSJeremy L Thompson 2638eaf62fffSJeremy L Thompson // Calculate element averages 26392b730f8bSJeremy L Thompson CeedCall(CeedVectorCreate(ceed_parent, num_qpts, &q_weight)); 26402b730f8bSJeremy L Thompson CeedCall(CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, CEED_VECTOR_NONE, q_weight)); 26412b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembled_array)); 26422b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayRead(q_weight, CEED_MEM_HOST, &q_weight_array)); 26432b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_elem, &elem_avg)); 2644eaf62fffSJeremy L Thompson const CeedScalar qf_value_bound = max_norm * 100 * CEED_EPSILON; 26451c66c397SJeremy L Thompson 2646eaf62fffSJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) { 2647eaf62fffSJeremy L Thompson CeedInt count = 0; 26481c66c397SJeremy L Thompson 26492b730f8bSJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 26502b730f8bSJeremy L Thompson for (CeedInt i = 0; i < num_comp * num_comp * num_modes * num_modes; i++) { 26512b730f8bSJeremy L Thompson if (fabs(assembled_array[q * layout[0] + i * layout[1] + e * layout[2]]) > qf_value_bound) { 26522b730f8bSJeremy L Thompson elem_avg[e] += assembled_array[q * layout[0] + i * layout[1] + e * layout[2]] / q_weight_array[q]; 2653eaf62fffSJeremy L Thompson count++; 2654eaf62fffSJeremy L Thompson } 26552b730f8bSJeremy L Thompson } 26562b730f8bSJeremy L Thompson } 2657eaf62fffSJeremy L Thompson if (count) { 2658eaf62fffSJeremy L Thompson elem_avg[e] /= count; 2659eaf62fffSJeremy L Thompson } else { 2660eaf62fffSJeremy L Thompson elem_avg[e] = 1.0; 2661eaf62fffSJeremy L Thompson } 2662eaf62fffSJeremy L Thompson } 26632b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(assembled, &assembled_array)); 26642b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&assembled)); 26652b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(q_weight, &q_weight_array)); 26662b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&q_weight)); 26671c66c397SJeremy L Thompson } 2668eaf62fffSJeremy L Thompson 2669eaf62fffSJeremy L Thompson // Build FDM diagonal 26701c66c397SJeremy L Thompson { 2671eaf62fffSJeremy L Thompson CeedScalar *q_data_array, *fdm_diagonal; 26721c66c397SJeremy L Thompson 2673352a5e7cSSebastian Grimberg CeedCall(CeedCalloc(num_comp * num_nodes, &fdm_diagonal)); 2674352a5e7cSSebastian Grimberg const CeedScalar fdm_diagonal_bound = num_nodes * CEED_EPSILON; 26752b730f8bSJeremy L Thompson for (CeedInt c = 0; c < num_comp; c++) { 2676352a5e7cSSebastian Grimberg for (CeedInt n = 0; n < num_nodes; n++) { 2677352a5e7cSSebastian Grimberg if (interp) fdm_diagonal[c * num_nodes + n] = 1.0; 26782b730f8bSJeremy L Thompson if (grad) { 2679eaf62fffSJeremy L Thompson for (CeedInt d = 0; d < dim; d++) { 2680eaf62fffSJeremy L Thompson CeedInt i = (n / CeedIntPow(P_1d, d)) % P_1d; 2681352a5e7cSSebastian Grimberg fdm_diagonal[c * num_nodes + n] += lambda[i]; 2682eaf62fffSJeremy L Thompson } 2683eaf62fffSJeremy L Thompson } 2684352a5e7cSSebastian Grimberg if (fabs(fdm_diagonal[c * num_nodes + n]) < fdm_diagonal_bound) fdm_diagonal[c * num_nodes + n] = fdm_diagonal_bound; 26852b730f8bSJeremy L Thompson } 26862b730f8bSJeremy L Thompson } 2687352a5e7cSSebastian Grimberg CeedCall(CeedVectorCreate(ceed_parent, num_elem * num_comp * num_nodes, &q_data)); 26882b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(q_data, 0.0)); 26892b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayWrite(q_data, CEED_MEM_HOST, &q_data_array)); 26902b730f8bSJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) { 26912b730f8bSJeremy L Thompson for (CeedInt c = 0; c < num_comp; c++) { 26921c66c397SJeremy L Thompson for (CeedInt n = 0; n < num_nodes; n++) 26931c66c397SJeremy L Thompson q_data_array[(e * num_comp + c) * num_nodes + n] = 1. / (elem_avg[e] * fdm_diagonal[c * num_nodes + n]); 26942b730f8bSJeremy L Thompson } 26952b730f8bSJeremy L Thompson } 26962b730f8bSJeremy L Thompson CeedCall(CeedFree(&elem_avg)); 26972b730f8bSJeremy L Thompson CeedCall(CeedFree(&fdm_diagonal)); 26982b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArray(q_data, &q_data_array)); 26991c66c397SJeremy L Thompson } 2700eaf62fffSJeremy L Thompson 2701eaf62fffSJeremy L Thompson // Setup FDM operator 2702eaf62fffSJeremy L Thompson // -- Basis 27031c66c397SJeremy L Thompson { 2704eaf62fffSJeremy L Thompson CeedScalar *grad_dummy, *q_ref_dummy, *q_weight_dummy; 27051c66c397SJeremy L Thompson 27062b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &grad_dummy)); 27072b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d, &q_ref_dummy)); 27082b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d, &q_weight_dummy)); 27092b730f8bSJeremy 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)); 27102b730f8bSJeremy L Thompson CeedCall(CeedFree(&fdm_interp)); 27112b730f8bSJeremy L Thompson CeedCall(CeedFree(&grad_dummy)); 27122b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_ref_dummy)); 27132b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_weight_dummy)); 27142b730f8bSJeremy L Thompson CeedCall(CeedFree(&lambda)); 27151c66c397SJeremy L Thompson } 2716eaf62fffSJeremy L Thompson 2717eaf62fffSJeremy L Thompson // -- Restriction 27181c66c397SJeremy L Thompson { 2719352a5e7cSSebastian Grimberg CeedInt strides[3] = {1, num_nodes, num_nodes * num_comp}; 2720352a5e7cSSebastian Grimberg CeedCall(CeedElemRestrictionCreateStrided(ceed_parent, num_elem, num_nodes, num_comp, num_elem * num_comp * num_nodes, strides, &rstr_qd_i)); 27211c66c397SJeremy L Thompson } 27221c66c397SJeremy L Thompson 2723eaf62fffSJeremy L Thompson // -- QFunction 27242b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateInteriorByName(ceed_parent, "Scale", &qf_fdm)); 27252b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_fdm, "input", num_comp, CEED_EVAL_INTERP)); 27262b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_fdm, "scale", num_comp, CEED_EVAL_NONE)); 27272b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddOutput(qf_fdm, "output", num_comp, CEED_EVAL_INTERP)); 27282b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetUserFlopsEstimate(qf_fdm, num_comp)); 27291c66c397SJeremy L Thompson 2730eaf62fffSJeremy L Thompson // -- QFunction context 27311c66c397SJeremy L Thompson { 2732eaf62fffSJeremy L Thompson CeedInt *num_comp_data; 27331c66c397SJeremy L Thompson 27342b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, &num_comp_data)); 2735eaf62fffSJeremy L Thompson num_comp_data[0] = num_comp; 27362b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextCreate(ceed, &ctx_fdm)); 27372b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextSetData(ctx_fdm, CEED_MEM_HOST, CEED_OWN_POINTER, sizeof(*num_comp_data), num_comp_data)); 27381c66c397SJeremy L Thompson } 27392b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetContext(qf_fdm, ctx_fdm)); 27402b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextDestroy(&ctx_fdm)); 27411c66c397SJeremy L Thompson 2742eaf62fffSJeremy L Thompson // -- Operator 27432b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(ceed_parent, qf_fdm, NULL, NULL, fdm_inv)); 27442b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*fdm_inv, "input", rstr, fdm_basis, CEED_VECTOR_ACTIVE)); 2745356036faSJeremy L Thompson CeedCall(CeedOperatorSetField(*fdm_inv, "scale", rstr_qd_i, CEED_BASIS_NONE, q_data)); 27462b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*fdm_inv, "output", rstr, fdm_basis, CEED_VECTOR_ACTIVE)); 2747eaf62fffSJeremy L Thompson 2748eaf62fffSJeremy L Thompson // Cleanup 27492b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&q_data)); 27502b730f8bSJeremy L Thompson CeedCall(CeedBasisDestroy(&fdm_basis)); 27512b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&rstr_qd_i)); 27522b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&qf_fdm)); 2753eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2754eaf62fffSJeremy L Thompson } 2755eaf62fffSJeremy L Thompson 2756eaf62fffSJeremy L Thompson /// @} 2757