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 8ed9e99e6SJeremy L Thompson #include <assert.h> 9*2b730f8bSJeremy L Thompson #include <ceed-impl.h> 10*2b730f8bSJeremy L Thompson #include <ceed/backend.h> 11*2b730f8bSJeremy L Thompson #include <ceed/ceed.h> 12*2b730f8bSJeremy 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 /** 279e77b9c8SJeremy L Thompson @brief Duplicate a CeedQFunction with a reference Ceed to fallback for advanced 289e77b9c8SJeremy L Thompson CeedOperator functionality 299e77b9c8SJeremy L Thompson 3001ea9c81SJed Brown @param[in] fallback_ceed Ceed on which to create fallback CeedQFunction 319e77b9c8SJeremy L Thompson @param[in] qf CeedQFunction to create fallback for 3201ea9c81SJed Brown @param[out] qf_fallback fallback CeedQFunction 339e77b9c8SJeremy L Thompson 349e77b9c8SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 359e77b9c8SJeremy L Thompson 369e77b9c8SJeremy L Thompson @ref Developer 379e77b9c8SJeremy L Thompson **/ 38*2b730f8bSJeremy L Thompson static int CeedQFunctionCreateFallback(Ceed fallback_ceed, CeedQFunction qf, CeedQFunction *qf_fallback) { 399e77b9c8SJeremy L Thompson // Check if NULL qf passed in 409e77b9c8SJeremy L Thompson if (!qf) return CEED_ERROR_SUCCESS; 419e77b9c8SJeremy L Thompson 42d04bbc78SJeremy L Thompson CeedDebug256(qf->ceed, 1, "---------- CeedOperator Fallback ----------\n"); 4313f886e9SJeremy L Thompson CeedDebug(qf->ceed, "Creating fallback CeedQFunction\n"); 44d04bbc78SJeremy L Thompson 459e77b9c8SJeremy L Thompson char *source_path_with_name = ""; 469e77b9c8SJeremy L Thompson if (qf->source_path) { 47*2b730f8bSJeremy L Thompson size_t path_len = strlen(qf->source_path), name_len = strlen(qf->kernel_name); 48*2b730f8bSJeremy 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 { 53*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, &source_path_with_name)); 549e77b9c8SJeremy L Thompson } 559e77b9c8SJeremy L Thompson 56*2b730f8bSJeremy 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 60*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionGetContext(qf, &ctx)); 61*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetContext(*qf_fallback, ctx)); 629e77b9c8SJeremy L Thompson } 639e77b9c8SJeremy L Thompson for (CeedInt i = 0; i < qf->num_input_fields; i++) { 64*2b730f8bSJeremy 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++) { 67*2b730f8bSJeremy 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 } 69*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&source_path_with_name)); 709e77b9c8SJeremy L Thompson 719e77b9c8SJeremy L Thompson return CEED_ERROR_SUCCESS; 729e77b9c8SJeremy L Thompson } 739e77b9c8SJeremy L Thompson 749e77b9c8SJeremy L Thompson /** 75eaf62fffSJeremy L Thompson @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced 76eaf62fffSJeremy L Thompson CeedOperator functionality 77eaf62fffSJeremy L Thompson 78eaf62fffSJeremy L Thompson @param op CeedOperator to create fallback for 79eaf62fffSJeremy L Thompson 80eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 81eaf62fffSJeremy L Thompson 82eaf62fffSJeremy L Thompson @ref Developer 83eaf62fffSJeremy L Thompson **/ 84d04bbc78SJeremy L Thompson static int CeedOperatorCreateFallback(CeedOperator op) { 859e77b9c8SJeremy L Thompson Ceed ceed_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 91*2b730f8bSJeremy 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 98805fe78eSJeremy L Thompson CeedOperator op_fallback; 99805fe78eSJeremy L Thompson if (op->is_composite) { 100*2b730f8bSJeremy L Thompson CeedCall(CeedCompositeOperatorCreate(ceed_fallback, &op_fallback)); 101805fe78eSJeremy L Thompson for (CeedInt i = 0; i < op->num_suboperators; i++) { 102d04bbc78SJeremy L Thompson CeedOperator op_sub_fallback; 103d04bbc78SJeremy L Thompson 104*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op->sub_operators[i], &op_sub_fallback)); 105*2b730f8bSJeremy L Thompson CeedCall(CeedCompositeOperatorAddSub(op_fallback, op_sub_fallback)); 106805fe78eSJeremy L Thompson } 107805fe78eSJeremy L Thompson } else { 1089e77b9c8SJeremy L Thompson CeedQFunction qf_fallback = NULL, dqf_fallback = NULL, dqfT_fallback = NULL; 109*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateFallback(ceed_fallback, op->qf, &qf_fallback)); 110*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateFallback(ceed_fallback, op->dqf, &dqf_fallback)); 111*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateFallback(ceed_fallback, op->dqfT, &dqfT_fallback)); 112*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(ceed_fallback, qf_fallback, dqf_fallback, dqfT_fallback, &op_fallback)); 113805fe78eSJeremy L Thompson for (CeedInt i = 0; i < op->qf->num_input_fields; i++) { 114*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(op_fallback, op->input_fields[i]->field_name, op->input_fields[i]->elem_restr, op->input_fields[i]->basis, 115*2b730f8bSJeremy L Thompson op->input_fields[i]->vec)); 116805fe78eSJeremy L Thompson } 117805fe78eSJeremy L Thompson for (CeedInt i = 0; i < op->qf->num_output_fields; i++) { 118*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(op_fallback, op->output_fields[i]->field_name, op->output_fields[i]->elem_restr, op->output_fields[i]->basis, 119*2b730f8bSJeremy L Thompson op->output_fields[i]->vec)); 120805fe78eSJeremy L Thompson } 121*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataReferenceCopy(op->qf_assembled, &op_fallback->qf_assembled)); 122805fe78eSJeremy L Thompson if (op_fallback->num_qpts == 0) { 123*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetNumQuadraturePoints(op_fallback, op->num_qpts)); 124805fe78eSJeremy L Thompson } 1259e77b9c8SJeremy L Thompson // Cleanup 126*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&qf_fallback)); 127*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&dqf_fallback)); 128*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&dqfT_fallback)); 129805fe78eSJeremy L Thompson } 130*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetName(op_fallback, op->name)); 131*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op_fallback)); 132805fe78eSJeremy L Thompson op->op_fallback = op_fallback; 133eaf62fffSJeremy L Thompson 134eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 135eaf62fffSJeremy L Thompson } 136eaf62fffSJeremy L Thompson 137eaf62fffSJeremy L Thompson /** 138d04bbc78SJeremy L Thompson @brief Retreive fallback CeedOperator with a reference Ceed for advanced CeedOperator functionality 139d04bbc78SJeremy L Thompson 140d04bbc78SJeremy L Thompson @param[in] op CeedOperator to retrieve fallback for 141d04bbc78SJeremy L Thompson @param[out] op_fallback Fallback CeedOperator 142d04bbc78SJeremy L Thompson 143d04bbc78SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 144d04bbc78SJeremy L Thompson 145d04bbc78SJeremy L Thompson @ref Developer 146d04bbc78SJeremy L Thompson **/ 147d04bbc78SJeremy L Thompson int CeedOperatorGetFallback(CeedOperator op, CeedOperator *op_fallback) { 148d04bbc78SJeremy L Thompson // Create if needed 149d04bbc78SJeremy L Thompson if (!op->op_fallback) { 150*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreateFallback(op)); 151d04bbc78SJeremy L Thompson } 152d04bbc78SJeremy L Thompson if (op->op_fallback) { 153d04bbc78SJeremy L Thompson bool is_debug; 154d04bbc78SJeremy L Thompson 155*2b730f8bSJeremy L Thompson CeedCall(CeedIsDebug(op->ceed, &is_debug)); 156d04bbc78SJeremy L Thompson if (is_debug) { 157d04bbc78SJeremy L Thompson Ceed ceed_fallback; 158d04bbc78SJeremy L Thompson const char *resource, *resource_fallback; 159d04bbc78SJeremy L Thompson 160*2b730f8bSJeremy L Thompson CeedCall(CeedGetOperatorFallbackCeed(op->ceed, &ceed_fallback)); 161*2b730f8bSJeremy L Thompson CeedCall(CeedGetResource(op->ceed, &resource)); 162*2b730f8bSJeremy L Thompson CeedCall(CeedGetResource(ceed_fallback, &resource_fallback)); 163d04bbc78SJeremy L Thompson 164d04bbc78SJeremy L Thompson CeedDebug256(op->ceed, 1, "---------- CeedOperator Fallback ----------\n"); 165*2b730f8bSJeremy L Thompson CeedDebug(op->ceed, "Falling back from %s operator at address %ld to %s operator at address %ld\n", resource, op, resource_fallback, 166*2b730f8bSJeremy L Thompson op->op_fallback); 167d04bbc78SJeremy L Thompson } 168d04bbc78SJeremy L Thompson } 169d04bbc78SJeremy L Thompson *op_fallback = op->op_fallback; 170d04bbc78SJeremy L Thompson 171d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 172d04bbc78SJeremy L Thompson } 173d04bbc78SJeremy L Thompson 174d04bbc78SJeremy L Thompson /** 175eaf62fffSJeremy L Thompson @brief Select correct basis matrix pointer based on CeedEvalMode 176eaf62fffSJeremy L Thompson 177eaf62fffSJeremy L Thompson @param[in] eval_mode Current basis evaluation mode 178eaf62fffSJeremy L Thompson @param[in] identity Pointer to identity matrix 179eaf62fffSJeremy L Thompson @param[in] interp Pointer to interpolation matrix 180eaf62fffSJeremy L Thompson @param[in] grad Pointer to gradient matrix 181eaf62fffSJeremy L Thompson @param[out] basis_ptr Basis pointer to set 182eaf62fffSJeremy L Thompson 183eaf62fffSJeremy L Thompson @ref Developer 184eaf62fffSJeremy L Thompson **/ 185*2b730f8bSJeremy L Thompson static inline void CeedOperatorGetBasisPointer(CeedEvalMode eval_mode, const CeedScalar *identity, const CeedScalar *interp, const CeedScalar *grad, 186*2b730f8bSJeremy L Thompson const CeedScalar **basis_ptr) { 187eaf62fffSJeremy L Thompson switch (eval_mode) { 188eaf62fffSJeremy L Thompson case CEED_EVAL_NONE: 189eaf62fffSJeremy L Thompson *basis_ptr = identity; 190eaf62fffSJeremy L Thompson break; 191eaf62fffSJeremy L Thompson case CEED_EVAL_INTERP: 192eaf62fffSJeremy L Thompson *basis_ptr = interp; 193eaf62fffSJeremy L Thompson break; 194eaf62fffSJeremy L Thompson case CEED_EVAL_GRAD: 195eaf62fffSJeremy L Thompson *basis_ptr = grad; 196eaf62fffSJeremy L Thompson break; 197eaf62fffSJeremy L Thompson case CEED_EVAL_WEIGHT: 198eaf62fffSJeremy L Thompson case CEED_EVAL_DIV: 199eaf62fffSJeremy L Thompson case CEED_EVAL_CURL: 200eaf62fffSJeremy L Thompson break; // Caught by QF Assembly 201eaf62fffSJeremy L Thompson } 202ed9e99e6SJeremy L Thompson assert(*basis_ptr != NULL); 203eaf62fffSJeremy L Thompson } 204eaf62fffSJeremy L Thompson 205eaf62fffSJeremy L Thompson /** 206eaf62fffSJeremy L Thompson @brief Create point block restriction for active operator field 207eaf62fffSJeremy L Thompson 208eaf62fffSJeremy L Thompson @param[in] rstr Original CeedElemRestriction for active field 209eaf62fffSJeremy L Thompson @param[out] pointblock_rstr Address of the variable where the newly created 210eaf62fffSJeremy L Thompson CeedElemRestriction will be stored 211eaf62fffSJeremy L Thompson 212eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 213eaf62fffSJeremy L Thompson 214eaf62fffSJeremy L Thompson @ref Developer 215eaf62fffSJeremy L Thompson **/ 216*2b730f8bSJeremy L Thompson static int CeedOperatorCreateActivePointBlockRestriction(CeedElemRestriction rstr, CeedElemRestriction *pointblock_rstr) { 217eaf62fffSJeremy L Thompson Ceed ceed; 218*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 219eaf62fffSJeremy L Thompson const CeedInt *offsets; 220*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets)); 221eaf62fffSJeremy L Thompson 222eaf62fffSJeremy L Thompson // Expand offsets 2237b63f5c6SJed Brown CeedInt num_elem, num_comp, elem_size, comp_stride, *pointblock_offsets; 2247b63f5c6SJed Brown CeedSize l_size; 225*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 226*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 227*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 228*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetCompStride(rstr, &comp_stride)); 229*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size)); 230eaf62fffSJeremy L Thompson CeedInt shift = num_comp; 231*2b730f8bSJeremy L Thompson if (comp_stride != 1) shift *= num_comp; 232*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_elem * elem_size, &pointblock_offsets)); 233eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_elem * elem_size; i++) { 234eaf62fffSJeremy L Thompson pointblock_offsets[i] = offsets[i] * shift; 235eaf62fffSJeremy L Thompson } 236eaf62fffSJeremy L Thompson 237eaf62fffSJeremy L Thompson // Create new restriction 238*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionCreate(ceed, num_elem, elem_size, num_comp * num_comp, 1, l_size * num_comp, CEED_MEM_HOST, CEED_OWN_POINTER, 239*2b730f8bSJeremy L Thompson pointblock_offsets, pointblock_rstr)); 240eaf62fffSJeremy L Thompson 241eaf62fffSJeremy L Thompson // Cleanup 242*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionRestoreOffsets(rstr, &offsets)); 243eaf62fffSJeremy L Thompson 244eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 245eaf62fffSJeremy L Thompson } 246eaf62fffSJeremy L Thompson 247eaf62fffSJeremy L Thompson /** 248eaf62fffSJeremy L Thompson @brief Core logic for assembling operator diagonal or point block diagonal 249eaf62fffSJeremy L Thompson 250eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble point block diagonal 251eaf62fffSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else 252eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 253eaf62fffSJeremy L Thompson @param[in] is_pointblock Boolean flag to assemble diagonal or point block diagonal 254eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled diagonal 255eaf62fffSJeremy L Thompson 256eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 257eaf62fffSJeremy L Thompson 258eaf62fffSJeremy L Thompson @ref Developer 259eaf62fffSJeremy L Thompson **/ 260*2b730f8bSJeremy L Thompson static inline int CeedSingleOperatorAssembleAddDiagonal_Core(CeedOperator op, CeedRequest *request, const bool is_pointblock, CeedVector assembled) { 261eaf62fffSJeremy L Thompson Ceed ceed; 262*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 263eaf62fffSJeremy L Thompson 264eaf62fffSJeremy L Thompson // Assemble QFunction 265eaf62fffSJeremy L Thompson CeedQFunction qf; 266*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetQFunction(op, &qf)); 267eaf62fffSJeremy L Thompson CeedInt num_input_fields, num_output_fields; 268*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionGetNumArgs(qf, &num_input_fields, &num_output_fields)); 269eaf62fffSJeremy L Thompson CeedVector assembled_qf; 270eaf62fffSJeremy L Thompson CeedElemRestriction rstr; 271*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled_qf, &rstr, request)); 272eaf62fffSJeremy L Thompson CeedInt layout[3]; 273*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetELayout(rstr, &layout)); 274*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&rstr)); 275eaf62fffSJeremy L Thompson 276ed9e99e6SJeremy L Thompson // Get assembly data 277ed9e99e6SJeremy L Thompson CeedOperatorAssemblyData data; 278*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetOperatorAssemblyData(op, &data)); 279ed9e99e6SJeremy L Thompson const CeedEvalMode *eval_mode_in, *eval_mode_out; 280ed9e99e6SJeremy L Thompson CeedInt num_eval_mode_in, num_eval_mode_out; 281*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorAssemblyDataGetEvalModes(data, &num_eval_mode_in, &eval_mode_in, &num_eval_mode_out, &eval_mode_out)); 282ed9e99e6SJeremy L Thompson CeedBasis basis_in, basis_out; 283*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorAssemblyDataGetBases(data, &basis_in, NULL, &basis_out, NULL)); 284ed9e99e6SJeremy L Thompson CeedInt num_comp; 285*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumComponents(basis_in, &num_comp)); 286eaf62fffSJeremy L Thompson 287eaf62fffSJeremy L Thompson // Assemble point block diagonal restriction, if needed 288ed9e99e6SJeremy L Thompson CeedElemRestriction diag_rstr; 289*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveElemRestriction(op, &diag_rstr)); 290eaf62fffSJeremy L Thompson if (is_pointblock) { 291ed9e99e6SJeremy L Thompson CeedElemRestriction point_block_rstr; 292*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreateActivePointBlockRestriction(diag_rstr, &point_block_rstr)); 293ed9e99e6SJeremy L Thompson diag_rstr = point_block_rstr; 294eaf62fffSJeremy L Thompson } 295eaf62fffSJeremy L Thompson 296eaf62fffSJeremy L Thompson // Create diagonal vector 297eaf62fffSJeremy L Thompson CeedVector elem_diag; 298*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionCreateVector(diag_rstr, NULL, &elem_diag)); 299eaf62fffSJeremy L Thompson 300eaf62fffSJeremy L Thompson // Assemble element operator diagonals 3019c774eddSJeremy L Thompson CeedScalar *elem_diag_array; 3029c774eddSJeremy L Thompson const CeedScalar *assembled_qf_array; 303*2b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(elem_diag, 0.0)); 304*2b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArray(elem_diag, CEED_MEM_HOST, &elem_diag_array)); 305*2b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array)); 306eaf62fffSJeremy L Thompson CeedInt num_elem, num_nodes, num_qpts; 307*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(diag_rstr, &num_elem)); 308*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumNodes(basis_in, &num_nodes)); 309*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts)); 310ed9e99e6SJeremy L Thompson 311eaf62fffSJeremy L Thompson // Basis matrices 312eaf62fffSJeremy L Thompson const CeedScalar *interp_in, *interp_out, *grad_in, *grad_out; 313eaf62fffSJeremy L Thompson CeedScalar *identity = NULL; 314ed9e99e6SJeremy L Thompson bool has_eval_none = false; 315ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < num_eval_mode_in; i++) { 316ed9e99e6SJeremy L Thompson has_eval_none = has_eval_none || (eval_mode_in[i] == CEED_EVAL_NONE); 317ed9e99e6SJeremy L Thompson } 318ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < num_eval_mode_out; i++) { 319ed9e99e6SJeremy L Thompson has_eval_none = has_eval_none || (eval_mode_out[i] == CEED_EVAL_NONE); 320ed9e99e6SJeremy L Thompson } 321ed9e99e6SJeremy L Thompson if (has_eval_none) { 322*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_qpts * num_nodes, &identity)); 323*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < (num_nodes < num_qpts ? num_nodes : num_qpts); i++) identity[i * num_nodes + i] = 1.0; 324eaf62fffSJeremy L Thompson } 325*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetInterp(basis_in, &interp_in)); 326*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetInterp(basis_out, &interp_out)); 327*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetGrad(basis_in, &grad_in)); 328*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetGrad(basis_out, &grad_out)); 329eaf62fffSJeremy L Thompson // Compute the diagonal of B^T D B 330eaf62fffSJeremy L Thompson // Each element 331eaf62fffSJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) { 332eaf62fffSJeremy L Thompson CeedInt d_out = -1; 333eaf62fffSJeremy L Thompson // Each basis eval mode pair 334eaf62fffSJeremy L Thompson for (CeedInt e_out = 0; e_out < num_eval_mode_out; e_out++) { 335eaf62fffSJeremy L Thompson const CeedScalar *bt = NULL; 336*2b730f8bSJeremy L Thompson if (eval_mode_out[e_out] == CEED_EVAL_GRAD) d_out += 1; 337*2b730f8bSJeremy L Thompson CeedOperatorGetBasisPointer(eval_mode_out[e_out], identity, interp_out, &grad_out[d_out * num_qpts * num_nodes], &bt); 338eaf62fffSJeremy L Thompson CeedInt d_in = -1; 339eaf62fffSJeremy L Thompson for (CeedInt e_in = 0; e_in < num_eval_mode_in; e_in++) { 340eaf62fffSJeremy L Thompson const CeedScalar *b = NULL; 341*2b730f8bSJeremy L Thompson if (eval_mode_in[e_in] == CEED_EVAL_GRAD) d_in += 1; 342*2b730f8bSJeremy L Thompson CeedOperatorGetBasisPointer(eval_mode_in[e_in], identity, interp_in, &grad_in[d_in * num_qpts * num_nodes], &b); 343eaf62fffSJeremy L Thompson // Each component 344*2b730f8bSJeremy L Thompson for (CeedInt c_out = 0; c_out < num_comp; c_out++) { 345eaf62fffSJeremy L Thompson // Each qpoint/node pair 346*2b730f8bSJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 347eaf62fffSJeremy L Thompson if (is_pointblock) { 348eaf62fffSJeremy L Thompson // Point Block Diagonal 349eaf62fffSJeremy L Thompson for (CeedInt c_in = 0; c_in < num_comp; c_in++) { 350eaf62fffSJeremy L Thompson const CeedScalar qf_value = 351*2b730f8bSJeremy L Thompson assembled_qf_array[q * layout[0] + (((e_in * num_comp + c_in) * num_eval_mode_out + e_out) * num_comp + c_out) * layout[1] + 352*2b730f8bSJeremy L Thompson e * layout[2]]; 353*2b730f8bSJeremy L Thompson for (CeedInt n = 0; n < num_nodes; n++) { 354eaf62fffSJeremy L Thompson elem_diag_array[((e * num_comp + c_out) * num_comp + c_in) * num_nodes + n] += 355eaf62fffSJeremy L Thompson bt[q * num_nodes + n] * qf_value * b[q * num_nodes + n]; 356eaf62fffSJeremy L Thompson } 357*2b730f8bSJeremy L Thompson } 358eaf62fffSJeremy L Thompson } else { 359eaf62fffSJeremy L Thompson // Diagonal Only 360eaf62fffSJeremy L Thompson const CeedScalar qf_value = 361*2b730f8bSJeremy L Thompson assembled_qf_array[q * layout[0] + (((e_in * num_comp + c_out) * num_eval_mode_out + e_out) * num_comp + c_out) * layout[1] + 362*2b730f8bSJeremy L Thompson e * layout[2]]; 363*2b730f8bSJeremy L Thompson for (CeedInt n = 0; n < num_nodes; n++) { 364*2b730f8bSJeremy L Thompson elem_diag_array[(e * num_comp + c_out) * num_nodes + n] += bt[q * num_nodes + n] * qf_value * b[q * num_nodes + n]; 365eaf62fffSJeremy L Thompson } 366eaf62fffSJeremy L Thompson } 367eaf62fffSJeremy L Thompson } 368eaf62fffSJeremy L Thompson } 369*2b730f8bSJeremy L Thompson } 370*2b730f8bSJeremy L Thompson } 371*2b730f8bSJeremy L Thompson } 372*2b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArray(elem_diag, &elem_diag_array)); 373*2b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array)); 374eaf62fffSJeremy L Thompson 375eaf62fffSJeremy L Thompson // Assemble local operator diagonal 376*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionApply(diag_rstr, CEED_TRANSPOSE, elem_diag, assembled, request)); 377eaf62fffSJeremy L Thompson 378eaf62fffSJeremy L Thompson // Cleanup 379eaf62fffSJeremy L Thompson if (is_pointblock) { 380*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&diag_rstr)); 381eaf62fffSJeremy L Thompson } 382*2b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&assembled_qf)); 383*2b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&elem_diag)); 384*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&identity)); 385eaf62fffSJeremy L Thompson 386eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 387eaf62fffSJeremy L Thompson } 388eaf62fffSJeremy L Thompson 389eaf62fffSJeremy L Thompson /** 390eaf62fffSJeremy L Thompson @brief Core logic for assembling composite operator diagonal 391eaf62fffSJeremy L Thompson 392eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble point block diagonal 393eaf62fffSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else 394eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 395eaf62fffSJeremy L Thompson @param[in] is_pointblock Boolean flag to assemble diagonal or point block diagonal 396eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled diagonal 397eaf62fffSJeremy L Thompson 398eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 399eaf62fffSJeremy L Thompson 400eaf62fffSJeremy L Thompson @ref Developer 401eaf62fffSJeremy L Thompson **/ 402*2b730f8bSJeremy L Thompson static inline int CeedCompositeOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedRequest *request, const bool is_pointblock, 403eaf62fffSJeremy L Thompson CeedVector assembled) { 404eaf62fffSJeremy L Thompson CeedInt num_sub; 405eaf62fffSJeremy L Thompson CeedOperator *suboperators; 406*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetNumSub(op, &num_sub)); 407*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetSubList(op, &suboperators)); 408eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_sub; i++) { 4096aa95790SJeremy L Thompson if (is_pointblock) { 410*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddPointBlockDiagonal(suboperators[i], assembled, request)); 4116aa95790SJeremy L Thompson } else { 412*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddDiagonal(suboperators[i], assembled, request)); 4136aa95790SJeremy L Thompson } 414eaf62fffSJeremy L Thompson } 415eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 416eaf62fffSJeremy L Thompson } 417eaf62fffSJeremy L Thompson 418eaf62fffSJeremy L Thompson /** 419eaf62fffSJeremy L Thompson @brief Build nonzero pattern for non-composite operator 420eaf62fffSJeremy L Thompson 421eaf62fffSJeremy L Thompson Users should generally use CeedOperatorLinearAssembleSymbolic() 422eaf62fffSJeremy L Thompson 423eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble nonzero pattern 424eaf62fffSJeremy L Thompson @param[in] offset Offset for number of entries 425eaf62fffSJeremy L Thompson @param[out] rows Row number for each entry 426eaf62fffSJeremy L Thompson @param[out] cols Column number for each entry 427eaf62fffSJeremy L Thompson 428eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 429eaf62fffSJeremy L Thompson 430eaf62fffSJeremy L Thompson @ref Developer 431eaf62fffSJeremy L Thompson **/ 432*2b730f8bSJeremy L Thompson static int CeedSingleOperatorAssembleSymbolic(CeedOperator op, CeedInt offset, CeedInt *rows, CeedInt *cols) { 433eaf62fffSJeremy L Thompson Ceed ceed = op->ceed; 434*2b730f8bSJeremy L Thompson if (op->is_composite) { 435eaf62fffSJeremy L Thompson // LCOV_EXCL_START 436*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Composite operator not supported"); 437eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 438*2b730f8bSJeremy L Thompson } 439eaf62fffSJeremy L Thompson 440c9366a6bSJeremy L Thompson CeedSize num_nodes; 441*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &num_nodes, NULL)); 442eaf62fffSJeremy L Thompson CeedElemRestriction rstr_in; 443*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveElemRestriction(op, &rstr_in)); 444e79b91d9SJeremy L Thompson CeedInt num_elem, elem_size, num_comp; 445*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(rstr_in, &num_elem)); 446*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetElementSize(rstr_in, &elem_size)); 447*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumComponents(rstr_in, &num_comp)); 448eaf62fffSJeremy L Thompson CeedInt layout_er[3]; 449*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetELayout(rstr_in, &layout_er)); 450eaf62fffSJeremy L Thompson 451eaf62fffSJeremy L Thompson CeedInt local_num_entries = elem_size * num_comp * elem_size * num_comp * num_elem; 452eaf62fffSJeremy L Thompson 453eaf62fffSJeremy L Thompson // Determine elem_dof relation 454eaf62fffSJeremy L Thompson CeedVector index_vec; 455*2b730f8bSJeremy L Thompson CeedCall(CeedVectorCreate(ceed, num_nodes, &index_vec)); 456eaf62fffSJeremy L Thompson CeedScalar *array; 457*2b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayWrite(index_vec, CEED_MEM_HOST, &array)); 458ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < num_nodes; i++) array[i] = i; 459*2b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArray(index_vec, &array)); 460eaf62fffSJeremy L Thompson CeedVector elem_dof; 461*2b730f8bSJeremy L Thompson CeedCall(CeedVectorCreate(ceed, num_elem * elem_size * num_comp, &elem_dof)); 462*2b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(elem_dof, 0.0)); 463*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionApply(rstr_in, CEED_NOTRANSPOSE, index_vec, elem_dof, CEED_REQUEST_IMMEDIATE)); 464eaf62fffSJeremy L Thompson const CeedScalar *elem_dof_a; 465*2b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayRead(elem_dof, CEED_MEM_HOST, &elem_dof_a)); 466*2b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&index_vec)); 467eaf62fffSJeremy L Thompson 468eaf62fffSJeremy L Thompson // Determine i, j locations for element matrices 469eaf62fffSJeremy L Thompson CeedInt count = 0; 470ed9e99e6SJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) { 471ed9e99e6SJeremy L Thompson for (CeedInt comp_in = 0; comp_in < num_comp; comp_in++) { 472ed9e99e6SJeremy L Thompson for (CeedInt comp_out = 0; comp_out < num_comp; comp_out++) { 473ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < elem_size; i++) { 474ed9e99e6SJeremy L Thompson for (CeedInt j = 0; j < elem_size; j++) { 475*2b730f8bSJeremy L Thompson const CeedInt elem_dof_index_row = i * layout_er[0] + (comp_out)*layout_er[1] + e * layout_er[2]; 476*2b730f8bSJeremy L Thompson const CeedInt elem_dof_index_col = j * layout_er[0] + comp_in * layout_er[1] + e * layout_er[2]; 477eaf62fffSJeremy L Thompson 478eaf62fffSJeremy L Thompson const CeedInt row = elem_dof_a[elem_dof_index_row]; 479eaf62fffSJeremy L Thompson const CeedInt col = elem_dof_a[elem_dof_index_col]; 480eaf62fffSJeremy L Thompson 481eaf62fffSJeremy L Thompson rows[offset + count] = row; 482eaf62fffSJeremy L Thompson cols[offset + count] = col; 483eaf62fffSJeremy L Thompson count++; 484eaf62fffSJeremy L Thompson } 485eaf62fffSJeremy L Thompson } 486eaf62fffSJeremy L Thompson } 487eaf62fffSJeremy L Thompson } 488eaf62fffSJeremy L Thompson } 489*2b730f8bSJeremy L Thompson if (count != local_num_entries) { 490eaf62fffSJeremy L Thompson // LCOV_EXCL_START 491eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing assembled entries"); 492eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 493*2b730f8bSJeremy L Thompson } 494*2b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(elem_dof, &elem_dof_a)); 495*2b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&elem_dof)); 496eaf62fffSJeremy L Thompson 497eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 498eaf62fffSJeremy L Thompson } 499eaf62fffSJeremy L Thompson 500eaf62fffSJeremy L Thompson /** 501eaf62fffSJeremy L Thompson @brief Assemble nonzero entries for non-composite operator 502eaf62fffSJeremy L Thompson 503eaf62fffSJeremy L Thompson Users should generally use CeedOperatorLinearAssemble() 504eaf62fffSJeremy L Thompson 505eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 50652b3e6a7SJed Brown @param[in] offset Offest for number of entries 507eaf62fffSJeremy L Thompson @param[out] values Values to assemble into matrix 508eaf62fffSJeremy L Thompson 509eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 510eaf62fffSJeremy L Thompson 511eaf62fffSJeremy L Thompson @ref Developer 512eaf62fffSJeremy L Thompson **/ 513*2b730f8bSJeremy L Thompson static int CeedSingleOperatorAssemble(CeedOperator op, CeedInt offset, CeedVector values) { 514eaf62fffSJeremy L Thompson Ceed ceed = op->ceed; 515*2b730f8bSJeremy L Thompson if (op->is_composite) { 516eaf62fffSJeremy L Thompson // LCOV_EXCL_START 517*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Composite operator not supported"); 518eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 519*2b730f8bSJeremy L Thompson } 52052b3e6a7SJed Brown if (op->num_elem == 0) return CEED_ERROR_SUCCESS; 521eaf62fffSJeremy L Thompson 522cefa2673SJeremy L Thompson if (op->LinearAssembleSingle) { 523cefa2673SJeremy L Thompson // Backend version 524*2b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleSingle(op, offset, values)); 525cefa2673SJeremy L Thompson return CEED_ERROR_SUCCESS; 526cefa2673SJeremy L Thompson } else { 527cefa2673SJeremy L Thompson // Operator fallback 528cefa2673SJeremy L Thompson CeedOperator op_fallback; 529cefa2673SJeremy L Thompson 530*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 531cefa2673SJeremy L Thompson if (op_fallback) { 532*2b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemble(op_fallback, offset, values)); 533cefa2673SJeremy L Thompson return CEED_ERROR_SUCCESS; 534cefa2673SJeremy L Thompson } 535cefa2673SJeremy L Thompson } 536cefa2673SJeremy L Thompson 537eaf62fffSJeremy L Thompson // Assemble QFunction 538eaf62fffSJeremy L Thompson CeedQFunction qf; 539*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetQFunction(op, &qf)); 540eaf62fffSJeremy L Thompson CeedVector assembled_qf; 541eaf62fffSJeremy L Thompson CeedElemRestriction rstr_q; 542*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled_qf, &rstr_q, CEED_REQUEST_IMMEDIATE)); 5431f9221feSJeremy L Thompson CeedSize qf_length; 544*2b730f8bSJeremy L Thompson CeedCall(CeedVectorGetLength(assembled_qf, &qf_length)); 545eaf62fffSJeremy L Thompson 5467e7773b5SJeremy L Thompson CeedInt num_input_fields, num_output_fields; 547eaf62fffSJeremy L Thompson CeedOperatorField *input_fields; 548eaf62fffSJeremy L Thompson CeedOperatorField *output_fields; 549*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields)); 550eaf62fffSJeremy L Thompson 551ed9e99e6SJeremy L Thompson // Get assembly data 552ed9e99e6SJeremy L Thompson CeedOperatorAssemblyData data; 553*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetOperatorAssemblyData(op, &data)); 554ed9e99e6SJeremy L Thompson const CeedEvalMode *eval_mode_in, *eval_mode_out; 555ed9e99e6SJeremy L Thompson CeedInt num_eval_mode_in, num_eval_mode_out; 556*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorAssemblyDataGetEvalModes(data, &num_eval_mode_in, &eval_mode_in, &num_eval_mode_out, &eval_mode_out)); 557ed9e99e6SJeremy L Thompson CeedBasis basis_in, basis_out; 558*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorAssemblyDataGetBases(data, &basis_in, NULL, &basis_out, NULL)); 559eaf62fffSJeremy L Thompson 560*2b730f8bSJeremy L Thompson if (num_eval_mode_in == 0 || num_eval_mode_out == 0) { 561eaf62fffSJeremy L Thompson // LCOV_EXCL_START 562*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Cannot assemble operator with out inputs/outputs"); 563eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 564*2b730f8bSJeremy L Thompson } 565eaf62fffSJeremy L Thompson 566ed9e99e6SJeremy L Thompson CeedElemRestriction active_rstr; 567eaf62fffSJeremy L Thompson CeedInt num_elem, elem_size, num_qpts, num_comp; 568*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveElemRestriction(op, &active_rstr)); 569*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(active_rstr, &num_elem)); 570*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetElementSize(active_rstr, &elem_size)); 571*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumComponents(active_rstr, &num_comp)); 572*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts)); 573eaf62fffSJeremy L Thompson 574eaf62fffSJeremy L Thompson CeedInt local_num_entries = elem_size * num_comp * elem_size * num_comp * num_elem; 575eaf62fffSJeremy L Thompson 576eaf62fffSJeremy L Thompson // loop over elements and put in data structure 577eaf62fffSJeremy L Thompson const CeedScalar *interp_in, *grad_in; 578*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetInterp(basis_in, &interp_in)); 579*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetGrad(basis_in, &grad_in)); 580eaf62fffSJeremy L Thompson 581eaf62fffSJeremy L Thompson const CeedScalar *assembled_qf_array; 582*2b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array)); 583eaf62fffSJeremy L Thompson 584eaf62fffSJeremy L Thompson CeedInt layout_qf[3]; 585*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetELayout(rstr_q, &layout_qf)); 586*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&rstr_q)); 587eaf62fffSJeremy L Thompson 588eaf62fffSJeremy L Thompson // we store B_mat_in, B_mat_out, BTD, elem_mat in row-major order 589ed9e99e6SJeremy L Thompson const CeedScalar *B_mat_in, *B_mat_out; 590*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorAssemblyDataGetBases(data, NULL, &B_mat_in, NULL, &B_mat_out)); 591ed9e99e6SJeremy L Thompson CeedScalar BTD_mat[elem_size * num_qpts * num_eval_mode_in]; 592eaf62fffSJeremy L Thompson CeedScalar elem_mat[elem_size * elem_size]; 59392ae7e47SJeremy L Thompson CeedInt count = 0; 594eaf62fffSJeremy L Thompson CeedScalar *vals; 595*2b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayWrite(values, CEED_MEM_HOST, &vals)); 596ed9e99e6SJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) { 597ed9e99e6SJeremy L Thompson for (CeedInt comp_in = 0; comp_in < num_comp; comp_in++) { 598ed9e99e6SJeremy L Thompson for (CeedInt comp_out = 0; comp_out < num_comp; comp_out++) { 599ed9e99e6SJeremy L Thompson // Compute B^T*D 600ed9e99e6SJeremy L Thompson for (CeedInt n = 0; n < elem_size; n++) { 601ed9e99e6SJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 602ed9e99e6SJeremy L Thompson for (CeedInt e_in = 0; e_in < num_eval_mode_in; e_in++) { 603*2b730f8bSJeremy L Thompson const CeedInt btd_index = n * (num_qpts * num_eval_mode_in) + (num_eval_mode_in * q + e_in); 604067fd99fSJeremy L Thompson CeedScalar sum = 0.0; 605067fd99fSJeremy L Thompson for (CeedInt e_out = 0; e_out < num_eval_mode_out; e_out++) { 606ed9e99e6SJeremy L Thompson const CeedInt b_out_index = (num_eval_mode_out * q + e_out) * elem_size + n; 607*2b730f8bSJeremy L Thompson const CeedInt eval_mode_index = ((e_in * num_comp + comp_in) * num_eval_mode_out + e_out) * num_comp + comp_out; 608*2b730f8bSJeremy L Thompson const CeedInt qf_index = q * layout_qf[0] + eval_mode_index * layout_qf[1] + e * layout_qf[2]; 609067fd99fSJeremy L Thompson sum += B_mat_out[b_out_index] * assembled_qf_array[qf_index]; 610eaf62fffSJeremy L Thompson } 611067fd99fSJeremy L Thompson BTD_mat[btd_index] = sum; 612ed9e99e6SJeremy L Thompson } 613ed9e99e6SJeremy L Thompson } 614eaf62fffSJeremy L Thompson } 615eaf62fffSJeremy L Thompson // form element matrix itself (for each block component) 616*2b730f8bSJeremy L Thompson CeedCall(CeedMatrixMatrixMultiply(ceed, BTD_mat, B_mat_in, elem_mat, elem_size, elem_size, num_qpts * num_eval_mode_in)); 617eaf62fffSJeremy L Thompson 618eaf62fffSJeremy L Thompson // put element matrix in coordinate data structure 619ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < elem_size; i++) { 620ed9e99e6SJeremy L Thompson for (CeedInt j = 0; j < elem_size; j++) { 621eaf62fffSJeremy L Thompson vals[offset + count] = elem_mat[i * elem_size + j]; 622eaf62fffSJeremy L Thompson count++; 623eaf62fffSJeremy L Thompson } 624eaf62fffSJeremy L Thompson } 625eaf62fffSJeremy L Thompson } 626eaf62fffSJeremy L Thompson } 627eaf62fffSJeremy L Thompson } 628*2b730f8bSJeremy L Thompson if (count != local_num_entries) { 629eaf62fffSJeremy L Thompson // LCOV_EXCL_START 630eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing entries"); 631eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 632*2b730f8bSJeremy L Thompson } 633*2b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArray(values, &vals)); 634eaf62fffSJeremy L Thompson 635*2b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array)); 636*2b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&assembled_qf)); 637eaf62fffSJeremy L Thompson 638eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 639eaf62fffSJeremy L Thompson } 640eaf62fffSJeremy L Thompson 641eaf62fffSJeremy L Thompson /** 642eaf62fffSJeremy L Thompson @brief Count number of entries for assembled CeedOperator 643eaf62fffSJeremy L Thompson 644eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 645eaf62fffSJeremy L Thompson @param[out] num_entries Number of entries in assembled representation 646eaf62fffSJeremy L Thompson 647eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 648eaf62fffSJeremy L Thompson 649eaf62fffSJeremy L Thompson @ref Utility 650eaf62fffSJeremy L Thompson **/ 651*2b730f8bSJeremy L Thompson static int CeedSingleOperatorAssemblyCountEntries(CeedOperator op, CeedInt *num_entries) { 652eaf62fffSJeremy L Thompson CeedElemRestriction rstr; 653eaf62fffSJeremy L Thompson CeedInt num_elem, elem_size, num_comp; 654eaf62fffSJeremy L Thompson 655*2b730f8bSJeremy L Thompson if (op->is_composite) { 656eaf62fffSJeremy L Thompson // LCOV_EXCL_START 657*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, "Composite operator not supported"); 658eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 659*2b730f8bSJeremy L Thompson } 660*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveElemRestriction(op, &rstr)); 661*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 662*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 663*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 664eaf62fffSJeremy L Thompson *num_entries = elem_size * num_comp * elem_size * num_comp * num_elem; 665eaf62fffSJeremy L Thompson 666eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 667eaf62fffSJeremy L Thompson } 668eaf62fffSJeremy L Thompson 669eaf62fffSJeremy L Thompson /** 670eaf62fffSJeremy L Thompson @brief Common code for creating a multigrid coarse operator and level 671eaf62fffSJeremy L Thompson transfer operators for a CeedOperator 672eaf62fffSJeremy L Thompson 673eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 674eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 675eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 676eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 677eaf62fffSJeremy L Thompson @param[in] basis_c_to_f Basis for coarse to fine interpolation 678eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 679eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 680eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 681eaf62fffSJeremy L Thompson 682eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 683eaf62fffSJeremy L Thompson 684eaf62fffSJeremy L Thompson @ref Developer 685eaf62fffSJeremy L Thompson **/ 686*2b730f8bSJeremy L Thompson static int CeedSingleOperatorMultigridLevel(CeedOperator op_fine, CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 687*2b730f8bSJeremy L Thompson CeedBasis basis_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong, CeedOperator *op_restrict) { 688eaf62fffSJeremy L Thompson Ceed ceed; 689*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op_fine, &ceed)); 690eaf62fffSJeremy L Thompson 691eaf62fffSJeremy L Thompson // Check for composite operator 692eaf62fffSJeremy L Thompson bool is_composite; 693*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorIsComposite(op_fine, &is_composite)); 694*2b730f8bSJeremy L Thompson if (is_composite) { 695eaf62fffSJeremy L Thompson // LCOV_EXCL_START 696*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Automatic multigrid setup for composite operators not supported"); 697eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 698*2b730f8bSJeremy L Thompson } 699eaf62fffSJeremy L Thompson 700eaf62fffSJeremy L Thompson // Coarse Grid 701*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(ceed, op_fine->qf, op_fine->dqf, op_fine->dqfT, op_coarse)); 702eaf62fffSJeremy L Thompson CeedElemRestriction rstr_fine = NULL; 703eaf62fffSJeremy L Thompson // -- Clone input fields 70492ae7e47SJeremy L Thompson for (CeedInt i = 0; i < op_fine->qf->num_input_fields; i++) { 705eaf62fffSJeremy L Thompson if (op_fine->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 706eaf62fffSJeremy L Thompson rstr_fine = op_fine->input_fields[i]->elem_restr; 707*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name, rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE)); 708eaf62fffSJeremy L Thompson } else { 709*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name, op_fine->input_fields[i]->elem_restr, 710*2b730f8bSJeremy L Thompson op_fine->input_fields[i]->basis, op_fine->input_fields[i]->vec)); 711eaf62fffSJeremy L Thompson } 712eaf62fffSJeremy L Thompson } 713eaf62fffSJeremy L Thompson // -- Clone output fields 71492ae7e47SJeremy L Thompson for (CeedInt i = 0; i < op_fine->qf->num_output_fields; i++) { 715eaf62fffSJeremy L Thompson if (op_fine->output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 716*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name, rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE)); 717eaf62fffSJeremy L Thompson } else { 718*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name, op_fine->output_fields[i]->elem_restr, 719*2b730f8bSJeremy L Thompson op_fine->output_fields[i]->basis, op_fine->output_fields[i]->vec)); 720eaf62fffSJeremy L Thompson } 721eaf62fffSJeremy L Thompson } 722af99e877SJeremy L Thompson // -- Clone QFunctionAssemblyData 723*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataReferenceCopy(op_fine->qf_assembled, &(*op_coarse)->qf_assembled)); 724eaf62fffSJeremy L Thompson 725eaf62fffSJeremy L Thompson // Multiplicity vector 726eaf62fffSJeremy L Thompson CeedVector mult_vec, mult_e_vec; 727*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionCreateVector(rstr_fine, &mult_vec, &mult_e_vec)); 728*2b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(mult_e_vec, 0.0)); 729*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionApply(rstr_fine, CEED_NOTRANSPOSE, p_mult_fine, mult_e_vec, CEED_REQUEST_IMMEDIATE)); 730*2b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(mult_vec, 0.0)); 731*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionApply(rstr_fine, CEED_TRANSPOSE, mult_e_vec, mult_vec, CEED_REQUEST_IMMEDIATE)); 732*2b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&mult_e_vec)); 733*2b730f8bSJeremy L Thompson CeedCall(CeedVectorReciprocal(mult_vec)); 734eaf62fffSJeremy L Thompson 735eaf62fffSJeremy L Thompson // Restriction 736eaf62fffSJeremy L Thompson CeedInt num_comp; 737*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumComponents(basis_coarse, &num_comp)); 738eaf62fffSJeremy L Thompson CeedQFunction qf_restrict; 739*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_restrict)); 740eaf62fffSJeremy L Thompson CeedInt *num_comp_r_data; 741*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, &num_comp_r_data)); 742eaf62fffSJeremy L Thompson num_comp_r_data[0] = num_comp; 743eaf62fffSJeremy L Thompson CeedQFunctionContext ctx_r; 744*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextCreate(ceed, &ctx_r)); 745*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextSetData(ctx_r, CEED_MEM_HOST, CEED_OWN_POINTER, sizeof(*num_comp_r_data), num_comp_r_data)); 746*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetContext(qf_restrict, ctx_r)); 747*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextDestroy(&ctx_r)); 748*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_restrict, "input", num_comp, CEED_EVAL_NONE)); 749*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_restrict, "scale", num_comp, CEED_EVAL_NONE)); 750*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddOutput(qf_restrict, "output", num_comp, CEED_EVAL_INTERP)); 751*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetUserFlopsEstimate(qf_restrict, num_comp)); 752eaf62fffSJeremy L Thompson 753*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(ceed, qf_restrict, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, op_restrict)); 754*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_restrict, "input", rstr_fine, CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE)); 755*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_restrict, "scale", rstr_fine, CEED_BASIS_COLLOCATED, mult_vec)); 756*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_restrict, "output", rstr_coarse, basis_c_to_f, CEED_VECTOR_ACTIVE)); 757eaf62fffSJeremy L Thompson 758eaf62fffSJeremy L Thompson // Prolongation 759eaf62fffSJeremy L Thompson CeedQFunction qf_prolong; 760*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_prolong)); 761eaf62fffSJeremy L Thompson CeedInt *num_comp_p_data; 762*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, &num_comp_p_data)); 763eaf62fffSJeremy L Thompson num_comp_p_data[0] = num_comp; 764eaf62fffSJeremy L Thompson CeedQFunctionContext ctx_p; 765*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextCreate(ceed, &ctx_p)); 766*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextSetData(ctx_p, CEED_MEM_HOST, CEED_OWN_POINTER, sizeof(*num_comp_p_data), num_comp_p_data)); 767*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetContext(qf_prolong, ctx_p)); 768*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextDestroy(&ctx_p)); 769*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_prolong, "input", num_comp, CEED_EVAL_INTERP)); 770*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_prolong, "scale", num_comp, CEED_EVAL_NONE)); 771*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddOutput(qf_prolong, "output", num_comp, CEED_EVAL_NONE)); 772*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetUserFlopsEstimate(qf_prolong, num_comp)); 773eaf62fffSJeremy L Thompson 774*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(ceed, qf_prolong, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, op_prolong)); 775*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_prolong, "input", rstr_coarse, basis_c_to_f, CEED_VECTOR_ACTIVE)); 776*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_prolong, "scale", rstr_fine, CEED_BASIS_COLLOCATED, mult_vec)); 777*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*op_prolong, "output", rstr_fine, CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE)); 778eaf62fffSJeremy L Thompson 779ea6b5821SJeremy L Thompson // Clone name 780ea6b5821SJeremy L Thompson bool has_name = op_fine->name; 781ea6b5821SJeremy L Thompson size_t name_len = op_fine->name ? strlen(op_fine->name) : 0; 782*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetName(*op_coarse, op_fine->name)); 783ea6b5821SJeremy L Thompson { 784ea6b5821SJeremy L Thompson char *prolongation_name; 785*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(18 + name_len, &prolongation_name)); 786*2b730f8bSJeremy L Thompson sprintf(prolongation_name, "prolongation%s%s", has_name ? " for " : "", has_name ? op_fine->name : ""); 787*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetName(*op_prolong, prolongation_name)); 788*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&prolongation_name)); 789ea6b5821SJeremy L Thompson } 790ea6b5821SJeremy L Thompson { 791ea6b5821SJeremy L Thompson char *restriction_name; 792*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(17 + name_len, &restriction_name)); 793*2b730f8bSJeremy L Thompson sprintf(restriction_name, "restriction%s%s", has_name ? " for " : "", has_name ? op_fine->name : ""); 794*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetName(*op_restrict, restriction_name)); 795*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&restriction_name)); 796ea6b5821SJeremy L Thompson } 797ea6b5821SJeremy L Thompson 798eaf62fffSJeremy L Thompson // Cleanup 799*2b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&mult_vec)); 800*2b730f8bSJeremy L Thompson CeedCall(CeedBasisDestroy(&basis_c_to_f)); 801*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&qf_restrict)); 802*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&qf_prolong)); 803805fe78eSJeremy L Thompson 804eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 805eaf62fffSJeremy L Thompson } 806eaf62fffSJeremy L Thompson 807eaf62fffSJeremy L Thompson /** 808eaf62fffSJeremy L Thompson @brief Build 1D mass matrix and Laplacian with perturbation 809eaf62fffSJeremy L Thompson 810eaf62fffSJeremy L Thompson @param[in] interp_1d Interpolation matrix in one dimension 811eaf62fffSJeremy L Thompson @param[in] grad_1d Gradient matrix in one dimension 812eaf62fffSJeremy L Thompson @param[in] q_weight_1d Quadrature weights in one dimension 813eaf62fffSJeremy L Thompson @param[in] P_1d Number of basis nodes in one dimension 814eaf62fffSJeremy L Thompson @param[in] Q_1d Number of quadrature points in one dimension 815eaf62fffSJeremy L Thompson @param[in] dim Dimension of basis 816eaf62fffSJeremy L Thompson @param[out] mass Assembled mass matrix in one dimension 817eaf62fffSJeremy L Thompson @param[out] laplace Assembled perturbed Laplacian in one dimension 818eaf62fffSJeremy L Thompson 819eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 820eaf62fffSJeremy L Thompson 821eaf62fffSJeremy L Thompson @ref Developer 822eaf62fffSJeremy L Thompson **/ 823*2b730f8bSJeremy L Thompson CeedPragmaOptimizeOff static int CeedBuildMassLaplace(const CeedScalar *interp_1d, const CeedScalar *grad_1d, const CeedScalar *q_weight_1d, 824*2b730f8bSJeremy L Thompson CeedInt P_1d, CeedInt Q_1d, CeedInt dim, CeedScalar *mass, CeedScalar *laplace) { 825*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < P_1d; i++) { 826eaf62fffSJeremy L Thompson for (CeedInt j = 0; j < P_1d; j++) { 827eaf62fffSJeremy L Thompson CeedScalar sum = 0.0; 828*2b730f8bSJeremy 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]; 829eaf62fffSJeremy L Thompson mass[i + j * P_1d] = sum; 830eaf62fffSJeremy L Thompson } 831*2b730f8bSJeremy L Thompson } 832eaf62fffSJeremy L Thompson // -- Laplacian 833*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < P_1d; i++) { 834eaf62fffSJeremy L Thompson for (CeedInt j = 0; j < P_1d; j++) { 835eaf62fffSJeremy L Thompson CeedScalar sum = 0.0; 836*2b730f8bSJeremy 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]; 837eaf62fffSJeremy L Thompson laplace[i + j * P_1d] = sum; 838eaf62fffSJeremy L Thompson } 839*2b730f8bSJeremy L Thompson } 840eaf62fffSJeremy L Thompson CeedScalar perturbation = dim > 2 ? 1e-6 : 1e-4; 841*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < P_1d; i++) laplace[i + P_1d * i] += perturbation; 842eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 843eaf62fffSJeremy L Thompson } 844eaf62fffSJeremy L Thompson CeedPragmaOptimizeOn 845eaf62fffSJeremy L Thompson 846eaf62fffSJeremy L Thompson /// @} 847eaf62fffSJeremy L Thompson 848eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 849480fae85SJeremy L Thompson /// CeedOperator Backend API 850480fae85SJeremy L Thompson /// ---------------------------------------------------------------------------- 851480fae85SJeremy L Thompson /// @addtogroup CeedOperatorBackend 852480fae85SJeremy L Thompson /// @{ 853480fae85SJeremy L Thompson 854480fae85SJeremy L Thompson /** 855480fae85SJeremy L Thompson @brief Create object holding CeedQFunction assembly data for CeedOperator 856480fae85SJeremy L Thompson 857480fae85SJeremy L Thompson @param[in] ceed A Ceed object where the CeedQFunctionAssemblyData will be created 858480fae85SJeremy L Thompson @param[out] data Address of the variable where the newly created 859480fae85SJeremy L Thompson CeedQFunctionAssemblyData will be stored 860480fae85SJeremy L Thompson 861480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 862480fae85SJeremy L Thompson 863480fae85SJeremy L Thompson @ref Backend 864480fae85SJeremy L Thompson **/ 865*2b730f8bSJeremy L Thompson int 866*2b730f8bSJeremy L Thompson CeedQFunctionAssemblyDataCreate(Ceed ceed, CeedQFunctionAssemblyData *data) { 867*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, data)); 868480fae85SJeremy L Thompson (*data)->ref_count = 1; 869480fae85SJeremy L Thompson (*data)->ceed = ceed; 870*2b730f8bSJeremy L Thompson CeedCall(CeedReference(ceed)); 871480fae85SJeremy L Thompson 872480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 873480fae85SJeremy L Thompson } 874480fae85SJeremy L Thompson 875480fae85SJeremy L Thompson /** 876480fae85SJeremy L Thompson @brief Increment the reference counter for a CeedQFunctionAssemblyData 877480fae85SJeremy L Thompson 878480fae85SJeremy L Thompson @param data CeedQFunctionAssemblyData to increment the reference counter 879480fae85SJeremy L Thompson 880480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 881480fae85SJeremy L Thompson 882480fae85SJeremy L Thompson @ref Backend 883480fae85SJeremy L Thompson **/ 884480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataReference(CeedQFunctionAssemblyData data) { 885480fae85SJeremy L Thompson data->ref_count++; 886480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 887480fae85SJeremy L Thompson } 888480fae85SJeremy L Thompson 889480fae85SJeremy L Thompson /** 890beecbf24SJeremy L Thompson @brief Set re-use of CeedQFunctionAssemblyData 8918b919e6bSJeremy L Thompson 892beecbf24SJeremy L Thompson @param data CeedQFunctionAssemblyData to mark for reuse 893beecbf24SJeremy L Thompson @param reuse_data Boolean flag indicating data re-use 8948b919e6bSJeremy L Thompson 8958b919e6bSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 8968b919e6bSJeremy L Thompson 8978b919e6bSJeremy L Thompson @ref Backend 8988b919e6bSJeremy L Thompson **/ 899*2b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataSetReuse(CeedQFunctionAssemblyData data, bool reuse_data) { 900beecbf24SJeremy L Thompson data->reuse_data = reuse_data; 901beecbf24SJeremy L Thompson data->needs_data_update = true; 902beecbf24SJeremy L Thompson return CEED_ERROR_SUCCESS; 903beecbf24SJeremy L Thompson } 904beecbf24SJeremy L Thompson 905beecbf24SJeremy L Thompson /** 906beecbf24SJeremy L Thompson @brief Mark QFunctionAssemblyData as stale 907beecbf24SJeremy L Thompson 908beecbf24SJeremy L Thompson @param data CeedQFunctionAssemblyData to mark as stale 909beecbf24SJeremy L Thompson @param needs_data_update Boolean flag indicating if update is needed or completed 910beecbf24SJeremy L Thompson 911beecbf24SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 912beecbf24SJeremy L Thompson 913beecbf24SJeremy L Thompson @ref Backend 914beecbf24SJeremy L Thompson **/ 915*2b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataSetUpdateNeeded(CeedQFunctionAssemblyData data, bool needs_data_update) { 916beecbf24SJeremy L Thompson data->needs_data_update = needs_data_update; 9178b919e6bSJeremy L Thompson return CEED_ERROR_SUCCESS; 9188b919e6bSJeremy L Thompson } 9198b919e6bSJeremy L Thompson 9208b919e6bSJeremy L Thompson /** 9218b919e6bSJeremy L Thompson @brief Determine if QFunctionAssemblyData needs update 9228b919e6bSJeremy L Thompson 9238b919e6bSJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to mark as stale 9248b919e6bSJeremy L Thompson @param[out] is_update_needed Boolean flag indicating if re-assembly is required 9258b919e6bSJeremy L Thompson 9268b919e6bSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 9278b919e6bSJeremy L Thompson 9288b919e6bSJeremy L Thompson @ref Backend 9298b919e6bSJeremy L Thompson **/ 930*2b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataIsUpdateNeeded(CeedQFunctionAssemblyData data, bool *is_update_needed) { 931beecbf24SJeremy L Thompson *is_update_needed = !data->reuse_data || data->needs_data_update; 9328b919e6bSJeremy L Thompson return CEED_ERROR_SUCCESS; 9338b919e6bSJeremy L Thompson } 9348b919e6bSJeremy L Thompson 9358b919e6bSJeremy L Thompson /** 936480fae85SJeremy L Thompson @brief Copy the pointer to a CeedQFunctionAssemblyData. Both pointers should 937480fae85SJeremy L Thompson be destroyed with `CeedCeedQFunctionAssemblyDataDestroy()`; 938480fae85SJeremy L Thompson Note: If `*data_copy` is non-NULL, then it is assumed that 939480fae85SJeremy L Thompson `*data_copy` is a pointer to a CeedQFunctionAssemblyData. This 940480fae85SJeremy L Thompson CeedQFunctionAssemblyData will be destroyed if `*data_copy` is 941480fae85SJeremy L Thompson the only reference to this CeedQFunctionAssemblyData. 942480fae85SJeremy L Thompson 943480fae85SJeremy L Thompson @param data CeedQFunctionAssemblyData to copy reference to 944480fae85SJeremy L Thompson @param[out] data_copy Variable to store copied reference 945480fae85SJeremy L Thompson 946480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 947480fae85SJeremy L Thompson 948480fae85SJeremy L Thompson @ref Backend 949480fae85SJeremy L Thompson **/ 950*2b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataReferenceCopy(CeedQFunctionAssemblyData data, CeedQFunctionAssemblyData *data_copy) { 951*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataReference(data)); 952*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataDestroy(data_copy)); 953480fae85SJeremy L Thompson *data_copy = data; 954480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 955480fae85SJeremy L Thompson } 956480fae85SJeremy L Thompson 957480fae85SJeremy L Thompson /** 958480fae85SJeremy L Thompson @brief Get setup status for internal objects for CeedQFunctionAssemblyData 959480fae85SJeremy L Thompson 960480fae85SJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to retreive status 961480fae85SJeremy L Thompson @param[out] is_setup Boolean flag for setup status 962480fae85SJeremy L Thompson 963480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 964480fae85SJeremy L Thompson 965480fae85SJeremy L Thompson @ref Backend 966480fae85SJeremy L Thompson **/ 967*2b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataIsSetup(CeedQFunctionAssemblyData data, bool *is_setup) { 968480fae85SJeremy L Thompson *is_setup = data->is_setup; 969480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 970480fae85SJeremy L Thompson } 971480fae85SJeremy L Thompson 972480fae85SJeremy L Thompson /** 973480fae85SJeremy L Thompson @brief Set internal objects for CeedQFunctionAssemblyData 974480fae85SJeremy L Thompson 975480fae85SJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to set objects 976480fae85SJeremy L Thompson @param[in] vec CeedVector to store assembled CeedQFunction at quadrature points 977480fae85SJeremy L Thompson @param[in] rstr CeedElemRestriction for CeedVector containing assembled CeedQFunction 978480fae85SJeremy L Thompson 979480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 980480fae85SJeremy L Thompson 981480fae85SJeremy L Thompson @ref Backend 982480fae85SJeremy L Thompson **/ 983*2b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataSetObjects(CeedQFunctionAssemblyData data, CeedVector vec, CeedElemRestriction rstr) { 984*2b730f8bSJeremy L Thompson CeedCall(CeedVectorReferenceCopy(vec, &data->vec)); 985*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionReferenceCopy(rstr, &data->rstr)); 986480fae85SJeremy L Thompson 987480fae85SJeremy L Thompson data->is_setup = true; 988480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 989480fae85SJeremy L Thompson } 990480fae85SJeremy L Thompson 991*2b730f8bSJeremy L Thompson int CeedQFunctionAssemblyDataGetObjects(CeedQFunctionAssemblyData data, CeedVector *vec, CeedElemRestriction *rstr) { 992*2b730f8bSJeremy L Thompson if (!data->is_setup) { 993480fae85SJeremy L Thompson // LCOV_EXCL_START 994*2b730f8bSJeremy L Thompson return CeedError(data->ceed, CEED_ERROR_INCOMPLETE, "Internal objects not set; must call CeedQFunctionAssemblyDataSetObjects first."); 995480fae85SJeremy L Thompson // LCOV_EXCL_STOP 996*2b730f8bSJeremy L Thompson } 997480fae85SJeremy L Thompson 998*2b730f8bSJeremy L Thompson CeedCall(CeedVectorReferenceCopy(data->vec, vec)); 999*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionReferenceCopy(data->rstr, rstr)); 1000480fae85SJeremy L Thompson 1001480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1002480fae85SJeremy L Thompson } 1003480fae85SJeremy L Thompson 1004480fae85SJeremy L Thompson /** 1005480fae85SJeremy L Thompson @brief Destroy CeedQFunctionAssemblyData 1006480fae85SJeremy L Thompson 1007480fae85SJeremy L Thompson @param[out] data CeedQFunctionAssemblyData to destroy 1008480fae85SJeremy L Thompson 1009480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1010480fae85SJeremy L Thompson 1011480fae85SJeremy L Thompson @ref Backend 1012480fae85SJeremy L Thompson **/ 1013480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataDestroy(CeedQFunctionAssemblyData *data) { 1014480fae85SJeremy L Thompson if (!*data || --(*data)->ref_count > 0) return CEED_ERROR_SUCCESS; 1015480fae85SJeremy L Thompson 1016*2b730f8bSJeremy L Thompson CeedCall(CeedDestroy(&(*data)->ceed)); 1017*2b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&(*data)->vec)); 1018*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&(*data)->rstr)); 1019480fae85SJeremy L Thompson 1020*2b730f8bSJeremy L Thompson CeedCall(CeedFree(data)); 1021480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1022480fae85SJeremy L Thompson } 1023480fae85SJeremy L Thompson 1024ed9e99e6SJeremy L Thompson /** 1025ed9e99e6SJeremy L Thompson @brief Get CeedOperatorAssemblyData 1026ed9e99e6SJeremy L Thompson 1027ed9e99e6SJeremy L Thompson @param[in] op CeedOperator to assemble 1028ed9e99e6SJeremy L Thompson @param[out] data CeedQFunctionAssemblyData 1029ed9e99e6SJeremy L Thompson 1030ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1031ed9e99e6SJeremy L Thompson 1032ed9e99e6SJeremy L Thompson @ref Backend 1033ed9e99e6SJeremy L Thompson **/ 1034*2b730f8bSJeremy L Thompson int CeedOperatorGetOperatorAssemblyData(CeedOperator op, CeedOperatorAssemblyData *data) { 1035ed9e99e6SJeremy L Thompson if (!op->op_assembled) { 1036ed9e99e6SJeremy L Thompson CeedOperatorAssemblyData data; 1037ed9e99e6SJeremy L Thompson 1038*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorAssemblyDataCreate(op->ceed, op, &data)); 1039ed9e99e6SJeremy L Thompson op->op_assembled = data; 1040ed9e99e6SJeremy L Thompson } 1041ed9e99e6SJeremy L Thompson *data = op->op_assembled; 1042ed9e99e6SJeremy L Thompson 1043ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1044ed9e99e6SJeremy L Thompson } 1045ed9e99e6SJeremy L Thompson 1046ed9e99e6SJeremy L Thompson /** 1047ed9e99e6SJeremy L Thompson @brief Create object holding CeedOperator assembly data 1048ed9e99e6SJeremy L Thompson 1049ed9e99e6SJeremy L Thompson @param[in] ceed A Ceed object where the CeedOperatorAssemblyData will be created 1050ed9e99e6SJeremy L Thompson @param[in] op CeedOperator to be assembled 1051ed9e99e6SJeremy L Thompson @param[out] data Address of the variable where the newly created 1052ed9e99e6SJeremy L Thompson CeedOperatorAssemblyData will be stored 1053ed9e99e6SJeremy L Thompson 1054ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1055ed9e99e6SJeremy L Thompson 1056ed9e99e6SJeremy L Thompson @ref Backend 1057ed9e99e6SJeremy L Thompson **/ 1058*2b730f8bSJeremy L Thompson int CeedOperatorAssemblyDataCreate(Ceed ceed, CeedOperator op, CeedOperatorAssemblyData *data) { 1059*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, data)); 1060ed9e99e6SJeremy L Thompson (*data)->ceed = ceed; 1061*2b730f8bSJeremy L Thompson CeedCall(CeedReference(ceed)); 1062ed9e99e6SJeremy L Thompson 1063ed9e99e6SJeremy L Thompson // Build OperatorAssembly data 1064ed9e99e6SJeremy L Thompson CeedQFunction qf; 1065ed9e99e6SJeremy L Thompson CeedQFunctionField *qf_fields; 1066ed9e99e6SJeremy L Thompson CeedOperatorField *op_fields; 1067ed9e99e6SJeremy L Thompson CeedInt num_input_fields; 1068*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetQFunction(op, &qf)); 1069*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, &qf_fields, NULL, NULL)); 1070*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFields(op, NULL, &op_fields, NULL, NULL)); 1071ed9e99e6SJeremy L Thompson 1072ed9e99e6SJeremy L Thompson // Determine active input basis 1073ed9e99e6SJeremy L Thompson CeedInt num_eval_mode_in = 0, dim = 1; 1074ed9e99e6SJeremy L Thompson CeedEvalMode *eval_mode_in = NULL; 1075ed9e99e6SJeremy L Thompson CeedBasis basis_in = NULL; 1076ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < num_input_fields; i++) { 1077ed9e99e6SJeremy L Thompson CeedVector vec; 1078*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetVector(op_fields[i], &vec)); 1079ed9e99e6SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 1080*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetBasis(op_fields[i], &basis_in)); 1081*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetDimension(basis_in, &dim)); 1082ed9e99e6SJeremy L Thompson CeedEvalMode eval_mode; 1083*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode)); 1084ed9e99e6SJeremy L Thompson switch (eval_mode) { 1085ed9e99e6SJeremy L Thompson case CEED_EVAL_NONE: 1086ed9e99e6SJeremy L Thompson case CEED_EVAL_INTERP: 1087*2b730f8bSJeremy L Thompson CeedCall(CeedRealloc(num_eval_mode_in + 1, &eval_mode_in)); 1088ed9e99e6SJeremy L Thompson eval_mode_in[num_eval_mode_in] = eval_mode; 1089ed9e99e6SJeremy L Thompson num_eval_mode_in += 1; 1090ed9e99e6SJeremy L Thompson break; 1091ed9e99e6SJeremy L Thompson case CEED_EVAL_GRAD: 1092*2b730f8bSJeremy L Thompson CeedCall(CeedRealloc(num_eval_mode_in + dim, &eval_mode_in)); 1093ed9e99e6SJeremy L Thompson for (CeedInt d = 0; d < dim; d++) { 1094ed9e99e6SJeremy L Thompson eval_mode_in[num_eval_mode_in + d] = eval_mode; 1095ed9e99e6SJeremy L Thompson } 1096ed9e99e6SJeremy L Thompson num_eval_mode_in += dim; 1097ed9e99e6SJeremy L Thompson break; 1098ed9e99e6SJeremy L Thompson case CEED_EVAL_WEIGHT: 1099ed9e99e6SJeremy L Thompson case CEED_EVAL_DIV: 1100ed9e99e6SJeremy L Thompson case CEED_EVAL_CURL: 1101ed9e99e6SJeremy L Thompson break; // Caught by QF Assembly 1102ed9e99e6SJeremy L Thompson } 1103ed9e99e6SJeremy L Thompson } 1104ed9e99e6SJeremy L Thompson } 1105ed9e99e6SJeremy L Thompson (*data)->num_eval_mode_in = num_eval_mode_in; 1106ed9e99e6SJeremy L Thompson (*data)->eval_mode_in = eval_mode_in; 1107*2b730f8bSJeremy L Thompson CeedCall(CeedBasisReferenceCopy(basis_in, &(*data)->basis_in)); 1108ed9e99e6SJeremy L Thompson 1109ed9e99e6SJeremy L Thompson // Determine active output basis 1110ed9e99e6SJeremy L Thompson CeedInt num_output_fields; 1111*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionGetFields(qf, NULL, NULL, &num_output_fields, &qf_fields)); 1112*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFields(op, NULL, NULL, NULL, &op_fields)); 1113ed9e99e6SJeremy L Thompson CeedInt num_eval_mode_out = 0; 1114ed9e99e6SJeremy L Thompson CeedEvalMode *eval_mode_out = NULL; 1115ed9e99e6SJeremy L Thompson CeedBasis basis_out = NULL; 1116ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < num_output_fields; i++) { 1117ed9e99e6SJeremy L Thompson CeedVector vec; 1118*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetVector(op_fields[i], &vec)); 1119ed9e99e6SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 1120*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetBasis(op_fields[i], &basis_out)); 1121ed9e99e6SJeremy L Thompson CeedEvalMode eval_mode; 1122*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode)); 1123ed9e99e6SJeremy L Thompson switch (eval_mode) { 1124ed9e99e6SJeremy L Thompson case CEED_EVAL_NONE: 1125ed9e99e6SJeremy L Thompson case CEED_EVAL_INTERP: 1126*2b730f8bSJeremy L Thompson CeedCall(CeedRealloc(num_eval_mode_out + 1, &eval_mode_out)); 1127ed9e99e6SJeremy L Thompson eval_mode_out[num_eval_mode_out] = eval_mode; 1128ed9e99e6SJeremy L Thompson num_eval_mode_out += 1; 1129ed9e99e6SJeremy L Thompson break; 1130ed9e99e6SJeremy L Thompson case CEED_EVAL_GRAD: 1131*2b730f8bSJeremy L Thompson CeedCall(CeedRealloc(num_eval_mode_out + dim, &eval_mode_out)); 1132ed9e99e6SJeremy L Thompson for (CeedInt d = 0; d < dim; d++) { 1133ed9e99e6SJeremy L Thompson eval_mode_out[num_eval_mode_out + d] = eval_mode; 1134ed9e99e6SJeremy L Thompson } 1135ed9e99e6SJeremy L Thompson num_eval_mode_out += dim; 1136ed9e99e6SJeremy L Thompson break; 1137ed9e99e6SJeremy L Thompson case CEED_EVAL_WEIGHT: 1138ed9e99e6SJeremy L Thompson case CEED_EVAL_DIV: 1139ed9e99e6SJeremy L Thompson case CEED_EVAL_CURL: 1140ed9e99e6SJeremy L Thompson break; // Caught by QF Assembly 1141ed9e99e6SJeremy L Thompson } 1142ed9e99e6SJeremy L Thompson } 1143ed9e99e6SJeremy L Thompson } 1144ed9e99e6SJeremy L Thompson (*data)->num_eval_mode_out = num_eval_mode_out; 1145ed9e99e6SJeremy L Thompson (*data)->eval_mode_out = eval_mode_out; 1146*2b730f8bSJeremy L Thompson CeedCall(CeedBasisReferenceCopy(basis_out, &(*data)->basis_out)); 1147ed9e99e6SJeremy L Thompson 1148ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1149ed9e99e6SJeremy L Thompson } 1150ed9e99e6SJeremy L Thompson 1151ed9e99e6SJeremy L Thompson /** 1152ed9e99e6SJeremy L Thompson @brief Get CeedOperator CeedEvalModes for assembly 1153ed9e99e6SJeremy L Thompson 1154ed9e99e6SJeremy L Thompson @param[in] data CeedOperatorAssemblyData 1155ed9e99e6SJeremy L Thompson @param[out] num_eval_mode_in Pointer to hold number of input CeedEvalModes, or NULL 1156ed9e99e6SJeremy L Thompson @param[out] eval_mode_in Pointer to hold input CeedEvalModes, or NULL 1157ed9e99e6SJeremy L Thompson @param[out] num_eval_mode_out Pointer to hold number of output CeedEvalModes, or NULL 1158ed9e99e6SJeremy L Thompson @param[out] eval_mode_out Pointer to hold output CeedEvalModes, or NULL 1159ed9e99e6SJeremy L Thompson 1160ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1161ed9e99e6SJeremy L Thompson 1162ed9e99e6SJeremy L Thompson @ref Backend 1163ed9e99e6SJeremy L Thompson **/ 1164*2b730f8bSJeremy L Thompson int CeedOperatorAssemblyDataGetEvalModes(CeedOperatorAssemblyData data, CeedInt *num_eval_mode_in, const CeedEvalMode **eval_mode_in, 1165ed9e99e6SJeremy L Thompson CeedInt *num_eval_mode_out, const CeedEvalMode **eval_mode_out) { 1166ed9e99e6SJeremy L Thompson if (num_eval_mode_in) *num_eval_mode_in = data->num_eval_mode_in; 1167ed9e99e6SJeremy L Thompson if (eval_mode_in) *eval_mode_in = data->eval_mode_in; 1168ed9e99e6SJeremy L Thompson if (num_eval_mode_out) *num_eval_mode_out = data->num_eval_mode_out; 1169ed9e99e6SJeremy L Thompson if (eval_mode_out) *eval_mode_out = data->eval_mode_out; 1170ed9e99e6SJeremy L Thompson 1171ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1172ed9e99e6SJeremy L Thompson } 1173ed9e99e6SJeremy L Thompson 1174ed9e99e6SJeremy L Thompson /** 1175ed9e99e6SJeremy L Thompson @brief Get CeedOperator CeedBasis data for assembly 1176ed9e99e6SJeremy L Thompson 1177ed9e99e6SJeremy L Thompson @param[in] data CeedOperatorAssemblyData 1178ed9e99e6SJeremy L Thompson @param[out] basis_in Pointer to hold active input CeedBasis, or NULL 1179ed9e99e6SJeremy L Thompson @param[out] B_in Pointer to hold assembled active input B, or NULL 1180ed9e99e6SJeremy L Thompson @param[out] basis_out Pointer to hold active output CeedBasis, or NULL 1181ed9e99e6SJeremy L Thompson @param[out] B_out Pointer to hold assembled active output B, or NULL 1182ed9e99e6SJeremy L Thompson 1183ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1184ed9e99e6SJeremy L Thompson 1185ed9e99e6SJeremy L Thompson @ref Backend 1186ed9e99e6SJeremy L Thompson **/ 1187*2b730f8bSJeremy L Thompson int CeedOperatorAssemblyDataGetBases(CeedOperatorAssemblyData data, CeedBasis *basis_in, const CeedScalar **B_in, CeedBasis *basis_out, 1188ed9e99e6SJeremy L Thompson const CeedScalar **B_out) { 1189ed9e99e6SJeremy L Thompson // Assemble B_in, B_out if needed 1190ed9e99e6SJeremy L Thompson if (B_in && !data->B_in) { 1191ed9e99e6SJeremy L Thompson CeedInt num_qpts, elem_size; 1192ed9e99e6SJeremy L Thompson CeedScalar *B_in, *identity = NULL; 1193ed9e99e6SJeremy L Thompson const CeedScalar *interp_in, *grad_in; 1194ed9e99e6SJeremy L Thompson bool has_eval_none = false; 1195ed9e99e6SJeremy L Thompson 1196*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(data->basis_in, &num_qpts)); 1197*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumNodes(data->basis_in, &elem_size)); 1198*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_qpts * elem_size * data->num_eval_mode_in, &B_in)); 1199ed9e99e6SJeremy L Thompson 1200ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < data->num_eval_mode_in; i++) { 1201ed9e99e6SJeremy L Thompson has_eval_none = has_eval_none || (data->eval_mode_in[i] == CEED_EVAL_NONE); 1202ed9e99e6SJeremy L Thompson } 1203ed9e99e6SJeremy L Thompson if (has_eval_none) { 1204*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_qpts * elem_size, &identity)); 1205ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < (elem_size < num_qpts ? elem_size : num_qpts); i++) { 1206ed9e99e6SJeremy L Thompson identity[i * elem_size + i] = 1.0; 1207ed9e99e6SJeremy L Thompson } 1208ed9e99e6SJeremy L Thompson } 1209*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetInterp(data->basis_in, &interp_in)); 1210*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetGrad(data->basis_in, &grad_in)); 1211ed9e99e6SJeremy L Thompson 1212ed9e99e6SJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 1213ed9e99e6SJeremy L Thompson for (CeedInt n = 0; n < elem_size; n++) { 1214ed9e99e6SJeremy L Thompson CeedInt d_in = -1; 1215ed9e99e6SJeremy L Thompson for (CeedInt e_in = 0; e_in < data->num_eval_mode_in; e_in++) { 1216ed9e99e6SJeremy L Thompson const CeedInt qq = data->num_eval_mode_in * q; 1217ed9e99e6SJeremy L Thompson const CeedScalar *b = NULL; 1218ed9e99e6SJeremy L Thompson 1219ed9e99e6SJeremy L Thompson if (data->eval_mode_in[e_in] == CEED_EVAL_GRAD) d_in++; 1220*2b730f8bSJeremy L Thompson CeedOperatorGetBasisPointer(data->eval_mode_in[e_in], identity, interp_in, &grad_in[d_in * num_qpts * elem_size], &b); 1221ed9e99e6SJeremy L Thompson B_in[(qq + e_in) * elem_size + n] = b[q * elem_size + n]; 1222ed9e99e6SJeremy L Thompson } 1223ed9e99e6SJeremy L Thompson } 1224ed9e99e6SJeremy L Thompson } 1225ed9e99e6SJeremy L Thompson data->B_in = B_in; 1226ed9e99e6SJeremy L Thompson } 1227ed9e99e6SJeremy L Thompson 1228ed9e99e6SJeremy L Thompson if (B_out && !data->B_out) { 1229ed9e99e6SJeremy L Thompson CeedInt num_qpts, elem_size; 1230ed9e99e6SJeremy L Thompson CeedScalar *B_out, *identity = NULL; 1231ed9e99e6SJeremy L Thompson const CeedScalar *interp_out, *grad_out; 1232ed9e99e6SJeremy L Thompson bool has_eval_none = false; 1233ed9e99e6SJeremy L Thompson 1234*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(data->basis_out, &num_qpts)); 1235*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumNodes(data->basis_out, &elem_size)); 1236*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_qpts * elem_size * data->num_eval_mode_out, &B_out)); 1237ed9e99e6SJeremy L Thompson 1238ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < data->num_eval_mode_out; i++) { 1239ed9e99e6SJeremy L Thompson has_eval_none = has_eval_none || (data->eval_mode_out[i] == CEED_EVAL_NONE); 1240ed9e99e6SJeremy L Thompson } 1241ed9e99e6SJeremy L Thompson if (has_eval_none) { 1242*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_qpts * elem_size, &identity)); 1243ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < (elem_size < num_qpts ? elem_size : num_qpts); i++) { 1244ed9e99e6SJeremy L Thompson identity[i * elem_size + i] = 1.0; 1245ed9e99e6SJeremy L Thompson } 1246ed9e99e6SJeremy L Thompson } 1247*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetInterp(data->basis_out, &interp_out)); 1248*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetGrad(data->basis_out, &grad_out)); 1249ed9e99e6SJeremy L Thompson 1250ed9e99e6SJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 1251ed9e99e6SJeremy L Thompson for (CeedInt n = 0; n < elem_size; n++) { 1252ed9e99e6SJeremy L Thompson CeedInt d_out = -1; 1253ed9e99e6SJeremy L Thompson for (CeedInt e_out = 0; e_out < data->num_eval_mode_out; e_out++) { 1254ed9e99e6SJeremy L Thompson const CeedInt qq = data->num_eval_mode_out * q; 1255ed9e99e6SJeremy L Thompson const CeedScalar *b = NULL; 1256ed9e99e6SJeremy L Thompson 1257ed9e99e6SJeremy L Thompson if (data->eval_mode_out[e_out] == CEED_EVAL_GRAD) d_out++; 1258*2b730f8bSJeremy L Thompson CeedOperatorGetBasisPointer(data->eval_mode_out[e_out], identity, interp_out, &grad_out[d_out * num_qpts * elem_size], &b); 1259ed9e99e6SJeremy L Thompson B_out[(qq + e_out) * elem_size + n] = b[q * elem_size + n]; 1260ed9e99e6SJeremy L Thompson } 1261ed9e99e6SJeremy L Thompson } 1262ed9e99e6SJeremy L Thompson } 1263ed9e99e6SJeremy L Thompson data->B_out = B_out; 1264ed9e99e6SJeremy L Thompson } 1265ed9e99e6SJeremy L Thompson 1266ed9e99e6SJeremy L Thompson if (basis_in) *basis_in = data->basis_in; 1267ed9e99e6SJeremy L Thompson if (B_in) *B_in = data->B_in; 1268ed9e99e6SJeremy L Thompson if (basis_out) *basis_out = data->basis_out; 1269ed9e99e6SJeremy L Thompson if (B_out) *B_out = data->B_out; 1270ed9e99e6SJeremy L Thompson 1271ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1272ed9e99e6SJeremy L Thompson } 1273ed9e99e6SJeremy L Thompson 1274ed9e99e6SJeremy L Thompson /** 1275ed9e99e6SJeremy L Thompson @brief Destroy CeedOperatorAssemblyData 1276ed9e99e6SJeremy L Thompson 1277ed9e99e6SJeremy L Thompson @param[out] data CeedOperatorAssemblyData to destroy 1278ed9e99e6SJeremy L Thompson 1279ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1280ed9e99e6SJeremy L Thompson 1281ed9e99e6SJeremy L Thompson @ref Backend 1282ed9e99e6SJeremy L Thompson **/ 1283ed9e99e6SJeremy L Thompson int CeedOperatorAssemblyDataDestroy(CeedOperatorAssemblyData *data) { 1284ed9e99e6SJeremy L Thompson if (!*data) return CEED_ERROR_SUCCESS; 1285ed9e99e6SJeremy L Thompson 1286*2b730f8bSJeremy L Thompson CeedCall(CeedDestroy(&(*data)->ceed)); 1287*2b730f8bSJeremy L Thompson CeedCall(CeedBasisDestroy(&(*data)->basis_in)); 1288*2b730f8bSJeremy L Thompson CeedCall(CeedBasisDestroy(&(*data)->basis_out)); 1289*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_mode_in)); 1290*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*data)->eval_mode_out)); 1291*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*data)->B_in)); 1292*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*data)->B_out)); 1293ed9e99e6SJeremy L Thompson 1294*2b730f8bSJeremy L Thompson CeedCall(CeedFree(data)); 1295ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1296ed9e99e6SJeremy L Thompson } 1297ed9e99e6SJeremy L Thompson 1298480fae85SJeremy L Thompson /// @} 1299480fae85SJeremy L Thompson 1300480fae85SJeremy L Thompson /// ---------------------------------------------------------------------------- 1301eaf62fffSJeremy L Thompson /// CeedOperator Public API 1302eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 1303eaf62fffSJeremy L Thompson /// @addtogroup CeedOperatorUser 1304eaf62fffSJeremy L Thompson /// @{ 1305eaf62fffSJeremy L Thompson 1306eaf62fffSJeremy L Thompson /** 1307eaf62fffSJeremy L Thompson @brief Assemble a linear CeedQFunction associated with a CeedOperator 1308eaf62fffSJeremy L Thompson 1309eaf62fffSJeremy L Thompson This returns a CeedVector containing a matrix at each quadrature point 1310eaf62fffSJeremy L Thompson providing the action of the CeedQFunction associated with the CeedOperator. 1311eaf62fffSJeremy L Thompson The vector 'assembled' is of shape 1312eaf62fffSJeremy L Thompson [num_elements, num_input_fields, num_output_fields, num_quad_points] 1313eaf62fffSJeremy L Thompson and contains column-major matrices representing the action of the 1314eaf62fffSJeremy L Thompson CeedQFunction for a corresponding quadrature point on an element. Inputs and 1315eaf62fffSJeremy L Thompson outputs are in the order provided by the user when adding CeedOperator fields. 1316eaf62fffSJeremy L Thompson For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and 1317eaf62fffSJeremy L Thompson 'v', provided in that order, would result in an assembled QFunction that 1318eaf62fffSJeremy L Thompson consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting 1319eaf62fffSJeremy L Thompson on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v]. 1320eaf62fffSJeremy L Thompson 1321f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1322f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1323f04ea552SJeremy L Thompson 1324eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1325eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedQFunction at 1326eaf62fffSJeremy L Thompson quadrature points 1327eaf62fffSJeremy L Thompson @param[out] rstr CeedElemRestriction for CeedVector containing assembled 1328eaf62fffSJeremy L Thompson CeedQFunction 1329eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1330eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1331eaf62fffSJeremy L Thompson 1332eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1333eaf62fffSJeremy L Thompson 1334eaf62fffSJeremy L Thompson @ref User 1335eaf62fffSJeremy L Thompson **/ 1336*2b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) { 1337*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1338eaf62fffSJeremy L Thompson 1339eaf62fffSJeremy L Thompson if (op->LinearAssembleQFunction) { 1340d04bbc78SJeremy L Thompson // Backend version 1341*2b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleQFunction(op, assembled, rstr, request)); 1342eaf62fffSJeremy L Thompson } else { 1343d04bbc78SJeremy L Thompson // Operator fallback 1344d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1345d04bbc78SJeremy L Thompson 1346*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1347d04bbc78SJeremy L Thompson if (op_fallback) { 1348*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleQFunction(op_fallback, assembled, rstr, request)); 1349d04bbc78SJeremy L Thompson } else { 1350d04bbc78SJeremy L Thompson // LCOV_EXCL_START 1351*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedOperatorLinearAssembleQFunction"); 1352d04bbc78SJeremy L Thompson // LCOV_EXCL_STOP 1353d04bbc78SJeremy L Thompson } 135470a7ffb3SJeremy L Thompson } 1355eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1356eaf62fffSJeremy L Thompson } 135770a7ffb3SJeremy L Thompson 135870a7ffb3SJeremy L Thompson /** 135970a7ffb3SJeremy L Thompson @brief Assemble CeedQFunction and store result internall. Return copied 136070a7ffb3SJeremy L Thompson references of stored data to the caller. Caller is responsible for 136170a7ffb3SJeremy L Thompson ownership and destruction of the copied references. See also 136270a7ffb3SJeremy L Thompson @ref CeedOperatorLinearAssembleQFunction 136370a7ffb3SJeremy L Thompson 136470a7ffb3SJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 136570a7ffb3SJeremy L Thompson @param assembled CeedVector to store assembled CeedQFunction at 136670a7ffb3SJeremy L Thompson quadrature points 136770a7ffb3SJeremy L Thompson @param rstr CeedElemRestriction for CeedVector containing assembled 136870a7ffb3SJeremy L Thompson CeedQFunction 136970a7ffb3SJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 137070a7ffb3SJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 137170a7ffb3SJeremy L Thompson 137270a7ffb3SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 137370a7ffb3SJeremy L Thompson 137470a7ffb3SJeremy L Thompson @ref User 137570a7ffb3SJeremy L Thompson **/ 1376*2b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleQFunctionBuildOrUpdate(CeedOperator op, CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) { 1377*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 137870a7ffb3SJeremy L Thompson 137970a7ffb3SJeremy L Thompson if (op->LinearAssembleQFunctionUpdate) { 1380d04bbc78SJeremy L Thompson // Backend version 1381480fae85SJeremy L Thompson bool qf_assembled_is_setup; 13822efa2d85SJeremy L Thompson CeedVector assembled_vec = NULL; 13832efa2d85SJeremy L Thompson CeedElemRestriction assembled_rstr = NULL; 1384480fae85SJeremy L Thompson 1385*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataIsSetup(op->qf_assembled, &qf_assembled_is_setup)); 1386480fae85SJeremy L Thompson if (qf_assembled_is_setup) { 1387d04bbc78SJeremy L Thompson bool update_needed; 1388d04bbc78SJeremy L Thompson 1389*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataGetObjects(op->qf_assembled, &assembled_vec, &assembled_rstr)); 1390*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataIsUpdateNeeded(op->qf_assembled, &update_needed)); 13918b919e6bSJeremy L Thompson if (update_needed) { 1392*2b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleQFunctionUpdate(op, assembled_vec, assembled_rstr, request)); 13938b919e6bSJeremy L Thompson } 139470a7ffb3SJeremy L Thompson } else { 1395*2b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleQFunction(op, &assembled_vec, &assembled_rstr, request)); 1396*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataSetObjects(op->qf_assembled, assembled_vec, assembled_rstr)); 139770a7ffb3SJeremy L Thompson } 1398*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, false)); 13992efa2d85SJeremy L Thompson 1400d04bbc78SJeremy L Thompson // Copy reference from internally held copy 140170a7ffb3SJeremy L Thompson *assembled = NULL; 140270a7ffb3SJeremy L Thompson *rstr = NULL; 1403*2b730f8bSJeremy L Thompson CeedCall(CeedVectorReferenceCopy(assembled_vec, assembled)); 1404*2b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&assembled_vec)); 1405*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionReferenceCopy(assembled_rstr, rstr)); 1406*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&assembled_rstr)); 140770a7ffb3SJeremy L Thompson } else { 1408d04bbc78SJeremy L Thompson // Operator fallback 1409d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1410d04bbc78SJeremy L Thompson 1411*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1412d04bbc78SJeremy L Thompson if (op_fallback) { 1413*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op_fallback, assembled, rstr, request)); 1414d04bbc78SJeremy L Thompson } else { 1415d04bbc78SJeremy L Thompson // LCOV_EXCL_START 1416*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedOperatorLinearAssembleQFunctionUpdate"); 1417d04bbc78SJeremy L Thompson // LCOV_EXCL_STOP 141870a7ffb3SJeremy L Thompson } 141970a7ffb3SJeremy L Thompson } 142070a7ffb3SJeremy L Thompson 142170a7ffb3SJeremy L Thompson return CEED_ERROR_SUCCESS; 1422eaf62fffSJeremy L Thompson } 1423eaf62fffSJeremy L Thompson 1424eaf62fffSJeremy L Thompson /** 1425eaf62fffSJeremy L Thompson @brief Assemble the diagonal of a square linear CeedOperator 1426eaf62fffSJeremy L Thompson 1427eaf62fffSJeremy L Thompson This overwrites a CeedVector with the diagonal of a linear CeedOperator. 1428eaf62fffSJeremy L Thompson 1429eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1430eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1431eaf62fffSJeremy L Thompson 1432f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1433f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1434f04ea552SJeremy L Thompson 1435eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1436eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator diagonal 1437eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1438eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1439eaf62fffSJeremy L Thompson 1440eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1441eaf62fffSJeremy L Thompson 1442eaf62fffSJeremy L Thompson @ref User 1443eaf62fffSJeremy L Thompson **/ 1444*2b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled, CeedRequest *request) { 1445*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1446eaf62fffSJeremy L Thompson 1447c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 1448*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 1449*2b730f8bSJeremy L Thompson if (input_size != output_size) { 1450c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1451c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1452c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 1453*2b730f8bSJeremy L Thompson } 1454c9366a6bSJeremy L Thompson 1455eaf62fffSJeremy L Thompson if (op->LinearAssembleDiagonal) { 1456d04bbc78SJeremy L Thompson // Backend version 1457*2b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleDiagonal(op, assembled, request)); 1458eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1459eaf62fffSJeremy L Thompson } else if (op->LinearAssembleAddDiagonal) { 1460d04bbc78SJeremy L Thompson // Backend version with zeroing first 1461*2b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(assembled, 0.0)); 1462*2b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleAddDiagonal(op, assembled, request)); 1463eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1464eaf62fffSJeremy L Thompson } else { 1465d04bbc78SJeremy L Thompson // Operator fallback 1466d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1467d04bbc78SJeremy L Thompson 1468*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1469d04bbc78SJeremy L Thompson if (op_fallback) { 1470*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleDiagonal(op_fallback, assembled, request)); 1471eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1472eaf62fffSJeremy L Thompson } 1473eaf62fffSJeremy L Thompson } 1474eaf62fffSJeremy L Thompson // Default interface implementation 1475*2b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(assembled, 0.0)); 1476*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddDiagonal(op, assembled, request)); 1477d04bbc78SJeremy L Thompson 1478eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1479eaf62fffSJeremy L Thompson } 1480eaf62fffSJeremy L Thompson 1481eaf62fffSJeremy L Thompson /** 1482eaf62fffSJeremy L Thompson @brief Assemble the diagonal of a square linear CeedOperator 1483eaf62fffSJeremy L Thompson 1484eaf62fffSJeremy L Thompson This sums into a CeedVector the diagonal of a linear CeedOperator. 1485eaf62fffSJeremy L Thompson 1486eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1487eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1488eaf62fffSJeremy L Thompson 1489f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1490f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1491f04ea552SJeremy L Thompson 1492eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1493eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator diagonal 1494eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1495eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1496eaf62fffSJeremy L Thompson 1497eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1498eaf62fffSJeremy L Thompson 1499eaf62fffSJeremy L Thompson @ref User 1500eaf62fffSJeremy L Thompson **/ 1501*2b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled, CeedRequest *request) { 1502*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1503eaf62fffSJeremy L Thompson 1504c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 1505*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 1506*2b730f8bSJeremy L Thompson if (input_size != output_size) { 1507c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1508c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1509c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 1510*2b730f8bSJeremy L Thompson } 1511c9366a6bSJeremy L Thompson 1512eaf62fffSJeremy L Thompson if (op->LinearAssembleAddDiagonal) { 1513d04bbc78SJeremy L Thompson // Backend version 1514*2b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleAddDiagonal(op, assembled, request)); 1515eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1516eaf62fffSJeremy L Thompson } else { 1517d04bbc78SJeremy L Thompson // Operator fallback 1518d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1519d04bbc78SJeremy L Thompson 1520*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1521d04bbc78SJeremy L Thompson if (op_fallback) { 1522*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddDiagonal(op_fallback, assembled, request)); 1523eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1524eaf62fffSJeremy L Thompson } 1525eaf62fffSJeremy L Thompson } 1526eaf62fffSJeremy L Thompson // Default interface implementation 1527eaf62fffSJeremy L Thompson bool is_composite; 1528*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1529eaf62fffSJeremy L Thompson if (is_composite) { 1530*2b730f8bSJeremy L Thompson CeedCall(CeedCompositeOperatorLinearAssembleAddDiagonal(op, request, false, assembled)); 1531eaf62fffSJeremy L Thompson } else { 1532*2b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssembleAddDiagonal_Core(op, request, false, assembled)); 1533eaf62fffSJeremy L Thompson } 1534d04bbc78SJeremy L Thompson 1535d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 1536eaf62fffSJeremy L Thompson } 1537eaf62fffSJeremy L Thompson 1538eaf62fffSJeremy L Thompson /** 1539eaf62fffSJeremy L Thompson @brief Assemble the point block diagonal of a square linear CeedOperator 1540eaf62fffSJeremy L Thompson 1541eaf62fffSJeremy L Thompson This overwrites a CeedVector with the point block diagonal of a linear 1542eaf62fffSJeremy L Thompson CeedOperator. 1543eaf62fffSJeremy L Thompson 1544eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1545eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1546eaf62fffSJeremy L Thompson 1547f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1548f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1549f04ea552SJeremy L Thompson 1550eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1551eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator point block 1552eaf62fffSJeremy L Thompson diagonal, provided in row-major form with an 1553eaf62fffSJeremy L Thompson @a num_comp * @a num_comp block at each node. The dimensions 1554eaf62fffSJeremy L Thompson of this vector are derived from the active vector 1555eaf62fffSJeremy L Thompson for the CeedOperator. The array has shape 1556eaf62fffSJeremy L Thompson [nodes, component out, component in]. 1557eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1558eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 1559eaf62fffSJeremy L Thompson 1560eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1561eaf62fffSJeremy L Thompson 1562eaf62fffSJeremy L Thompson @ref User 1563eaf62fffSJeremy L Thompson **/ 1564*2b730f8bSJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op, CeedVector assembled, CeedRequest *request) { 1565*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1566eaf62fffSJeremy L Thompson 1567c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 1568*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 1569*2b730f8bSJeremy L Thompson if (input_size != output_size) { 1570c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1571c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1572c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 1573*2b730f8bSJeremy L Thompson } 1574c9366a6bSJeremy L Thompson 1575eaf62fffSJeremy L Thompson if (op->LinearAssemblePointBlockDiagonal) { 1576d04bbc78SJeremy L Thompson // Backend version 1577*2b730f8bSJeremy L Thompson CeedCall(op->LinearAssemblePointBlockDiagonal(op, assembled, request)); 1578eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1579eaf62fffSJeremy L Thompson } else if (op->LinearAssembleAddPointBlockDiagonal) { 1580d04bbc78SJeremy L Thompson // Backend version with zeroing first 1581*2b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(assembled, 0.0)); 1582*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, request)); 1583eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1584eaf62fffSJeremy L Thompson } else { 1585d04bbc78SJeremy L Thompson // Operator fallback 1586d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1587d04bbc78SJeremy L Thompson 1588*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1589d04bbc78SJeremy L Thompson if (op_fallback) { 1590*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssemblePointBlockDiagonal(op_fallback, assembled, request)); 1591eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1592eaf62fffSJeremy L Thompson } 1593eaf62fffSJeremy L Thompson } 1594eaf62fffSJeremy L Thompson // Default interface implementation 1595*2b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(assembled, 0.0)); 1596*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, request)); 1597d04bbc78SJeremy L Thompson 1598eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1599eaf62fffSJeremy L Thompson } 1600eaf62fffSJeremy L Thompson 1601eaf62fffSJeremy L Thompson /** 1602eaf62fffSJeremy L Thompson @brief Assemble the point block diagonal of a square linear CeedOperator 1603eaf62fffSJeremy L Thompson 1604eaf62fffSJeremy L Thompson This sums into a CeedVector with the point block diagonal of a linear 1605eaf62fffSJeremy L Thompson CeedOperator. 1606eaf62fffSJeremy L Thompson 1607eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1608eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1609eaf62fffSJeremy L Thompson 1610f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1611f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1612f04ea552SJeremy L Thompson 1613eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1614eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator point block 1615eaf62fffSJeremy L Thompson diagonal, provided in row-major form with an 1616eaf62fffSJeremy L Thompson @a num_comp * @a num_comp block at each node. The dimensions 1617eaf62fffSJeremy L Thompson of this vector are derived from the active vector 1618eaf62fffSJeremy L Thompson for the CeedOperator. The array has shape 1619eaf62fffSJeremy L Thompson [nodes, component out, component in]. 1620eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1621eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 1622eaf62fffSJeremy L Thompson 1623eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1624eaf62fffSJeremy L Thompson 1625eaf62fffSJeremy L Thompson @ref User 1626eaf62fffSJeremy L Thompson **/ 1627*2b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op, CeedVector assembled, CeedRequest *request) { 1628*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1629eaf62fffSJeremy L Thompson 1630c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 1631*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 1632*2b730f8bSJeremy L Thompson if (input_size != output_size) { 1633c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1634c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1635c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 1636*2b730f8bSJeremy L Thompson } 1637c9366a6bSJeremy L Thompson 1638eaf62fffSJeremy L Thompson if (op->LinearAssembleAddPointBlockDiagonal) { 1639d04bbc78SJeremy L Thompson // Backend version 1640*2b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleAddPointBlockDiagonal(op, assembled, request)); 1641eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1642eaf62fffSJeremy L Thompson } else { 1643d04bbc78SJeremy L Thompson // Operator fallback 1644d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1645d04bbc78SJeremy L Thompson 1646*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1647d04bbc78SJeremy L Thompson if (op_fallback) { 1648*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleAddPointBlockDiagonal(op_fallback, assembled, request)); 1649eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1650eaf62fffSJeremy L Thompson } 1651eaf62fffSJeremy L Thompson } 1652eaf62fffSJeremy L Thompson // Default interface implemenation 1653eaf62fffSJeremy L Thompson bool is_composite; 1654*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1655eaf62fffSJeremy L Thompson if (is_composite) { 1656*2b730f8bSJeremy L Thompson CeedCall(CeedCompositeOperatorLinearAssembleAddDiagonal(op, request, true, assembled)); 1657eaf62fffSJeremy L Thompson } else { 1658*2b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssembleAddDiagonal_Core(op, request, true, assembled)); 1659eaf62fffSJeremy L Thompson } 1660d04bbc78SJeremy L Thompson 1661d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 1662eaf62fffSJeremy L Thompson } 1663eaf62fffSJeremy L Thompson 1664eaf62fffSJeremy L Thompson /** 1665eaf62fffSJeremy L Thompson @brief Fully assemble the nonzero pattern of a linear operator. 1666eaf62fffSJeremy L Thompson 1667eaf62fffSJeremy L Thompson Expected to be used in conjunction with CeedOperatorLinearAssemble() 1668eaf62fffSJeremy L Thompson 1669eaf62fffSJeremy L Thompson The assembly routines use coordinate format, with num_entries tuples of the 1670eaf62fffSJeremy L Thompson form (i, j, value) which indicate that value should be added to the matrix 1671eaf62fffSJeremy L Thompson in entry (i, j). Note that the (i, j) pairs are not unique and may repeat. 1672eaf62fffSJeremy L Thompson This function returns the number of entries and their (i, j) locations, 1673eaf62fffSJeremy L Thompson while CeedOperatorLinearAssemble() provides the values in the same 1674eaf62fffSJeremy L Thompson ordering. 1675eaf62fffSJeremy L Thompson 1676eaf62fffSJeremy L Thompson This will generally be slow unless your operator is low-order. 1677eaf62fffSJeremy L Thompson 1678f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1679f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1680f04ea552SJeremy L Thompson 1681eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 1682eaf62fffSJeremy L Thompson @param[out] num_entries Number of entries in coordinate nonzero pattern 1683eaf62fffSJeremy L Thompson @param[out] rows Row number for each entry 1684eaf62fffSJeremy L Thompson @param[out] cols Column number for each entry 1685eaf62fffSJeremy L Thompson 1686eaf62fffSJeremy L Thompson @ref User 1687eaf62fffSJeremy L Thompson **/ 1688*2b730f8bSJeremy L Thompson int CeedOperatorLinearAssembleSymbolic(CeedOperator op, CeedSize *num_entries, CeedInt **rows, CeedInt **cols) { 1689eaf62fffSJeremy L Thompson CeedInt num_suboperators, single_entries; 1690eaf62fffSJeremy L Thompson CeedOperator *sub_operators; 1691eaf62fffSJeremy L Thompson bool is_composite; 1692*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1693eaf62fffSJeremy L Thompson 1694eaf62fffSJeremy L Thompson if (op->LinearAssembleSymbolic) { 1695d04bbc78SJeremy L Thompson // Backend version 1696*2b730f8bSJeremy L Thompson CeedCall(op->LinearAssembleSymbolic(op, num_entries, rows, cols)); 1697eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1698eaf62fffSJeremy L Thompson } else { 1699d04bbc78SJeremy L Thompson // Operator fallback 1700d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1701d04bbc78SJeremy L Thompson 1702*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1703d04bbc78SJeremy L Thompson if (op_fallback) { 1704*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleSymbolic(op_fallback, num_entries, rows, cols)); 1705eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1706eaf62fffSJeremy L Thompson } 1707eaf62fffSJeremy L Thompson } 1708eaf62fffSJeremy L Thompson 1709eaf62fffSJeremy L Thompson // Default interface implementation 1710eaf62fffSJeremy L Thompson 1711eaf62fffSJeremy L Thompson // count entries and allocate rows, cols arrays 1712*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1713eaf62fffSJeremy L Thompson *num_entries = 0; 1714eaf62fffSJeremy L Thompson if (is_composite) { 1715*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetNumSub(op, &num_suboperators)); 1716*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetSubList(op, &sub_operators)); 171792ae7e47SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; ++k) { 1718*2b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemblyCountEntries(sub_operators[k], &single_entries)); 1719eaf62fffSJeremy L Thompson *num_entries += single_entries; 1720eaf62fffSJeremy L Thompson } 1721eaf62fffSJeremy L Thompson } else { 1722*2b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemblyCountEntries(op, &single_entries)); 1723eaf62fffSJeremy L Thompson *num_entries += single_entries; 1724eaf62fffSJeremy L Thompson } 1725*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(*num_entries, rows)); 1726*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(*num_entries, cols)); 1727eaf62fffSJeremy L Thompson 1728eaf62fffSJeremy L Thompson // assemble nonzero locations 1729eaf62fffSJeremy L Thompson CeedInt offset = 0; 1730eaf62fffSJeremy L Thompson if (is_composite) { 1731*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetNumSub(op, &num_suboperators)); 1732*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetSubList(op, &sub_operators)); 173392ae7e47SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; ++k) { 1734*2b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssembleSymbolic(sub_operators[k], offset, *rows, *cols)); 1735*2b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemblyCountEntries(sub_operators[k], &single_entries)); 1736eaf62fffSJeremy L Thompson offset += single_entries; 1737eaf62fffSJeremy L Thompson } 1738eaf62fffSJeremy L Thompson } else { 1739*2b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssembleSymbolic(op, offset, *rows, *cols)); 1740eaf62fffSJeremy L Thompson } 1741eaf62fffSJeremy L Thompson 1742eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1743eaf62fffSJeremy L Thompson } 1744eaf62fffSJeremy L Thompson 1745eaf62fffSJeremy L Thompson /** 1746eaf62fffSJeremy L Thompson @brief Fully assemble the nonzero entries of a linear operator. 1747eaf62fffSJeremy L Thompson 1748eaf62fffSJeremy L Thompson Expected to be used in conjunction with CeedOperatorLinearAssembleSymbolic() 1749eaf62fffSJeremy L Thompson 1750eaf62fffSJeremy L Thompson The assembly routines use coordinate format, with num_entries tuples of the 1751eaf62fffSJeremy L Thompson form (i, j, value) which indicate that value should be added to the matrix 1752eaf62fffSJeremy L Thompson in entry (i, j). Note that the (i, j) pairs are not unique and may repeat. 1753eaf62fffSJeremy L Thompson This function returns the values of the nonzero entries to be added, their 1754eaf62fffSJeremy L Thompson (i, j) locations are provided by CeedOperatorLinearAssembleSymbolic() 1755eaf62fffSJeremy L Thompson 1756eaf62fffSJeremy L Thompson This will generally be slow unless your operator is low-order. 1757eaf62fffSJeremy L Thompson 1758f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1759f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1760f04ea552SJeremy L Thompson 1761eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 1762eaf62fffSJeremy L Thompson @param[out] values Values to assemble into matrix 1763eaf62fffSJeremy L Thompson 1764eaf62fffSJeremy L Thompson @ref User 1765eaf62fffSJeremy L Thompson **/ 1766eaf62fffSJeremy L Thompson int CeedOperatorLinearAssemble(CeedOperator op, CeedVector values) { 1767eaf62fffSJeremy L Thompson CeedInt num_suboperators, single_entries = 0; 1768eaf62fffSJeremy L Thompson CeedOperator *sub_operators; 1769*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1770eaf62fffSJeremy L Thompson 1771eaf62fffSJeremy L Thompson if (op->LinearAssemble) { 1772d04bbc78SJeremy L Thompson // Backend version 1773*2b730f8bSJeremy L Thompson CeedCall(op->LinearAssemble(op, values)); 1774eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1775eaf62fffSJeremy L Thompson } else { 1776d04bbc78SJeremy L Thompson // Operator fallback 1777d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1778d04bbc78SJeremy L Thompson 1779*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 1780d04bbc78SJeremy L Thompson if (op_fallback) { 1781*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssemble(op_fallback, values)); 1782eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1783eaf62fffSJeremy L Thompson } 1784eaf62fffSJeremy L Thompson } 1785eaf62fffSJeremy L Thompson 1786eaf62fffSJeremy L Thompson // Default interface implementation 1787eaf62fffSJeremy L Thompson bool is_composite; 1788*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1789eaf62fffSJeremy L Thompson 1790eaf62fffSJeremy L Thompson CeedInt offset = 0; 1791eaf62fffSJeremy L Thompson if (is_composite) { 1792*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetNumSub(op, &num_suboperators)); 1793*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetSubList(op, &sub_operators)); 1794cefa2673SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; k++) { 1795*2b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemble(sub_operators[k], offset, values)); 1796*2b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemblyCountEntries(sub_operators[k], &single_entries)); 1797eaf62fffSJeremy L Thompson offset += single_entries; 1798eaf62fffSJeremy L Thompson } 1799eaf62fffSJeremy L Thompson } else { 1800*2b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorAssemble(op, offset, values)); 1801eaf62fffSJeremy L Thompson } 1802eaf62fffSJeremy L Thompson 1803eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1804eaf62fffSJeremy L Thompson } 1805eaf62fffSJeremy L Thompson 1806eaf62fffSJeremy L Thompson /** 1807eaf62fffSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators 1808eaf62fffSJeremy L Thompson for a CeedOperator, creating the prolongation basis from the 1809eaf62fffSJeremy L Thompson fine and coarse grid interpolation 1810eaf62fffSJeremy L Thompson 1811f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1812f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1813f04ea552SJeremy L Thompson 1814eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 1815eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 1816eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 1817eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 1818eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 1819eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 1820eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 1821eaf62fffSJeremy L Thompson 1822eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1823eaf62fffSJeremy L Thompson 1824eaf62fffSJeremy L Thompson @ref User 1825eaf62fffSJeremy L Thompson **/ 1826*2b730f8bSJeremy L Thompson int CeedOperatorMultigridLevelCreate(CeedOperator op_fine, CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 1827*2b730f8bSJeremy L Thompson CeedOperator *op_coarse, CeedOperator *op_prolong, CeedOperator *op_restrict) { 1828*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op_fine)); 1829eaf62fffSJeremy L Thompson 1830f113e5dcSJeremy L Thompson // Build prolongation matrix 1831f113e5dcSJeremy L Thompson CeedBasis basis_fine, basis_c_to_f; 1832*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveBasis(op_fine, &basis_fine)); 1833*2b730f8bSJeremy L Thompson CeedCall(CeedBasisCreateProjection(basis_coarse, basis_fine, &basis_c_to_f)); 1834eaf62fffSJeremy L Thompson 1835f113e5dcSJeremy L Thompson // Core code 1836*2b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, basis_coarse, basis_c_to_f, op_coarse, op_prolong, op_restrict)); 1837f113e5dcSJeremy L Thompson 1838eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1839eaf62fffSJeremy L Thompson } 1840eaf62fffSJeremy L Thompson 1841eaf62fffSJeremy L Thompson /** 1842eaf62fffSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators 1843eaf62fffSJeremy L Thompson for a CeedOperator with a tensor basis for the active basis 1844eaf62fffSJeremy L Thompson 1845f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1846f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1847f04ea552SJeremy L Thompson 1848eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 1849eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 1850eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 1851eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 1852eaf62fffSJeremy L Thompson @param[in] interp_c_to_f Matrix for coarse to fine interpolation 1853eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 1854eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 1855eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 1856eaf62fffSJeremy L Thompson 1857eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1858eaf62fffSJeremy L Thompson 1859eaf62fffSJeremy L Thompson @ref User 1860eaf62fffSJeremy L Thompson **/ 1861*2b730f8bSJeremy L Thompson int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator op_fine, CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 1862*2b730f8bSJeremy L Thompson const CeedScalar *interp_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong, 1863*2b730f8bSJeremy L Thompson CeedOperator *op_restrict) { 1864*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op_fine)); 1865eaf62fffSJeremy L Thompson Ceed ceed; 1866*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op_fine, &ceed)); 1867eaf62fffSJeremy L Thompson 1868eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 1869eaf62fffSJeremy L Thompson CeedBasis basis_fine; 1870*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveBasis(op_fine, &basis_fine)); 1871eaf62fffSJeremy L Thompson CeedInt Q_f, Q_c; 1872*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f)); 1873*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c)); 1874*2b730f8bSJeremy L Thompson if (Q_f != Q_c) { 1875eaf62fffSJeremy L Thompson // LCOV_EXCL_START 1876*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, "Bases must have compatible quadrature spaces"); 1877eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 1878*2b730f8bSJeremy L Thompson } 1879eaf62fffSJeremy L Thompson 1880eaf62fffSJeremy L Thompson // Coarse to fine basis 1881eaf62fffSJeremy L Thompson CeedInt dim, num_comp, num_nodes_c, P_1d_f, P_1d_c; 1882*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetDimension(basis_fine, &dim)); 1883*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumComponents(basis_fine, &num_comp)); 1884*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumNodes1D(basis_fine, &P_1d_f)); 1885*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c)); 1886*2b730f8bSJeremy L Thompson P_1d_c = dim == 1 ? num_nodes_c : dim == 2 ? sqrt(num_nodes_c) : cbrt(num_nodes_c); 1887eaf62fffSJeremy L Thompson CeedScalar *q_ref, *q_weight, *grad; 1888*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d_f, &q_ref)); 1889*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d_f, &q_weight)); 1890*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d_f * P_1d_c * dim, &grad)); 1891eaf62fffSJeremy L Thompson CeedBasis basis_c_to_f; 1892*2b730f8bSJeremy 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)); 1893*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_ref)); 1894*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_weight)); 1895*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&grad)); 1896eaf62fffSJeremy L Thompson 1897eaf62fffSJeremy L Thompson // Core code 1898*2b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, basis_coarse, basis_c_to_f, op_coarse, op_prolong, op_restrict)); 1899eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1900eaf62fffSJeremy L Thompson } 1901eaf62fffSJeremy L Thompson 1902eaf62fffSJeremy L Thompson /** 1903eaf62fffSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators 1904eaf62fffSJeremy L Thompson for a CeedOperator with a non-tensor basis for the active vector 1905eaf62fffSJeremy L Thompson 1906f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1907f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1908f04ea552SJeremy L Thompson 1909eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 1910eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 1911eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 1912eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 1913eaf62fffSJeremy L Thompson @param[in] interp_c_to_f Matrix for coarse to fine interpolation 1914eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 1915eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 1916eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 1917eaf62fffSJeremy L Thompson 1918eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1919eaf62fffSJeremy L Thompson 1920eaf62fffSJeremy L Thompson @ref User 1921eaf62fffSJeremy L Thompson **/ 1922*2b730f8bSJeremy L Thompson int CeedOperatorMultigridLevelCreateH1(CeedOperator op_fine, CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 1923*2b730f8bSJeremy L Thompson const CeedScalar *interp_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong, 1924eaf62fffSJeremy L Thompson CeedOperator *op_restrict) { 1925*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op_fine)); 1926eaf62fffSJeremy L Thompson Ceed ceed; 1927*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op_fine, &ceed)); 1928eaf62fffSJeremy L Thompson 1929eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 1930eaf62fffSJeremy L Thompson CeedBasis basis_fine; 1931*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveBasis(op_fine, &basis_fine)); 1932eaf62fffSJeremy L Thompson CeedInt Q_f, Q_c; 1933*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f)); 1934*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c)); 1935*2b730f8bSJeremy L Thompson if (Q_f != Q_c) { 1936eaf62fffSJeremy L Thompson // LCOV_EXCL_START 1937*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, "Bases must have compatible quadrature spaces"); 1938eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 1939*2b730f8bSJeremy L Thompson } 1940eaf62fffSJeremy L Thompson 1941eaf62fffSJeremy L Thompson // Coarse to fine basis 1942eaf62fffSJeremy L Thompson CeedElemTopology topo; 1943*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetTopology(basis_fine, &topo)); 1944eaf62fffSJeremy L Thompson CeedInt dim, num_comp, num_nodes_c, num_nodes_f; 1945*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetDimension(basis_fine, &dim)); 1946*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumComponents(basis_fine, &num_comp)); 1947*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumNodes(basis_fine, &num_nodes_f)); 1948*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c)); 1949eaf62fffSJeremy L Thompson CeedScalar *q_ref, *q_weight, *grad; 1950*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_nodes_f * dim, &q_ref)); 1951*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_nodes_f, &q_weight)); 1952*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_nodes_f * num_nodes_c * dim, &grad)); 1953eaf62fffSJeremy L Thompson CeedBasis basis_c_to_f; 1954*2b730f8bSJeremy 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)); 1955*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_ref)); 1956*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_weight)); 1957*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&grad)); 1958eaf62fffSJeremy L Thompson 1959eaf62fffSJeremy L Thompson // Core code 1960*2b730f8bSJeremy L Thompson CeedCall(CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, basis_coarse, basis_c_to_f, op_coarse, op_prolong, op_restrict)); 1961eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1962eaf62fffSJeremy L Thompson } 1963eaf62fffSJeremy L Thompson 1964eaf62fffSJeremy L Thompson /** 1965eaf62fffSJeremy L Thompson @brief Build a FDM based approximate inverse for each element for a 1966eaf62fffSJeremy L Thompson CeedOperator 1967eaf62fffSJeremy L Thompson 1968eaf62fffSJeremy L Thompson This returns a CeedOperator and CeedVector to apply a Fast Diagonalization 1969eaf62fffSJeremy L Thompson Method based approximate inverse. This function obtains the simultaneous 1970eaf62fffSJeremy L Thompson diagonalization for the 1D mass and Laplacian operators, 1971eaf62fffSJeremy L Thompson M = V^T V, K = V^T S V. 1972eaf62fffSJeremy L Thompson The assembled QFunction is used to modify the eigenvalues from simultaneous 1973eaf62fffSJeremy L Thompson diagonalization and obtain an approximate inverse of the form 1974eaf62fffSJeremy L Thompson V^T S^hat V. The CeedOperator must be linear and non-composite. The 1975eaf62fffSJeremy L Thompson associated CeedQFunction must therefore also be linear. 1976eaf62fffSJeremy L Thompson 1977f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1978f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1979f04ea552SJeremy L Thompson 1980eaf62fffSJeremy L Thompson @param op CeedOperator to create element inverses 1981eaf62fffSJeremy L Thompson @param[out] fdm_inv CeedOperator to apply the action of a FDM based inverse 1982eaf62fffSJeremy L Thompson for each element 1983eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1984eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1985eaf62fffSJeremy L Thompson 1986eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1987eaf62fffSJeremy L Thompson 1988480fae85SJeremy L Thompson @ref User 1989eaf62fffSJeremy L Thompson **/ 1990*2b730f8bSJeremy L Thompson int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdm_inv, CeedRequest *request) { 1991*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1992eaf62fffSJeremy L Thompson 1993eaf62fffSJeremy L Thompson if (op->CreateFDMElementInverse) { 1994d04bbc78SJeremy L Thompson // Backend version 1995*2b730f8bSJeremy L Thompson CeedCall(op->CreateFDMElementInverse(op, fdm_inv, request)); 1996eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1997eaf62fffSJeremy L Thompson } else { 1998d04bbc78SJeremy L Thompson // Operator fallback 1999d04bbc78SJeremy L Thompson CeedOperator op_fallback; 2000d04bbc78SJeremy L Thompson 2001*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFallback(op, &op_fallback)); 2002d04bbc78SJeremy L Thompson if (op_fallback) { 2003*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreateFDMElementInverse(op_fallback, fdm_inv, request)); 2004eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2005eaf62fffSJeremy L Thompson } 2006eaf62fffSJeremy L Thompson } 2007eaf62fffSJeremy L Thompson 2008d04bbc78SJeremy L Thompson // Default interface implementation 2009eaf62fffSJeremy L Thompson Ceed ceed, ceed_parent; 2010*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 2011*2b730f8bSJeremy L Thompson CeedCall(CeedGetOperatorFallbackParentCeed(ceed, &ceed_parent)); 2012eaf62fffSJeremy L Thompson ceed_parent = ceed_parent ? ceed_parent : ceed; 2013eaf62fffSJeremy L Thompson CeedQFunction qf; 2014*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetQFunction(op, &qf)); 2015eaf62fffSJeremy L Thompson 2016eaf62fffSJeremy L Thompson // Determine active input basis 2017eaf62fffSJeremy L Thompson bool interp = false, grad = false; 2018eaf62fffSJeremy L Thompson CeedBasis basis = NULL; 2019eaf62fffSJeremy L Thompson CeedElemRestriction rstr = NULL; 2020eaf62fffSJeremy L Thompson CeedOperatorField *op_fields; 2021eaf62fffSJeremy L Thompson CeedQFunctionField *qf_fields; 2022eaf62fffSJeremy L Thompson CeedInt num_input_fields; 2023*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_fields, NULL, NULL)); 2024*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL)); 2025eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_input_fields; i++) { 2026eaf62fffSJeremy L Thompson CeedVector vec; 2027*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetVector(op_fields[i], &vec)); 2028eaf62fffSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 2029eaf62fffSJeremy L Thompson CeedEvalMode eval_mode; 2030*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode)); 2031eaf62fffSJeremy L Thompson interp = interp || eval_mode == CEED_EVAL_INTERP; 2032eaf62fffSJeremy L Thompson grad = grad || eval_mode == CEED_EVAL_GRAD; 2033*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetBasis(op_fields[i], &basis)); 2034*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr)); 2035eaf62fffSJeremy L Thompson } 2036eaf62fffSJeremy L Thompson } 2037*2b730f8bSJeremy L Thompson if (!basis) { 2038eaf62fffSJeremy L Thompson // LCOV_EXCL_START 2039eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "No active field set"); 2040eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 2041*2b730f8bSJeremy L Thompson } 2042e79b91d9SJeremy L Thompson CeedSize l_size = 1; 2043e79b91d9SJeremy L Thompson CeedInt P_1d, Q_1d, elem_size, num_qpts, dim, num_comp = 1, num_elem = 1; 2044*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumNodes1D(basis, &P_1d)); 2045*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumNodes(basis, &elem_size)); 2046*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d)); 2047*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(basis, &num_qpts)); 2048*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetDimension(basis, &dim)); 2049*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumComponents(basis, &num_comp)); 2050*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 2051*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size)); 2052eaf62fffSJeremy L Thompson 2053eaf62fffSJeremy L Thompson // Build and diagonalize 1D Mass and Laplacian 2054eaf62fffSJeremy L Thompson bool tensor_basis; 2055*2b730f8bSJeremy L Thompson CeedCall(CeedBasisIsTensor(basis, &tensor_basis)); 2056*2b730f8bSJeremy L Thompson if (!tensor_basis) { 2057eaf62fffSJeremy L Thompson // LCOV_EXCL_START 2058*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "FDMElementInverse only supported for tensor bases"); 2059eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 2060*2b730f8bSJeremy L Thompson } 2061eaf62fffSJeremy L Thompson CeedScalar *mass, *laplace, *x, *fdm_interp, *lambda; 2062*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &mass)); 2063*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &laplace)); 2064*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &x)); 2065*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &fdm_interp)); 2066*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d, &lambda)); 2067eaf62fffSJeremy L Thompson // -- Build matrices 2068eaf62fffSJeremy L Thompson const CeedScalar *interp_1d, *grad_1d, *q_weight_1d; 2069*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetInterp1D(basis, &interp_1d)); 2070*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetGrad1D(basis, &grad_1d)); 2071*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetQWeights(basis, &q_weight_1d)); 2072*2b730f8bSJeremy L Thompson CeedCall(CeedBuildMassLaplace(interp_1d, grad_1d, q_weight_1d, P_1d, Q_1d, dim, mass, laplace)); 2073eaf62fffSJeremy L Thompson 2074eaf62fffSJeremy L Thompson // -- Diagonalize 2075*2b730f8bSJeremy L Thompson CeedCall(CeedSimultaneousDiagonalization(ceed, laplace, mass, x, lambda, P_1d)); 2076*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&mass)); 2077*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&laplace)); 2078*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < P_1d; i++) { 2079*2b730f8bSJeremy L Thompson for (CeedInt j = 0; j < P_1d; j++) fdm_interp[i + j * P_1d] = x[j + i * P_1d]; 2080*2b730f8bSJeremy L Thompson } 2081*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&x)); 2082eaf62fffSJeremy L Thompson 2083eaf62fffSJeremy L Thompson // Assemble QFunction 2084eaf62fffSJeremy L Thompson CeedVector assembled; 2085eaf62fffSJeremy L Thompson CeedElemRestriction rstr_qf; 2086*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled, &rstr_qf, request)); 2087eaf62fffSJeremy L Thompson CeedInt layout[3]; 2088*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetELayout(rstr_qf, &layout)); 2089*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&rstr_qf)); 2090eaf62fffSJeremy L Thompson CeedScalar max_norm = 0; 2091*2b730f8bSJeremy L Thompson CeedCall(CeedVectorNorm(assembled, CEED_NORM_MAX, &max_norm)); 2092eaf62fffSJeremy L Thompson 2093eaf62fffSJeremy L Thompson // Calculate element averages 2094eaf62fffSJeremy L Thompson CeedInt num_modes = (interp ? 1 : 0) + (grad ? dim : 0); 2095eaf62fffSJeremy L Thompson CeedScalar *elem_avg; 2096eaf62fffSJeremy L Thompson const CeedScalar *assembled_array, *q_weight_array; 2097eaf62fffSJeremy L Thompson CeedVector q_weight; 2098*2b730f8bSJeremy L Thompson CeedCall(CeedVectorCreate(ceed_parent, num_qpts, &q_weight)); 2099*2b730f8bSJeremy L Thompson CeedCall(CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, CEED_VECTOR_NONE, q_weight)); 2100*2b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembled_array)); 2101*2b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayRead(q_weight, CEED_MEM_HOST, &q_weight_array)); 2102*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_elem, &elem_avg)); 2103eaf62fffSJeremy L Thompson const CeedScalar qf_value_bound = max_norm * 100 * CEED_EPSILON; 2104eaf62fffSJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) { 2105eaf62fffSJeremy L Thompson CeedInt count = 0; 2106*2b730f8bSJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 2107*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < num_comp * num_comp * num_modes * num_modes; i++) { 2108*2b730f8bSJeremy L Thompson if (fabs(assembled_array[q * layout[0] + i * layout[1] + e * layout[2]]) > qf_value_bound) { 2109*2b730f8bSJeremy L Thompson elem_avg[e] += assembled_array[q * layout[0] + i * layout[1] + e * layout[2]] / q_weight_array[q]; 2110eaf62fffSJeremy L Thompson count++; 2111eaf62fffSJeremy L Thompson } 2112*2b730f8bSJeremy L Thompson } 2113*2b730f8bSJeremy L Thompson } 2114eaf62fffSJeremy L Thompson if (count) { 2115eaf62fffSJeremy L Thompson elem_avg[e] /= count; 2116eaf62fffSJeremy L Thompson } else { 2117eaf62fffSJeremy L Thompson elem_avg[e] = 1.0; 2118eaf62fffSJeremy L Thompson } 2119eaf62fffSJeremy L Thompson } 2120*2b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(assembled, &assembled_array)); 2121*2b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&assembled)); 2122*2b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArrayRead(q_weight, &q_weight_array)); 2123*2b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&q_weight)); 2124eaf62fffSJeremy L Thompson 2125eaf62fffSJeremy L Thompson // Build FDM diagonal 2126eaf62fffSJeremy L Thompson CeedVector q_data; 2127eaf62fffSJeremy L Thompson CeedScalar *q_data_array, *fdm_diagonal; 2128*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_comp * elem_size, &fdm_diagonal)); 2129eaf62fffSJeremy L Thompson const CeedScalar fdm_diagonal_bound = elem_size * CEED_EPSILON; 2130*2b730f8bSJeremy L Thompson for (CeedInt c = 0; c < num_comp; c++) { 2131eaf62fffSJeremy L Thompson for (CeedInt n = 0; n < elem_size; n++) { 2132*2b730f8bSJeremy L Thompson if (interp) fdm_diagonal[c * elem_size + n] = 1.0; 2133*2b730f8bSJeremy L Thompson if (grad) { 2134eaf62fffSJeremy L Thompson for (CeedInt d = 0; d < dim; d++) { 2135eaf62fffSJeremy L Thompson CeedInt i = (n / CeedIntPow(P_1d, d)) % P_1d; 2136eaf62fffSJeremy L Thompson fdm_diagonal[c * elem_size + n] += lambda[i]; 2137eaf62fffSJeremy L Thompson } 2138eaf62fffSJeremy L Thompson } 2139*2b730f8bSJeremy L Thompson if (fabs(fdm_diagonal[c * elem_size + n]) < fdm_diagonal_bound) fdm_diagonal[c * elem_size + n] = fdm_diagonal_bound; 2140*2b730f8bSJeremy L Thompson } 2141*2b730f8bSJeremy L Thompson } 2142*2b730f8bSJeremy L Thompson CeedCall(CeedVectorCreate(ceed_parent, num_elem * num_comp * elem_size, &q_data)); 2143*2b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(q_data, 0.0)); 2144*2b730f8bSJeremy L Thompson CeedCall(CeedVectorGetArrayWrite(q_data, CEED_MEM_HOST, &q_data_array)); 2145*2b730f8bSJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) { 2146*2b730f8bSJeremy L Thompson for (CeedInt c = 0; c < num_comp; c++) { 2147*2b730f8bSJeremy L Thompson for (CeedInt n = 0; n < elem_size; n++) q_data_array[(e * num_comp + c) * elem_size + n] = 1. / (elem_avg[e] * fdm_diagonal[c * elem_size + n]); 2148*2b730f8bSJeremy L Thompson } 2149*2b730f8bSJeremy L Thompson } 2150*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&elem_avg)); 2151*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&fdm_diagonal)); 2152*2b730f8bSJeremy L Thompson CeedCall(CeedVectorRestoreArray(q_data, &q_data_array)); 2153eaf62fffSJeremy L Thompson 2154eaf62fffSJeremy L Thompson // Setup FDM operator 2155eaf62fffSJeremy L Thompson // -- Basis 2156eaf62fffSJeremy L Thompson CeedBasis fdm_basis; 2157eaf62fffSJeremy L Thompson CeedScalar *grad_dummy, *q_ref_dummy, *q_weight_dummy; 2158*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d * P_1d, &grad_dummy)); 2159*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d, &q_ref_dummy)); 2160*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(P_1d, &q_weight_dummy)); 2161*2b730f8bSJeremy 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)); 2162*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&fdm_interp)); 2163*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&grad_dummy)); 2164*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_ref_dummy)); 2165*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&q_weight_dummy)); 2166*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&lambda)); 2167eaf62fffSJeremy L Thompson 2168eaf62fffSJeremy L Thompson // -- Restriction 2169eaf62fffSJeremy L Thompson CeedElemRestriction rstr_qd_i; 2170eaf62fffSJeremy L Thompson CeedInt strides[3] = {1, elem_size, elem_size * num_comp}; 2171*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionCreateStrided(ceed_parent, num_elem, elem_size, num_comp, num_elem * num_comp * elem_size, strides, &rstr_qd_i)); 2172eaf62fffSJeremy L Thompson // -- QFunction 2173eaf62fffSJeremy L Thompson CeedQFunction qf_fdm; 2174*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionCreateInteriorByName(ceed_parent, "Scale", &qf_fdm)); 2175*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_fdm, "input", num_comp, CEED_EVAL_INTERP)); 2176*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddInput(qf_fdm, "scale", num_comp, CEED_EVAL_NONE)); 2177*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAddOutput(qf_fdm, "output", num_comp, CEED_EVAL_INTERP)); 2178*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetUserFlopsEstimate(qf_fdm, num_comp)); 2179eaf62fffSJeremy L Thompson // -- QFunction context 2180eaf62fffSJeremy L Thompson CeedInt *num_comp_data; 2181*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, &num_comp_data)); 2182eaf62fffSJeremy L Thompson num_comp_data[0] = num_comp; 2183eaf62fffSJeremy L Thompson CeedQFunctionContext ctx_fdm; 2184*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextCreate(ceed, &ctx_fdm)); 2185*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextSetData(ctx_fdm, CEED_MEM_HOST, CEED_OWN_POINTER, sizeof(*num_comp_data), num_comp_data)); 2186*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionSetContext(qf_fdm, ctx_fdm)); 2187*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextDestroy(&ctx_fdm)); 2188eaf62fffSJeremy L Thompson // -- Operator 2189*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(ceed_parent, qf_fdm, NULL, NULL, fdm_inv)); 2190*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*fdm_inv, "input", rstr, fdm_basis, CEED_VECTOR_ACTIVE)); 2191*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*fdm_inv, "scale", rstr_qd_i, CEED_BASIS_COLLOCATED, q_data)); 2192*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetField(*fdm_inv, "output", rstr, fdm_basis, CEED_VECTOR_ACTIVE)); 2193eaf62fffSJeremy L Thompson 2194eaf62fffSJeremy L Thompson // Cleanup 2195*2b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&q_data)); 2196*2b730f8bSJeremy L Thompson CeedCall(CeedBasisDestroy(&fdm_basis)); 2197*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&rstr_qd_i)); 2198*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&qf_fdm)); 2199eaf62fffSJeremy L Thompson 2200eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2201eaf62fffSJeremy L Thompson } 2202eaf62fffSJeremy L Thompson 2203eaf62fffSJeremy L Thompson /// @} 2204