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 8eaf62fffSJeremy L Thompson #include <ceed/ceed.h> 9eaf62fffSJeremy L Thompson #include <ceed/backend.h> 10eaf62fffSJeremy L Thompson #include <ceed-impl.h> 11eaf62fffSJeremy L Thompson #include <math.h> 12eaf62fffSJeremy L Thompson #include <stdbool.h> 13eaf62fffSJeremy L Thompson #include <stdio.h> 14eaf62fffSJeremy L Thompson #include <string.h> 15eaf62fffSJeremy L Thompson 16eaf62fffSJeremy L Thompson /// @file 17eaf62fffSJeremy L Thompson /// Implementation of CeedOperator preconditioning interfaces 18eaf62fffSJeremy L Thompson 19eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 20eaf62fffSJeremy L Thompson /// CeedOperator Library Internal Preconditioning Functions 21eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 22eaf62fffSJeremy L Thompson /// @addtogroup CeedOperatorDeveloper 23eaf62fffSJeremy L Thompson /// @{ 24eaf62fffSJeremy L Thompson 25eaf62fffSJeremy L Thompson /** 269e77b9c8SJeremy L Thompson @brief Duplicate a CeedQFunction with a reference Ceed to fallback for advanced 279e77b9c8SJeremy L Thompson CeedOperator functionality 289e77b9c8SJeremy L Thompson 2901ea9c81SJed Brown @param[in] fallback_ceed Ceed on which to create fallback CeedQFunction 309e77b9c8SJeremy L Thompson @param[in] qf CeedQFunction to create fallback for 3101ea9c81SJed Brown @param[out] qf_fallback fallback CeedQFunction 329e77b9c8SJeremy L Thompson 339e77b9c8SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 349e77b9c8SJeremy L Thompson 359e77b9c8SJeremy L Thompson @ref Developer 369e77b9c8SJeremy L Thompson **/ 379e77b9c8SJeremy L Thompson static int CeedQFunctionCreateFallback(Ceed fallback_ceed, CeedQFunction qf, 389e77b9c8SJeremy L Thompson CeedQFunction *qf_fallback) { 399e77b9c8SJeremy L Thompson int ierr; 409e77b9c8SJeremy L Thompson 419e77b9c8SJeremy L Thompson // Check if NULL qf passed in 429e77b9c8SJeremy L Thompson if (!qf) return CEED_ERROR_SUCCESS; 439e77b9c8SJeremy L Thompson 44d04bbc78SJeremy L Thompson CeedDebug256(qf->ceed, 1, "---------- CeedOperator Fallback ----------\n"); 45d04bbc78SJeremy L Thompson CeedDebug256(qf->ceed, 255, "Creating fallback CeedQFunction\n"); 46d04bbc78SJeremy L Thompson 479e77b9c8SJeremy L Thompson char *source_path_with_name = ""; 489e77b9c8SJeremy L Thompson if (qf->source_path) { 499e77b9c8SJeremy L Thompson size_t path_len = strlen(qf->source_path), 509e77b9c8SJeremy L Thompson name_len = strlen(qf->kernel_name); 519e77b9c8SJeremy L Thompson ierr = CeedCalloc(path_len + name_len + 2, &source_path_with_name); 529e77b9c8SJeremy L Thompson CeedChk(ierr); 539e77b9c8SJeremy L Thompson memcpy(source_path_with_name, qf->source_path, path_len); 549e77b9c8SJeremy L Thompson memcpy(&source_path_with_name[path_len], ":", 1); 559e77b9c8SJeremy L Thompson memcpy(&source_path_with_name[path_len + 1], qf->kernel_name, name_len); 569e77b9c8SJeremy L Thompson } else { 579e77b9c8SJeremy L Thompson ierr = CeedCalloc(1, &source_path_with_name); CeedChk(ierr); 589e77b9c8SJeremy L Thompson } 599e77b9c8SJeremy L Thompson 609e77b9c8SJeremy L Thompson ierr = CeedQFunctionCreateInterior(fallback_ceed, qf->vec_length, 619e77b9c8SJeremy L Thompson qf->function, source_path_with_name, 629e77b9c8SJeremy L Thompson qf_fallback); CeedChk(ierr); 639e77b9c8SJeremy L Thompson { 649e77b9c8SJeremy L Thompson CeedQFunctionContext ctx; 659e77b9c8SJeremy L Thompson 669e77b9c8SJeremy L Thompson ierr = CeedQFunctionGetContext(qf, &ctx); CeedChk(ierr); 679e77b9c8SJeremy L Thompson ierr = CeedQFunctionSetContext(*qf_fallback, ctx); CeedChk(ierr); 689e77b9c8SJeremy L Thompson } 699e77b9c8SJeremy L Thompson for (CeedInt i = 0; i < qf->num_input_fields; i++) { 709e77b9c8SJeremy L Thompson ierr = CeedQFunctionAddInput(*qf_fallback, qf->input_fields[i]->field_name, 719e77b9c8SJeremy L Thompson qf->input_fields[i]->size, 729e77b9c8SJeremy L Thompson qf->input_fields[i]->eval_mode); CeedChk(ierr); 739e77b9c8SJeremy L Thompson } 749e77b9c8SJeremy L Thompson for (CeedInt i = 0; i < qf->num_output_fields; i++) { 759e77b9c8SJeremy L Thompson ierr = CeedQFunctionAddOutput(*qf_fallback, qf->output_fields[i]->field_name, 769e77b9c8SJeremy L Thompson qf->output_fields[i]->size, 779e77b9c8SJeremy L Thompson qf->output_fields[i]->eval_mode); CeedChk(ierr); 789e77b9c8SJeremy L Thompson } 799e77b9c8SJeremy L Thompson ierr = CeedFree(&source_path_with_name); CeedChk(ierr); 809e77b9c8SJeremy L Thompson 819e77b9c8SJeremy L Thompson return CEED_ERROR_SUCCESS; 829e77b9c8SJeremy L Thompson } 839e77b9c8SJeremy L Thompson 849e77b9c8SJeremy L Thompson /** 85eaf62fffSJeremy L Thompson @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced 86eaf62fffSJeremy L Thompson CeedOperator functionality 87eaf62fffSJeremy L Thompson 88eaf62fffSJeremy L Thompson @param op CeedOperator to create fallback for 89eaf62fffSJeremy L Thompson 90eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 91eaf62fffSJeremy L Thompson 92eaf62fffSJeremy L Thompson @ref Developer 93eaf62fffSJeremy L Thompson **/ 94d04bbc78SJeremy L Thompson static int CeedOperatorCreateFallback(CeedOperator op) { 95eaf62fffSJeremy L Thompson int ierr; 969e77b9c8SJeremy L Thompson Ceed ceed_fallback; 97eaf62fffSJeremy L Thompson 98805fe78eSJeremy L Thompson // Check not already created 99805fe78eSJeremy L Thompson if (op->op_fallback) return CEED_ERROR_SUCCESS; 100805fe78eSJeremy L Thompson 101eaf62fffSJeremy L Thompson // Fallback Ceed 1029e77b9c8SJeremy L Thompson ierr = CeedGetOperatorFallbackCeed(op->ceed, &ceed_fallback); CeedChk(ierr); 103d04bbc78SJeremy L Thompson if (!ceed_fallback) return CEED_ERROR_SUCCESS; 104d04bbc78SJeremy L Thompson 105d04bbc78SJeremy L Thompson CeedDebug256(op->ceed, 1, "---------- CeedOperator Fallback ----------\n"); 106d04bbc78SJeremy L Thompson CeedDebug256(op->ceed, 255, "Creating fallback CeedOperator\n"); 107eaf62fffSJeremy L Thompson 108eaf62fffSJeremy L Thompson // Clone Op 109805fe78eSJeremy L Thompson CeedOperator op_fallback; 110805fe78eSJeremy L Thompson if (op->is_composite) { 1119e77b9c8SJeremy L Thompson ierr = CeedCompositeOperatorCreate(ceed_fallback, &op_fallback); 112805fe78eSJeremy L Thompson CeedChk(ierr); 113805fe78eSJeremy L Thompson for (CeedInt i = 0; i < op->num_suboperators; i++) { 114d04bbc78SJeremy L Thompson CeedOperator op_sub_fallback; 115d04bbc78SJeremy L Thompson 116d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op->sub_operators[i], &op_sub_fallback); 117805fe78eSJeremy L Thompson CeedChk(ierr); 118d04bbc78SJeremy L Thompson ierr = CeedCompositeOperatorAddSub(op_fallback, op_sub_fallback); CeedChk(ierr); 119805fe78eSJeremy L Thompson } 120805fe78eSJeremy L Thompson } else { 1219e77b9c8SJeremy L Thompson CeedQFunction qf_fallback = NULL, dqf_fallback = NULL, dqfT_fallback = NULL; 1229e77b9c8SJeremy L Thompson ierr = CeedQFunctionCreateFallback(ceed_fallback, op->qf, &qf_fallback); 1239e77b9c8SJeremy L Thompson CeedChk(ierr); 1249e77b9c8SJeremy L Thompson ierr = CeedQFunctionCreateFallback(ceed_fallback, op->dqf, &dqf_fallback); 1259e77b9c8SJeremy L Thompson CeedChk(ierr); 1269e77b9c8SJeremy L Thompson ierr = CeedQFunctionCreateFallback(ceed_fallback, op->dqfT, &dqfT_fallback); 1279e77b9c8SJeremy L Thompson CeedChk(ierr); 1289e77b9c8SJeremy L Thompson ierr = CeedOperatorCreate(ceed_fallback, qf_fallback, dqf_fallback, 1299e77b9c8SJeremy L Thompson dqfT_fallback, &op_fallback); CeedChk(ierr); 130805fe78eSJeremy L Thompson for (CeedInt i = 0; i < op->qf->num_input_fields; i++) { 131805fe78eSJeremy L Thompson ierr = CeedOperatorSetField(op_fallback, op->input_fields[i]->field_name, 132805fe78eSJeremy L Thompson op->input_fields[i]->elem_restr, 133805fe78eSJeremy L Thompson op->input_fields[i]->basis, 134805fe78eSJeremy L Thompson op->input_fields[i]->vec); CeedChk(ierr); 135805fe78eSJeremy L Thompson } 136805fe78eSJeremy L Thompson for (CeedInt i = 0; i < op->qf->num_output_fields; i++) { 137805fe78eSJeremy L Thompson ierr = CeedOperatorSetField(op_fallback, op->output_fields[i]->field_name, 138805fe78eSJeremy L Thompson op->output_fields[i]->elem_restr, 139805fe78eSJeremy L Thompson op->output_fields[i]->basis, 140805fe78eSJeremy L Thompson op->output_fields[i]->vec); CeedChk(ierr); 141805fe78eSJeremy L Thompson } 142480fae85SJeremy L Thompson ierr = CeedQFunctionAssemblyDataReferenceCopy(op->qf_assembled, 143805fe78eSJeremy L Thompson &op_fallback->qf_assembled); CeedChk(ierr); 144805fe78eSJeremy L Thompson if (op_fallback->num_qpts == 0) { 145805fe78eSJeremy L Thompson ierr = CeedOperatorSetNumQuadraturePoints(op_fallback, op->num_qpts); 146805fe78eSJeremy L Thompson CeedChk(ierr); 147805fe78eSJeremy L Thompson } 1489e77b9c8SJeremy L Thompson // Cleanup 1499e77b9c8SJeremy L Thompson ierr = CeedQFunctionDestroy(&qf_fallback); CeedChk(ierr); 1509e77b9c8SJeremy L Thompson ierr = CeedQFunctionDestroy(&dqf_fallback); CeedChk(ierr); 1519e77b9c8SJeremy L Thompson ierr = CeedQFunctionDestroy(&dqfT_fallback); CeedChk(ierr); 152805fe78eSJeremy L Thompson } 153805fe78eSJeremy L Thompson ierr = CeedOperatorSetName(op_fallback, op->name); CeedChk(ierr); 154805fe78eSJeremy L Thompson ierr = CeedOperatorCheckReady(op_fallback); CeedChk(ierr); 155805fe78eSJeremy L Thompson op->op_fallback = op_fallback; 156eaf62fffSJeremy L Thompson 157eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 158eaf62fffSJeremy L Thompson } 159eaf62fffSJeremy L Thompson 160eaf62fffSJeremy L Thompson /** 161d04bbc78SJeremy L Thompson @brief Retreive fallback CeedOperator with a reference Ceed for advanced CeedOperator functionality 162d04bbc78SJeremy L Thompson 163d04bbc78SJeremy L Thompson @param[in] op CeedOperator to retrieve fallback for 164d04bbc78SJeremy L Thompson @param[out] op_fallback Fallback CeedOperator 165d04bbc78SJeremy L Thompson 166d04bbc78SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 167d04bbc78SJeremy L Thompson 168d04bbc78SJeremy L Thompson @ref Developer 169d04bbc78SJeremy L Thompson **/ 170d04bbc78SJeremy L Thompson int CeedOperatorGetFallback(CeedOperator op, CeedOperator *op_fallback) { 171d04bbc78SJeremy L Thompson int ierr; 172d04bbc78SJeremy L Thompson 173d04bbc78SJeremy L Thompson // Create if needed 174d04bbc78SJeremy L Thompson if (!op->op_fallback) { 175d04bbc78SJeremy L Thompson ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 176d04bbc78SJeremy L Thompson } 177d04bbc78SJeremy L Thompson if (op->op_fallback) { 178d04bbc78SJeremy L Thompson bool is_debug; 179d04bbc78SJeremy L Thompson 180d04bbc78SJeremy L Thompson ierr = CeedIsDebug(op->ceed, &is_debug); CeedChk(ierr); 181d04bbc78SJeremy L Thompson if (is_debug) { 182d04bbc78SJeremy L Thompson Ceed ceed_fallback; 183d04bbc78SJeremy L Thompson const char *resource, *resource_fallback; 184d04bbc78SJeremy L Thompson 185d04bbc78SJeremy L Thompson ierr = CeedGetOperatorFallbackCeed(op->ceed, &ceed_fallback); CeedChk(ierr); 186d04bbc78SJeremy L Thompson ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr); 187d04bbc78SJeremy L Thompson ierr = CeedGetResource(ceed_fallback, &resource_fallback); CeedChk(ierr); 188d04bbc78SJeremy L Thompson 189d04bbc78SJeremy L Thompson CeedDebug256(op->ceed, 1, "---------- CeedOperator Fallback ----------\n"); 190d04bbc78SJeremy L Thompson CeedDebug256(op->ceed, 255, 191d04bbc78SJeremy L Thompson "Falling back from %s operator at address %ld to %s operator at address %ld\n", 192d04bbc78SJeremy L Thompson resource, op, resource_fallback, op->op_fallback); 193d04bbc78SJeremy L Thompson } 194d04bbc78SJeremy L Thompson } 195d04bbc78SJeremy L Thompson *op_fallback = op->op_fallback; 196d04bbc78SJeremy L Thompson 197d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 198d04bbc78SJeremy L Thompson } 199d04bbc78SJeremy L Thompson 200d04bbc78SJeremy L Thompson /** 201eaf62fffSJeremy L Thompson @brief Select correct basis matrix pointer based on CeedEvalMode 202eaf62fffSJeremy L Thompson 203eaf62fffSJeremy L Thompson @param[in] eval_mode Current basis evaluation mode 204eaf62fffSJeremy L Thompson @param[in] identity Pointer to identity matrix 205eaf62fffSJeremy L Thompson @param[in] interp Pointer to interpolation matrix 206eaf62fffSJeremy L Thompson @param[in] grad Pointer to gradient matrix 207eaf62fffSJeremy L Thompson @param[out] basis_ptr Basis pointer to set 208eaf62fffSJeremy L Thompson 209eaf62fffSJeremy L Thompson @ref Developer 210eaf62fffSJeremy L Thompson **/ 211eaf62fffSJeremy L Thompson static inline void CeedOperatorGetBasisPointer(CeedEvalMode eval_mode, 212eaf62fffSJeremy L Thompson const CeedScalar *identity, const CeedScalar *interp, 213eaf62fffSJeremy L Thompson const CeedScalar *grad, const CeedScalar **basis_ptr) { 214eaf62fffSJeremy L Thompson switch (eval_mode) { 215eaf62fffSJeremy L Thompson case CEED_EVAL_NONE: 216eaf62fffSJeremy L Thompson *basis_ptr = identity; 217eaf62fffSJeremy L Thompson break; 218eaf62fffSJeremy L Thompson case CEED_EVAL_INTERP: 219eaf62fffSJeremy L Thompson *basis_ptr = interp; 220eaf62fffSJeremy L Thompson break; 221eaf62fffSJeremy L Thompson case CEED_EVAL_GRAD: 222eaf62fffSJeremy L Thompson *basis_ptr = grad; 223eaf62fffSJeremy L Thompson break; 224eaf62fffSJeremy L Thompson case CEED_EVAL_WEIGHT: 225eaf62fffSJeremy L Thompson case CEED_EVAL_DIV: 226eaf62fffSJeremy L Thompson case CEED_EVAL_CURL: 227eaf62fffSJeremy L Thompson break; // Caught by QF Assembly 228eaf62fffSJeremy L Thompson } 229eaf62fffSJeremy L Thompson } 230eaf62fffSJeremy L Thompson 231eaf62fffSJeremy L Thompson /** 232eaf62fffSJeremy L Thompson @brief Create point block restriction for active operator field 233eaf62fffSJeremy L Thompson 234eaf62fffSJeremy L Thompson @param[in] rstr Original CeedElemRestriction for active field 235eaf62fffSJeremy L Thompson @param[out] pointblock_rstr Address of the variable where the newly created 236eaf62fffSJeremy L Thompson CeedElemRestriction will be stored 237eaf62fffSJeremy L Thompson 238eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 239eaf62fffSJeremy L Thompson 240eaf62fffSJeremy L Thompson @ref Developer 241eaf62fffSJeremy L Thompson **/ 242eaf62fffSJeremy L Thompson static int CeedOperatorCreateActivePointBlockRestriction( 243eaf62fffSJeremy L Thompson CeedElemRestriction rstr, 244eaf62fffSJeremy L Thompson CeedElemRestriction *pointblock_rstr) { 245eaf62fffSJeremy L Thompson int ierr; 246eaf62fffSJeremy L Thompson Ceed ceed; 247eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetCeed(rstr, &ceed); CeedChk(ierr); 248eaf62fffSJeremy L Thompson const CeedInt *offsets; 249eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets); 250eaf62fffSJeremy L Thompson CeedChk(ierr); 251eaf62fffSJeremy L Thompson 252eaf62fffSJeremy L Thompson // Expand offsets 253eaf62fffSJeremy L Thompson CeedInt num_elem, num_comp, elem_size, comp_stride, max = 1, 254eaf62fffSJeremy L Thompson *pointblock_offsets; 255eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr); 256eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumComponents(rstr, &num_comp); CeedChk(ierr); 257eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr, &elem_size); CeedChk(ierr); 258eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetCompStride(rstr, &comp_stride); CeedChk(ierr); 259eaf62fffSJeremy L Thompson CeedInt shift = num_comp; 260eaf62fffSJeremy L Thompson if (comp_stride != 1) 261eaf62fffSJeremy L Thompson shift *= num_comp; 262eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_elem*elem_size, &pointblock_offsets); 263eaf62fffSJeremy L Thompson CeedChk(ierr); 264eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_elem*elem_size; i++) { 265eaf62fffSJeremy L Thompson pointblock_offsets[i] = offsets[i]*shift; 266eaf62fffSJeremy L Thompson if (pointblock_offsets[i] > max) 267eaf62fffSJeremy L Thompson max = pointblock_offsets[i]; 268eaf62fffSJeremy L Thompson } 269eaf62fffSJeremy L Thompson 270eaf62fffSJeremy L Thompson // Create new restriction 271eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionCreate(ceed, num_elem, elem_size, num_comp*num_comp, 272eaf62fffSJeremy L Thompson 1, max + num_comp*num_comp, CEED_MEM_HOST, 273eaf62fffSJeremy L Thompson CEED_OWN_POINTER, pointblock_offsets, pointblock_rstr); 274eaf62fffSJeremy L Thompson CeedChk(ierr); 275eaf62fffSJeremy L Thompson 276eaf62fffSJeremy L Thompson // Cleanup 277eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionRestoreOffsets(rstr, &offsets); CeedChk(ierr); 278eaf62fffSJeremy L Thompson 279eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 280eaf62fffSJeremy L Thompson } 281eaf62fffSJeremy L Thompson 282eaf62fffSJeremy L Thompson /** 283eaf62fffSJeremy L Thompson @brief Core logic for assembling operator diagonal or point block diagonal 284eaf62fffSJeremy L Thompson 285eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble point block diagonal 286eaf62fffSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else 287eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 288eaf62fffSJeremy L Thompson @param[in] is_pointblock Boolean flag to assemble diagonal or point block diagonal 289eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled diagonal 290eaf62fffSJeremy L Thompson 291eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 292eaf62fffSJeremy L Thompson 293eaf62fffSJeremy L Thompson @ref Developer 294eaf62fffSJeremy L Thompson **/ 295eaf62fffSJeremy L Thompson static inline int CeedSingleOperatorAssembleAddDiagonal(CeedOperator op, 296eaf62fffSJeremy L Thompson CeedRequest *request, const bool is_pointblock, CeedVector assembled) { 297eaf62fffSJeremy L Thompson int ierr; 298eaf62fffSJeremy L Thompson Ceed ceed; 299eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 300eaf62fffSJeremy L Thompson 301eaf62fffSJeremy L Thompson // Assemble QFunction 302eaf62fffSJeremy L Thompson CeedQFunction qf; 303eaf62fffSJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr); 304eaf62fffSJeremy L Thompson CeedInt num_input_fields, num_output_fields; 305eaf62fffSJeremy L Thompson ierr= CeedQFunctionGetNumArgs(qf, &num_input_fields, &num_output_fields); 306eaf62fffSJeremy L Thompson CeedChk(ierr); 307eaf62fffSJeremy L Thompson CeedVector assembled_qf; 308eaf62fffSJeremy L Thompson CeedElemRestriction rstr; 30970a7ffb3SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled_qf, 31070a7ffb3SJeremy L Thompson &rstr, request); CeedChk(ierr); 311eaf62fffSJeremy L Thompson CeedInt layout[3]; 312eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetELayout(rstr, &layout); CeedChk(ierr); 313eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr); 314eaf62fffSJeremy L Thompson CeedScalar max_norm = 0; 315eaf62fffSJeremy L Thompson ierr = CeedVectorNorm(assembled_qf, CEED_NORM_MAX, &max_norm); CeedChk(ierr); 316eaf62fffSJeremy L Thompson 317eaf62fffSJeremy L Thompson // Determine active input basis 318eaf62fffSJeremy L Thompson CeedOperatorField *op_fields; 319eaf62fffSJeremy L Thompson CeedQFunctionField *qf_fields; 3207e7773b5SJeremy L Thompson ierr = CeedOperatorGetFields(op, NULL, &op_fields, NULL, NULL); CeedChk(ierr); 3217e7773b5SJeremy L Thompson ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL); CeedChk(ierr); 322eaf62fffSJeremy L Thompson CeedInt num_eval_mode_in = 0, num_comp, dim = 1; 323eaf62fffSJeremy L Thompson CeedEvalMode *eval_mode_in = NULL; 324eaf62fffSJeremy L Thompson CeedBasis basis_in = NULL; 325eaf62fffSJeremy L Thompson CeedElemRestriction rstr_in = NULL; 326eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_input_fields; i++) { 327eaf62fffSJeremy L Thompson CeedVector vec; 328eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChk(ierr); 329eaf62fffSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 330eaf62fffSJeremy L Thompson CeedElemRestriction rstr; 331eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis_in); CeedChk(ierr); 332eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis_in, &num_comp); CeedChk(ierr); 333eaf62fffSJeremy L Thompson ierr = CeedBasisGetDimension(basis_in, &dim); CeedChk(ierr); 334eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr); CeedChk(ierr); 335eaf62fffSJeremy L Thompson if (rstr_in && rstr_in != rstr) 336eaf62fffSJeremy L Thompson // LCOV_EXCL_START 337eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 338eaf62fffSJeremy L Thompson "Multi-field non-composite operator diagonal assembly not supported"); 339eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 340eaf62fffSJeremy L Thompson rstr_in = rstr; 341eaf62fffSJeremy L Thompson CeedEvalMode eval_mode; 342eaf62fffSJeremy L Thompson ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); CeedChk(ierr); 343eaf62fffSJeremy L Thompson switch (eval_mode) { 344eaf62fffSJeremy L Thompson case CEED_EVAL_NONE: 345eaf62fffSJeremy L Thompson case CEED_EVAL_INTERP: 346eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_in + 1, &eval_mode_in); CeedChk(ierr); 347eaf62fffSJeremy L Thompson eval_mode_in[num_eval_mode_in] = eval_mode; 348eaf62fffSJeremy L Thompson num_eval_mode_in += 1; 349eaf62fffSJeremy L Thompson break; 350eaf62fffSJeremy L Thompson case CEED_EVAL_GRAD: 351eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_in + dim, &eval_mode_in); CeedChk(ierr); 352eaf62fffSJeremy L Thompson for (CeedInt d=0; d<dim; d++) 353eaf62fffSJeremy L Thompson eval_mode_in[num_eval_mode_in+d] = eval_mode; 354eaf62fffSJeremy L Thompson num_eval_mode_in += dim; 355eaf62fffSJeremy L Thompson break; 356eaf62fffSJeremy L Thompson case CEED_EVAL_WEIGHT: 357eaf62fffSJeremy L Thompson case CEED_EVAL_DIV: 358eaf62fffSJeremy L Thompson case CEED_EVAL_CURL: 359eaf62fffSJeremy L Thompson break; // Caught by QF Assembly 360eaf62fffSJeremy L Thompson } 361eaf62fffSJeremy L Thompson } 362eaf62fffSJeremy L Thompson } 363eaf62fffSJeremy L Thompson 364eaf62fffSJeremy L Thompson // Determine active output basis 3657e7773b5SJeremy L Thompson ierr = CeedOperatorGetFields(op, NULL, NULL, NULL, &op_fields); CeedChk(ierr); 3667e7773b5SJeremy L Thompson ierr = CeedQFunctionGetFields(qf, NULL, NULL, NULL, &qf_fields); CeedChk(ierr); 367eaf62fffSJeremy L Thompson CeedInt num_eval_mode_out = 0; 368eaf62fffSJeremy L Thompson CeedEvalMode *eval_mode_out = NULL; 369eaf62fffSJeremy L Thompson CeedBasis basis_out = NULL; 370eaf62fffSJeremy L Thompson CeedElemRestriction rstr_out = NULL; 371eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_output_fields; i++) { 372eaf62fffSJeremy L Thompson CeedVector vec; 373eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChk(ierr); 374eaf62fffSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 375eaf62fffSJeremy L Thompson CeedElemRestriction rstr; 376eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis_out); CeedChk(ierr); 377eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr); CeedChk(ierr); 378eaf62fffSJeremy L Thompson if (rstr_out && rstr_out != rstr) 379eaf62fffSJeremy L Thompson // LCOV_EXCL_START 380eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 381eaf62fffSJeremy L Thompson "Multi-field non-composite operator diagonal assembly not supported"); 382eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 383eaf62fffSJeremy L Thompson rstr_out = rstr; 384eaf62fffSJeremy L Thompson CeedEvalMode eval_mode; 385eaf62fffSJeremy L Thompson ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); CeedChk(ierr); 386eaf62fffSJeremy L Thompson switch (eval_mode) { 387eaf62fffSJeremy L Thompson case CEED_EVAL_NONE: 388eaf62fffSJeremy L Thompson case CEED_EVAL_INTERP: 389eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_out + 1, &eval_mode_out); CeedChk(ierr); 390eaf62fffSJeremy L Thompson eval_mode_out[num_eval_mode_out] = eval_mode; 391eaf62fffSJeremy L Thompson num_eval_mode_out += 1; 392eaf62fffSJeremy L Thompson break; 393eaf62fffSJeremy L Thompson case CEED_EVAL_GRAD: 394eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_out + dim, &eval_mode_out); CeedChk(ierr); 395eaf62fffSJeremy L Thompson for (CeedInt d=0; d<dim; d++) 396eaf62fffSJeremy L Thompson eval_mode_out[num_eval_mode_out+d] = eval_mode; 397eaf62fffSJeremy L Thompson num_eval_mode_out += dim; 398eaf62fffSJeremy L Thompson break; 399eaf62fffSJeremy L Thompson case CEED_EVAL_WEIGHT: 400eaf62fffSJeremy L Thompson case CEED_EVAL_DIV: 401eaf62fffSJeremy L Thompson case CEED_EVAL_CURL: 402eaf62fffSJeremy L Thompson break; // Caught by QF Assembly 403eaf62fffSJeremy L Thompson } 404eaf62fffSJeremy L Thompson } 405eaf62fffSJeremy L Thompson } 406eaf62fffSJeremy L Thompson 407eaf62fffSJeremy L Thompson // Assemble point block diagonal restriction, if needed 408eaf62fffSJeremy L Thompson CeedElemRestriction diag_rstr = rstr_out; 409eaf62fffSJeremy L Thompson if (is_pointblock) { 410eaf62fffSJeremy L Thompson ierr = CeedOperatorCreateActivePointBlockRestriction(rstr_out, &diag_rstr); 411eaf62fffSJeremy L Thompson CeedChk(ierr); 412eaf62fffSJeremy L Thompson } 413eaf62fffSJeremy L Thompson 414eaf62fffSJeremy L Thompson // Create diagonal vector 415eaf62fffSJeremy L Thompson CeedVector elem_diag; 416eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionCreateVector(diag_rstr, NULL, &elem_diag); 417eaf62fffSJeremy L Thompson CeedChk(ierr); 418eaf62fffSJeremy L Thompson 419eaf62fffSJeremy L Thompson // Assemble element operator diagonals 4209c774eddSJeremy L Thompson CeedScalar *elem_diag_array; 4219c774eddSJeremy L Thompson const CeedScalar *assembled_qf_array; 422eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(elem_diag, 0.0); CeedChk(ierr); 423eaf62fffSJeremy L Thompson ierr = CeedVectorGetArray(elem_diag, CEED_MEM_HOST, &elem_diag_array); 424eaf62fffSJeremy L Thompson CeedChk(ierr); 4259c774eddSJeremy L Thompson ierr = CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array); 426eaf62fffSJeremy L Thompson CeedChk(ierr); 427eaf62fffSJeremy L Thompson CeedInt num_elem, num_nodes, num_qpts; 428eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(diag_rstr, &num_elem); CeedChk(ierr); 429eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis_in, &num_nodes); CeedChk(ierr); 430eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts); CeedChk(ierr); 431eaf62fffSJeremy L Thompson // Basis matrices 432eaf62fffSJeremy L Thompson const CeedScalar *interp_in, *interp_out, *grad_in, *grad_out; 433eaf62fffSJeremy L Thompson CeedScalar *identity = NULL; 434eaf62fffSJeremy L Thompson bool evalNone = false; 435eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_eval_mode_in; i++) 436eaf62fffSJeremy L Thompson evalNone = evalNone || (eval_mode_in[i] == CEED_EVAL_NONE); 437eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_eval_mode_out; i++) 438eaf62fffSJeremy L Thompson evalNone = evalNone || (eval_mode_out[i] == CEED_EVAL_NONE); 439eaf62fffSJeremy L Thompson if (evalNone) { 440eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_qpts*num_nodes, &identity); CeedChk(ierr); 441eaf62fffSJeremy L Thompson for (CeedInt i=0; i<(num_nodes<num_qpts?num_nodes:num_qpts); i++) 442eaf62fffSJeremy L Thompson identity[i*num_nodes+i] = 1.0; 443eaf62fffSJeremy L Thompson } 444eaf62fffSJeremy L Thompson ierr = CeedBasisGetInterp(basis_in, &interp_in); CeedChk(ierr); 445eaf62fffSJeremy L Thompson ierr = CeedBasisGetInterp(basis_out, &interp_out); CeedChk(ierr); 446eaf62fffSJeremy L Thompson ierr = CeedBasisGetGrad(basis_in, &grad_in); CeedChk(ierr); 447eaf62fffSJeremy L Thompson ierr = CeedBasisGetGrad(basis_out, &grad_out); CeedChk(ierr); 448eaf62fffSJeremy L Thompson // Compute the diagonal of B^T D B 449eaf62fffSJeremy L Thompson // Each element 450eaf62fffSJeremy L Thompson const CeedScalar qf_value_bound = max_norm*100*CEED_EPSILON; 451eaf62fffSJeremy L Thompson for (CeedInt e=0; e<num_elem; e++) { 452eaf62fffSJeremy L Thompson CeedInt d_out = -1; 453eaf62fffSJeremy L Thompson // Each basis eval mode pair 454eaf62fffSJeremy L Thompson for (CeedInt e_out=0; e_out<num_eval_mode_out; e_out++) { 455eaf62fffSJeremy L Thompson const CeedScalar *bt = NULL; 456eaf62fffSJeremy L Thompson if (eval_mode_out[e_out] == CEED_EVAL_GRAD) 457eaf62fffSJeremy L Thompson d_out += 1; 458eaf62fffSJeremy L Thompson CeedOperatorGetBasisPointer(eval_mode_out[e_out], identity, interp_out, 459eaf62fffSJeremy L Thompson &grad_out[d_out*num_qpts*num_nodes], &bt); 460eaf62fffSJeremy L Thompson CeedInt d_in = -1; 461eaf62fffSJeremy L Thompson for (CeedInt e_in=0; e_in<num_eval_mode_in; e_in++) { 462eaf62fffSJeremy L Thompson const CeedScalar *b = NULL; 463eaf62fffSJeremy L Thompson if (eval_mode_in[e_in] == CEED_EVAL_GRAD) 464eaf62fffSJeremy L Thompson d_in += 1; 465eaf62fffSJeremy L Thompson CeedOperatorGetBasisPointer(eval_mode_in[e_in], identity, interp_in, 466eaf62fffSJeremy L Thompson &grad_in[d_in*num_qpts*num_nodes], &b); 467eaf62fffSJeremy L Thompson // Each component 468eaf62fffSJeremy L Thompson for (CeedInt c_out=0; c_out<num_comp; c_out++) 469eaf62fffSJeremy L Thompson // Each qpoint/node pair 470eaf62fffSJeremy L Thompson for (CeedInt q=0; q<num_qpts; q++) 471eaf62fffSJeremy L Thompson if (is_pointblock) { 472eaf62fffSJeremy L Thompson // Point Block Diagonal 473eaf62fffSJeremy L Thompson for (CeedInt c_in=0; c_in<num_comp; c_in++) { 474eaf62fffSJeremy L Thompson const CeedScalar qf_value = 475eaf62fffSJeremy L Thompson assembled_qf_array[q*layout[0] + (((e_in*num_comp+c_in)* 476eaf62fffSJeremy L Thompson num_eval_mode_out+e_out)*num_comp+c_out)*layout[1] + e*layout[2]]; 477eaf62fffSJeremy L Thompson if (fabs(qf_value) > qf_value_bound) 478eaf62fffSJeremy L Thompson for (CeedInt n=0; n<num_nodes; n++) 479eaf62fffSJeremy L Thompson elem_diag_array[((e*num_comp+c_out)*num_comp+c_in)*num_nodes+n] += 480eaf62fffSJeremy L Thompson bt[q*num_nodes+n] * qf_value * b[q*num_nodes+n]; 481eaf62fffSJeremy L Thompson } 482eaf62fffSJeremy L Thompson } else { 483eaf62fffSJeremy L Thompson // Diagonal Only 484eaf62fffSJeremy L Thompson const CeedScalar qf_value = 485eaf62fffSJeremy L Thompson assembled_qf_array[q*layout[0] + (((e_in*num_comp+c_out)* 486eaf62fffSJeremy L Thompson num_eval_mode_out+e_out)*num_comp+c_out)*layout[1] + e*layout[2]]; 487eaf62fffSJeremy L Thompson if (fabs(qf_value) > qf_value_bound) 488eaf62fffSJeremy L Thompson for (CeedInt n=0; n<num_nodes; n++) 489eaf62fffSJeremy L Thompson elem_diag_array[(e*num_comp+c_out)*num_nodes+n] += 490eaf62fffSJeremy L Thompson bt[q*num_nodes+n] * qf_value * b[q*num_nodes+n]; 491eaf62fffSJeremy L Thompson } 492eaf62fffSJeremy L Thompson } 493eaf62fffSJeremy L Thompson } 494eaf62fffSJeremy L Thompson } 495eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArray(elem_diag, &elem_diag_array); CeedChk(ierr); 4969c774eddSJeremy L Thompson ierr = CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array); 4979c774eddSJeremy L Thompson CeedChk(ierr); 498eaf62fffSJeremy L Thompson 499eaf62fffSJeremy L Thompson // Assemble local operator diagonal 500eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionApply(diag_rstr, CEED_TRANSPOSE, elem_diag, 501eaf62fffSJeremy L Thompson assembled, request); CeedChk(ierr); 502eaf62fffSJeremy L Thompson 503eaf62fffSJeremy L Thompson // Cleanup 504eaf62fffSJeremy L Thompson if (is_pointblock) { 505eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&diag_rstr); CeedChk(ierr); 506eaf62fffSJeremy L Thompson } 507eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&assembled_qf); CeedChk(ierr); 508eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&elem_diag); CeedChk(ierr); 509eaf62fffSJeremy L Thompson ierr = CeedFree(&eval_mode_in); CeedChk(ierr); 510eaf62fffSJeremy L Thompson ierr = CeedFree(&eval_mode_out); CeedChk(ierr); 511eaf62fffSJeremy L Thompson ierr = CeedFree(&identity); CeedChk(ierr); 512eaf62fffSJeremy L Thompson 513eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 514eaf62fffSJeremy L Thompson } 515eaf62fffSJeremy L Thompson 516eaf62fffSJeremy L Thompson /** 517eaf62fffSJeremy L Thompson @brief Core logic for assembling composite operator diagonal 518eaf62fffSJeremy L Thompson 519eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble point block diagonal 520eaf62fffSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else 521eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 522eaf62fffSJeremy L Thompson @param[in] is_pointblock Boolean flag to assemble diagonal or point block diagonal 523eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled diagonal 524eaf62fffSJeremy L Thompson 525eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 526eaf62fffSJeremy L Thompson 527eaf62fffSJeremy L Thompson @ref Developer 528eaf62fffSJeremy L Thompson **/ 529eaf62fffSJeremy L Thompson static inline int CeedCompositeOperatorLinearAssembleAddDiagonal( 530eaf62fffSJeremy L Thompson CeedOperator op, CeedRequest *request, const bool is_pointblock, 531eaf62fffSJeremy L Thompson CeedVector assembled) { 532eaf62fffSJeremy L Thompson int ierr; 533eaf62fffSJeremy L Thompson CeedInt num_sub; 534eaf62fffSJeremy L Thompson CeedOperator *suboperators; 535eaf62fffSJeremy L Thompson ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr); 536eaf62fffSJeremy L Thompson ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr); 537eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_sub; i++) { 5386aa95790SJeremy L Thompson if (is_pointblock) { 5396aa95790SJeremy L Thompson ierr = CeedOperatorLinearAssembleAddPointBlockDiagonal(suboperators[i], 5406aa95790SJeremy L Thompson assembled, request); CeedChk(ierr); 5416aa95790SJeremy L Thompson } else { 5426aa95790SJeremy L Thompson ierr = CeedOperatorLinearAssembleAddDiagonal(suboperators[i], assembled, 5436aa95790SJeremy L Thompson request); CeedChk(ierr); 5446aa95790SJeremy L Thompson } 545eaf62fffSJeremy L Thompson } 546eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 547eaf62fffSJeremy L Thompson } 548eaf62fffSJeremy L Thompson 549eaf62fffSJeremy L Thompson /** 550eaf62fffSJeremy L Thompson @brief Build nonzero pattern for non-composite operator 551eaf62fffSJeremy L Thompson 552eaf62fffSJeremy L Thompson Users should generally use CeedOperatorLinearAssembleSymbolic() 553eaf62fffSJeremy L Thompson 554eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble nonzero pattern 555eaf62fffSJeremy L Thompson @param[in] offset Offset for number of entries 556eaf62fffSJeremy L Thompson @param[out] rows Row number for each entry 557eaf62fffSJeremy L Thompson @param[out] cols Column number for each entry 558eaf62fffSJeremy L Thompson 559eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 560eaf62fffSJeremy L Thompson 561eaf62fffSJeremy L Thompson @ref Developer 562eaf62fffSJeremy L Thompson **/ 563eaf62fffSJeremy L Thompson static int CeedSingleOperatorAssembleSymbolic(CeedOperator op, CeedInt offset, 564eaf62fffSJeremy L Thompson CeedInt *rows, CeedInt *cols) { 565eaf62fffSJeremy L Thompson int ierr; 566eaf62fffSJeremy L Thompson Ceed ceed = op->ceed; 567f04ea552SJeremy L Thompson if (op->is_composite) 568eaf62fffSJeremy L Thompson // LCOV_EXCL_START 569eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 570eaf62fffSJeremy L Thompson "Composite operator not supported"); 571eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 572eaf62fffSJeremy L Thompson 573c9366a6bSJeremy L Thompson CeedSize num_nodes; 574c9366a6bSJeremy L Thompson ierr = CeedOperatorGetActiveVectorLengths(op, &num_nodes, NULL); CeedChk(ierr); 575eaf62fffSJeremy L Thompson CeedElemRestriction rstr_in; 576eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveElemRestriction(op, &rstr_in); CeedChk(ierr); 577e79b91d9SJeremy L Thompson CeedInt num_elem, elem_size, num_comp; 578eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(rstr_in, &num_elem); CeedChk(ierr); 579eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr_in, &elem_size); CeedChk(ierr); 580eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumComponents(rstr_in, &num_comp); CeedChk(ierr); 581eaf62fffSJeremy L Thompson CeedInt layout_er[3]; 582eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetELayout(rstr_in, &layout_er); CeedChk(ierr); 583eaf62fffSJeremy L Thompson 584eaf62fffSJeremy L Thompson CeedInt local_num_entries = elem_size*num_comp * elem_size*num_comp * num_elem; 585eaf62fffSJeremy L Thompson 586eaf62fffSJeremy L Thompson // Determine elem_dof relation 587eaf62fffSJeremy L Thompson CeedVector index_vec; 588eaf62fffSJeremy L Thompson ierr = CeedVectorCreate(ceed, num_nodes, &index_vec); CeedChk(ierr); 589eaf62fffSJeremy L Thompson CeedScalar *array; 5909c774eddSJeremy L Thompson ierr = CeedVectorGetArrayWrite(index_vec, CEED_MEM_HOST, &array); CeedChk(ierr); 591eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_nodes; ++i) { 592eaf62fffSJeremy L Thompson array[i] = i; 593eaf62fffSJeremy L Thompson } 594eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArray(index_vec, &array); CeedChk(ierr); 595eaf62fffSJeremy L Thompson CeedVector elem_dof; 596eaf62fffSJeremy L Thompson ierr = CeedVectorCreate(ceed, num_elem * elem_size * num_comp, &elem_dof); 597eaf62fffSJeremy L Thompson CeedChk(ierr); 598eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(elem_dof, 0.0); CeedChk(ierr); 599eaf62fffSJeremy L Thompson CeedElemRestrictionApply(rstr_in, CEED_NOTRANSPOSE, index_vec, 600eaf62fffSJeremy L Thompson elem_dof, CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 601eaf62fffSJeremy L Thompson const CeedScalar *elem_dof_a; 602eaf62fffSJeremy L Thompson ierr = CeedVectorGetArrayRead(elem_dof, CEED_MEM_HOST, &elem_dof_a); 603eaf62fffSJeremy L Thompson CeedChk(ierr); 604eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&index_vec); CeedChk(ierr); 605eaf62fffSJeremy L Thompson 606eaf62fffSJeremy L Thompson // Determine i, j locations for element matrices 607eaf62fffSJeremy L Thompson CeedInt count = 0; 60892ae7e47SJeremy L Thompson for (CeedInt e = 0; e < num_elem; ++e) { 60992ae7e47SJeremy L Thompson for (CeedInt comp_in = 0; comp_in < num_comp; ++comp_in) { 61092ae7e47SJeremy L Thompson for (CeedInt comp_out = 0; comp_out < num_comp; ++comp_out) { 61192ae7e47SJeremy L Thompson for (CeedInt i = 0; i < elem_size; ++i) { 61292ae7e47SJeremy L Thompson for (CeedInt j = 0; j < elem_size; ++j) { 613eaf62fffSJeremy L Thompson const CeedInt elem_dof_index_row = (i)*layout_er[0] + 614eaf62fffSJeremy L Thompson (comp_out)*layout_er[1] + e*layout_er[2]; 615eaf62fffSJeremy L Thompson const CeedInt elem_dof_index_col = (j)*layout_er[0] + 616eaf62fffSJeremy L Thompson (comp_in)*layout_er[1] + e*layout_er[2]; 617eaf62fffSJeremy L Thompson 618eaf62fffSJeremy L Thompson const CeedInt row = elem_dof_a[elem_dof_index_row]; 619eaf62fffSJeremy L Thompson const CeedInt col = elem_dof_a[elem_dof_index_col]; 620eaf62fffSJeremy L Thompson 621eaf62fffSJeremy L Thompson rows[offset + count] = row; 622eaf62fffSJeremy L Thompson cols[offset + count] = col; 623eaf62fffSJeremy L Thompson count++; 624eaf62fffSJeremy L Thompson } 625eaf62fffSJeremy L Thompson } 626eaf62fffSJeremy L Thompson } 627eaf62fffSJeremy L Thompson } 628eaf62fffSJeremy L Thompson } 629eaf62fffSJeremy L Thompson if (count != local_num_entries) 630eaf62fffSJeremy L Thompson // LCOV_EXCL_START 631eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing assembled entries"); 632eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 633eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArrayRead(elem_dof, &elem_dof_a); CeedChk(ierr); 634eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&elem_dof); CeedChk(ierr); 635eaf62fffSJeremy L Thompson 636eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 637eaf62fffSJeremy L Thompson } 638eaf62fffSJeremy L Thompson 639eaf62fffSJeremy L Thompson /** 640eaf62fffSJeremy L Thompson @brief Assemble nonzero entries for non-composite operator 641eaf62fffSJeremy L Thompson 642eaf62fffSJeremy L Thompson Users should generally use CeedOperatorLinearAssemble() 643eaf62fffSJeremy L Thompson 644eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 645*52b3e6a7SJed Brown @param[in] offset Offest for number of entries 646eaf62fffSJeremy L Thompson @param[out] values Values to assemble into matrix 647eaf62fffSJeremy L Thompson 648eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 649eaf62fffSJeremy L Thompson 650eaf62fffSJeremy L Thompson @ref Developer 651eaf62fffSJeremy L Thompson **/ 652eaf62fffSJeremy L Thompson static int CeedSingleOperatorAssemble(CeedOperator op, CeedInt offset, 653eaf62fffSJeremy L Thompson CeedVector values) { 654eaf62fffSJeremy L Thompson int ierr; 655eaf62fffSJeremy L Thompson Ceed ceed = op->ceed; 656f04ea552SJeremy L Thompson if (op->is_composite) 657eaf62fffSJeremy L Thompson // LCOV_EXCL_START 658eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 659eaf62fffSJeremy L Thompson "Composite operator not supported"); 660eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 661*52b3e6a7SJed Brown if (op->num_elem == 0) return CEED_ERROR_SUCCESS; 662eaf62fffSJeremy L Thompson 663cefa2673SJeremy L Thompson if (op->LinearAssembleSingle) { 664cefa2673SJeremy L Thompson // Backend version 665cefa2673SJeremy L Thompson ierr = op->LinearAssembleSingle(op, offset, values); CeedChk(ierr); 666cefa2673SJeremy L Thompson return CEED_ERROR_SUCCESS; 667cefa2673SJeremy L Thompson } else { 668cefa2673SJeremy L Thompson // Operator fallback 669cefa2673SJeremy L Thompson CeedOperator op_fallback; 670cefa2673SJeremy L Thompson 671cefa2673SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 672cefa2673SJeremy L Thompson if (op_fallback) { 673cefa2673SJeremy L Thompson ierr = CeedSingleOperatorAssemble(op_fallback, offset, values); 674cefa2673SJeremy L Thompson CeedChk(ierr); 675cefa2673SJeremy L Thompson return CEED_ERROR_SUCCESS; 676cefa2673SJeremy L Thompson } 677cefa2673SJeremy L Thompson } 678cefa2673SJeremy L Thompson 679eaf62fffSJeremy L Thompson // Assemble QFunction 680eaf62fffSJeremy L Thompson CeedQFunction qf; 681eaf62fffSJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr); 682eaf62fffSJeremy L Thompson CeedVector assembled_qf; 683eaf62fffSJeremy L Thompson CeedElemRestriction rstr_q; 68470a7ffb3SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate( 685eaf62fffSJeremy L Thompson op, &assembled_qf, &rstr_q, CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 686eaf62fffSJeremy L Thompson 6871f9221feSJeremy L Thompson CeedSize qf_length; 688eaf62fffSJeremy L Thompson ierr = CeedVectorGetLength(assembled_qf, &qf_length); CeedChk(ierr); 689eaf62fffSJeremy L Thompson 6907e7773b5SJeremy L Thompson CeedInt num_input_fields, num_output_fields; 691eaf62fffSJeremy L Thompson CeedOperatorField *input_fields; 692eaf62fffSJeremy L Thompson CeedOperatorField *output_fields; 6937e7773b5SJeremy L Thompson ierr = CeedOperatorGetFields(op, &num_input_fields, &input_fields, 6947e7773b5SJeremy L Thompson &num_output_fields, &output_fields); CeedChk(ierr); 695eaf62fffSJeremy L Thompson 696eaf62fffSJeremy L Thompson // Determine active input basis 697eaf62fffSJeremy L Thompson CeedQFunctionField *qf_fields; 6987e7773b5SJeremy L Thompson ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL); CeedChk(ierr); 699eaf62fffSJeremy L Thompson CeedInt num_eval_mode_in = 0, dim = 1; 700eaf62fffSJeremy L Thompson CeedEvalMode *eval_mode_in = NULL; 701eaf62fffSJeremy L Thompson CeedBasis basis_in = NULL; 702eaf62fffSJeremy L Thompson CeedElemRestriction rstr_in = NULL; 703eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_input_fields; i++) { 704eaf62fffSJeremy L Thompson CeedVector vec; 705eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetVector(input_fields[i], &vec); CeedChk(ierr); 706eaf62fffSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 707eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetBasis(input_fields[i], &basis_in); 708eaf62fffSJeremy L Thompson CeedChk(ierr); 709eaf62fffSJeremy L Thompson ierr = CeedBasisGetDimension(basis_in, &dim); CeedChk(ierr); 710eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetElemRestriction(input_fields[i], &rstr_in); 711eaf62fffSJeremy L Thompson CeedChk(ierr); 712eaf62fffSJeremy L Thompson CeedEvalMode eval_mode; 713eaf62fffSJeremy L Thompson ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); 714eaf62fffSJeremy L Thompson CeedChk(ierr); 715eaf62fffSJeremy L Thompson switch (eval_mode) { 716eaf62fffSJeremy L Thompson case CEED_EVAL_NONE: 717eaf62fffSJeremy L Thompson case CEED_EVAL_INTERP: 718eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_in + 1, &eval_mode_in); CeedChk(ierr); 719eaf62fffSJeremy L Thompson eval_mode_in[num_eval_mode_in] = eval_mode; 720eaf62fffSJeremy L Thompson num_eval_mode_in += 1; 721eaf62fffSJeremy L Thompson break; 722eaf62fffSJeremy L Thompson case CEED_EVAL_GRAD: 723eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_in + dim, &eval_mode_in); CeedChk(ierr); 724eaf62fffSJeremy L Thompson for (CeedInt d=0; d<dim; d++) { 725eaf62fffSJeremy L Thompson eval_mode_in[num_eval_mode_in+d] = eval_mode; 726eaf62fffSJeremy L Thompson } 727eaf62fffSJeremy L Thompson num_eval_mode_in += dim; 728eaf62fffSJeremy L Thompson break; 729eaf62fffSJeremy L Thompson case CEED_EVAL_WEIGHT: 730eaf62fffSJeremy L Thompson case CEED_EVAL_DIV: 731eaf62fffSJeremy L Thompson case CEED_EVAL_CURL: 732eaf62fffSJeremy L Thompson break; // Caught by QF Assembly 733eaf62fffSJeremy L Thompson } 734eaf62fffSJeremy L Thompson } 735eaf62fffSJeremy L Thompson } 736eaf62fffSJeremy L Thompson 737eaf62fffSJeremy L Thompson // Determine active output basis 7387e7773b5SJeremy L Thompson ierr = CeedQFunctionGetFields(qf, NULL, NULL, NULL, &qf_fields); CeedChk(ierr); 739eaf62fffSJeremy L Thompson CeedInt num_eval_mode_out = 0; 740eaf62fffSJeremy L Thompson CeedEvalMode *eval_mode_out = NULL; 741eaf62fffSJeremy L Thompson CeedBasis basis_out = NULL; 742eaf62fffSJeremy L Thompson CeedElemRestriction rstr_out = NULL; 743eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_output_fields; i++) { 744eaf62fffSJeremy L Thompson CeedVector vec; 745eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetVector(output_fields[i], &vec); CeedChk(ierr); 746eaf62fffSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 747eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetBasis(output_fields[i], &basis_out); 748eaf62fffSJeremy L Thompson CeedChk(ierr); 749eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetElemRestriction(output_fields[i], &rstr_out); 750eaf62fffSJeremy L Thompson CeedChk(ierr); 751eaf62fffSJeremy L Thompson CeedEvalMode eval_mode; 752eaf62fffSJeremy L Thompson ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); 753eaf62fffSJeremy L Thompson CeedChk(ierr); 754eaf62fffSJeremy L Thompson switch (eval_mode) { 755eaf62fffSJeremy L Thompson case CEED_EVAL_NONE: 756eaf62fffSJeremy L Thompson case CEED_EVAL_INTERP: 757eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_out + 1, &eval_mode_out); CeedChk(ierr); 758eaf62fffSJeremy L Thompson eval_mode_out[num_eval_mode_out] = eval_mode; 759eaf62fffSJeremy L Thompson num_eval_mode_out += 1; 760eaf62fffSJeremy L Thompson break; 761eaf62fffSJeremy L Thompson case CEED_EVAL_GRAD: 762eaf62fffSJeremy L Thompson ierr = CeedRealloc(num_eval_mode_out + dim, &eval_mode_out); CeedChk(ierr); 763eaf62fffSJeremy L Thompson for (CeedInt d=0; d<dim; d++) { 764eaf62fffSJeremy L Thompson eval_mode_out[num_eval_mode_out+d] = eval_mode; 765eaf62fffSJeremy L Thompson } 766eaf62fffSJeremy L Thompson num_eval_mode_out += dim; 767eaf62fffSJeremy L Thompson break; 768eaf62fffSJeremy L Thompson case CEED_EVAL_WEIGHT: 769eaf62fffSJeremy L Thompson case CEED_EVAL_DIV: 770eaf62fffSJeremy L Thompson case CEED_EVAL_CURL: 771eaf62fffSJeremy L Thompson break; // Caught by QF Assembly 772eaf62fffSJeremy L Thompson } 773eaf62fffSJeremy L Thompson } 774eaf62fffSJeremy L Thompson } 775eaf62fffSJeremy L Thompson 776eaf62fffSJeremy L Thompson if (num_eval_mode_in == 0 || num_eval_mode_out == 0) 777eaf62fffSJeremy L Thompson // LCOV_EXCL_START 778eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 779eaf62fffSJeremy L Thompson "Cannot assemble operator with out inputs/outputs"); 780eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 781eaf62fffSJeremy L Thompson 782eaf62fffSJeremy L Thompson CeedInt num_elem, elem_size, num_qpts, num_comp; 783eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(rstr_in, &num_elem); CeedChk(ierr); 784eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr_in, &elem_size); CeedChk(ierr); 785eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumComponents(rstr_in, &num_comp); CeedChk(ierr); 786eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts); CeedChk(ierr); 787eaf62fffSJeremy L Thompson 788eaf62fffSJeremy L Thompson CeedInt local_num_entries = elem_size*num_comp * elem_size*num_comp * num_elem; 789eaf62fffSJeremy L Thompson 790eaf62fffSJeremy L Thompson // loop over elements and put in data structure 791eaf62fffSJeremy L Thompson const CeedScalar *interp_in, *grad_in; 792eaf62fffSJeremy L Thompson ierr = CeedBasisGetInterp(basis_in, &interp_in); CeedChk(ierr); 793eaf62fffSJeremy L Thompson ierr = CeedBasisGetGrad(basis_in, &grad_in); CeedChk(ierr); 794eaf62fffSJeremy L Thompson 795eaf62fffSJeremy L Thompson const CeedScalar *assembled_qf_array; 796eaf62fffSJeremy L Thompson ierr = CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array); 797eaf62fffSJeremy L Thompson CeedChk(ierr); 798eaf62fffSJeremy L Thompson 799eaf62fffSJeremy L Thompson CeedInt layout_qf[3]; 800eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetELayout(rstr_q, &layout_qf); CeedChk(ierr); 801eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr_q); CeedChk(ierr); 802eaf62fffSJeremy L Thompson 803eaf62fffSJeremy L Thompson // we store B_mat_in, B_mat_out, BTD, elem_mat in row-major order 804eaf62fffSJeremy L Thompson CeedScalar B_mat_in[(num_qpts * num_eval_mode_in) * elem_size]; 805eaf62fffSJeremy L Thompson CeedScalar B_mat_out[(num_qpts * num_eval_mode_out) * elem_size]; 806eaf62fffSJeremy L Thompson CeedScalar D_mat[num_eval_mode_out * num_eval_mode_in * 807eaf62fffSJeremy L Thompson num_qpts]; // logically 3-tensor 808eaf62fffSJeremy L Thompson CeedScalar BTD[elem_size * num_qpts*num_eval_mode_in]; 809eaf62fffSJeremy L Thompson CeedScalar elem_mat[elem_size * elem_size]; 81092ae7e47SJeremy L Thompson CeedInt count = 0; 811eaf62fffSJeremy L Thompson CeedScalar *vals; 8129c774eddSJeremy L Thompson ierr = CeedVectorGetArrayWrite(values, CEED_MEM_HOST, &vals); CeedChk(ierr); 81392ae7e47SJeremy L Thompson for (CeedInt e = 0; e < num_elem; ++e) { 81492ae7e47SJeremy L Thompson for (CeedInt comp_in = 0; comp_in < num_comp; ++comp_in) { 81592ae7e47SJeremy L Thompson for (CeedInt comp_out = 0; comp_out < num_comp; ++comp_out) { 81692ae7e47SJeremy L Thompson for (CeedInt ell = 0; ell < (num_qpts * num_eval_mode_in) * elem_size; ++ell) { 817eaf62fffSJeremy L Thompson B_mat_in[ell] = 0.0; 818eaf62fffSJeremy L Thompson } 81992ae7e47SJeremy L Thompson for (CeedInt ell = 0; ell < (num_qpts * num_eval_mode_out) * elem_size; ++ell) { 820eaf62fffSJeremy L Thompson B_mat_out[ell] = 0.0; 821eaf62fffSJeremy L Thompson } 822eaf62fffSJeremy L Thompson // Store block-diagonal D matrix as collection of small dense blocks 82321d1e94bSJeremy L Thompson for (CeedInt ell = 0; ell < num_eval_mode_in*num_eval_mode_out*num_qpts; 82421d1e94bSJeremy L Thompson ++ell) { 825eaf62fffSJeremy L Thompson D_mat[ell] = 0.0; 826eaf62fffSJeremy L Thompson } 827eaf62fffSJeremy L Thompson // form element matrix itself (for each block component) 82892ae7e47SJeremy L Thompson for (CeedInt ell = 0; ell < elem_size*elem_size; ++ell) { 829eaf62fffSJeremy L Thompson elem_mat[ell] = 0.0; 830eaf62fffSJeremy L Thompson } 83192ae7e47SJeremy L Thompson for (CeedInt q = 0; q < num_qpts; ++q) { 83292ae7e47SJeremy L Thompson for (CeedInt n = 0; n < elem_size; ++n) { 833eaf62fffSJeremy L Thompson CeedInt d_in = -1; 83492ae7e47SJeremy L Thompson for (CeedInt e_in = 0; e_in < num_eval_mode_in; ++e_in) { 83592ae7e47SJeremy L Thompson const CeedInt qq = num_eval_mode_in*q; 836eaf62fffSJeremy L Thompson if (eval_mode_in[e_in] == CEED_EVAL_INTERP) { 837eaf62fffSJeremy L Thompson B_mat_in[(qq+e_in)*elem_size + n] += interp_in[q * elem_size + n]; 838eaf62fffSJeremy L Thompson } else if (eval_mode_in[e_in] == CEED_EVAL_GRAD) { 839eaf62fffSJeremy L Thompson d_in += 1; 840eaf62fffSJeremy L Thompson B_mat_in[(qq+e_in)*elem_size + n] += 841eaf62fffSJeremy L Thompson grad_in[(d_in*num_qpts+q) * elem_size + n]; 842eaf62fffSJeremy L Thompson } else { 843eaf62fffSJeremy L Thompson // LCOV_EXCL_START 844eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!"); 845eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 846eaf62fffSJeremy L Thompson } 847eaf62fffSJeremy L Thompson } 848eaf62fffSJeremy L Thompson CeedInt d_out = -1; 84992ae7e47SJeremy L Thompson for (CeedInt e_out = 0; e_out < num_eval_mode_out; ++e_out) { 85092ae7e47SJeremy L Thompson const CeedInt qq = num_eval_mode_out*q; 851eaf62fffSJeremy L Thompson if (eval_mode_out[e_out] == CEED_EVAL_INTERP) { 852eaf62fffSJeremy L Thompson B_mat_out[(qq+e_out)*elem_size + n] += interp_in[q * elem_size + n]; 853eaf62fffSJeremy L Thompson } else if (eval_mode_out[e_out] == CEED_EVAL_GRAD) { 854eaf62fffSJeremy L Thompson d_out += 1; 855eaf62fffSJeremy L Thompson B_mat_out[(qq+e_out)*elem_size + n] += 856eaf62fffSJeremy L Thompson grad_in[(d_out*num_qpts+q) * elem_size + n]; 857eaf62fffSJeremy L Thompson } else { 858eaf62fffSJeremy L Thompson // LCOV_EXCL_START 859eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!"); 860eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 861eaf62fffSJeremy L Thompson } 862eaf62fffSJeremy L Thompson } 863eaf62fffSJeremy L Thompson } 86492ae7e47SJeremy L Thompson for (CeedInt ei = 0; ei < num_eval_mode_out; ++ei) { 86592ae7e47SJeremy L Thompson for (CeedInt ej = 0; ej < num_eval_mode_in; ++ej) { 86621d1e94bSJeremy L Thompson const CeedInt eval_mode_index = ((ei*num_comp+comp_in)*num_eval_mode_in+ej) 86721d1e94bSJeremy L Thompson *num_comp 868eaf62fffSJeremy L Thompson +comp_out; 86992ae7e47SJeremy L Thompson const CeedInt index = q*layout_qf[0] + eval_mode_index*layout_qf[1] + 870eaf62fffSJeremy L Thompson e*layout_qf[2]; 871eaf62fffSJeremy L Thompson D_mat[(ei*num_eval_mode_in+ej)*num_qpts + q] += assembled_qf_array[index]; 872eaf62fffSJeremy L Thompson } 873eaf62fffSJeremy L Thompson } 874eaf62fffSJeremy L Thompson } 875eaf62fffSJeremy L Thompson // Compute B^T*D 87692ae7e47SJeremy L Thompson for (CeedInt ell = 0; ell < elem_size*num_qpts*num_eval_mode_in; ++ell) { 877eaf62fffSJeremy L Thompson BTD[ell] = 0.0; 878eaf62fffSJeremy L Thompson } 87992ae7e47SJeremy L Thompson for (CeedInt j = 0; j<elem_size; ++j) { 88092ae7e47SJeremy L Thompson for (CeedInt q = 0; q<num_qpts; ++q) { 88192ae7e47SJeremy L Thompson const CeedInt qq = num_eval_mode_out*q; 88292ae7e47SJeremy L Thompson for (CeedInt ei = 0; ei < num_eval_mode_in; ++ei) { 88392ae7e47SJeremy L Thompson for (CeedInt ej = 0; ej < num_eval_mode_out; ++ej) { 884eaf62fffSJeremy L Thompson BTD[j*(num_qpts*num_eval_mode_in) + (qq+ei)] += 885eaf62fffSJeremy L Thompson B_mat_out[(qq+ej)*elem_size + j] * D_mat[(ei*num_eval_mode_in+ej)*num_qpts + q]; 886eaf62fffSJeremy L Thompson } 887eaf62fffSJeremy L Thompson } 888eaf62fffSJeremy L Thompson } 889eaf62fffSJeremy L Thompson } 890eaf62fffSJeremy L Thompson 891eaf62fffSJeremy L Thompson ierr = CeedMatrixMultiply(ceed, BTD, B_mat_in, elem_mat, elem_size, 892eaf62fffSJeremy L Thompson elem_size, num_qpts*num_eval_mode_in); CeedChk(ierr); 893eaf62fffSJeremy L Thompson 894eaf62fffSJeremy L Thompson // put element matrix in coordinate data structure 89592ae7e47SJeremy L Thompson for (CeedInt i = 0; i < elem_size; ++i) { 89692ae7e47SJeremy L Thompson for (CeedInt j = 0; j < elem_size; ++j) { 897eaf62fffSJeremy L Thompson vals[offset + count] = elem_mat[i*elem_size + j]; 898eaf62fffSJeremy L Thompson count++; 899eaf62fffSJeremy L Thompson } 900eaf62fffSJeremy L Thompson } 901eaf62fffSJeremy L Thompson } 902eaf62fffSJeremy L Thompson } 903eaf62fffSJeremy L Thompson } 904eaf62fffSJeremy L Thompson if (count != local_num_entries) 905eaf62fffSJeremy L Thompson // LCOV_EXCL_START 906eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing entries"); 907eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 908eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArray(values, &vals); CeedChk(ierr); 909eaf62fffSJeremy L Thompson 910eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array); 911eaf62fffSJeremy L Thompson CeedChk(ierr); 912eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&assembled_qf); CeedChk(ierr); 913eaf62fffSJeremy L Thompson ierr = CeedFree(&eval_mode_in); CeedChk(ierr); 914eaf62fffSJeremy L Thompson ierr = CeedFree(&eval_mode_out); CeedChk(ierr); 915eaf62fffSJeremy L Thompson 916eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 917eaf62fffSJeremy L Thompson } 918eaf62fffSJeremy L Thompson 919eaf62fffSJeremy L Thompson /** 920eaf62fffSJeremy L Thompson @brief Count number of entries for assembled CeedOperator 921eaf62fffSJeremy L Thompson 922eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 923eaf62fffSJeremy L Thompson @param[out] num_entries Number of entries in assembled representation 924eaf62fffSJeremy L Thompson 925eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 926eaf62fffSJeremy L Thompson 927eaf62fffSJeremy L Thompson @ref Utility 928eaf62fffSJeremy L Thompson **/ 929eaf62fffSJeremy L Thompson static int CeedSingleOperatorAssemblyCountEntries(CeedOperator op, 930eaf62fffSJeremy L Thompson CeedInt *num_entries) { 931eaf62fffSJeremy L Thompson int ierr; 932eaf62fffSJeremy L Thompson CeedElemRestriction rstr; 933eaf62fffSJeremy L Thompson CeedInt num_elem, elem_size, num_comp; 934eaf62fffSJeremy L Thompson 935f04ea552SJeremy L Thompson if (op->is_composite) 936eaf62fffSJeremy L Thompson // LCOV_EXCL_START 937eaf62fffSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 938eaf62fffSJeremy L Thompson "Composite operator not supported"); 939eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 940eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveElemRestriction(op, &rstr); CeedChk(ierr); 941eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr); 942eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr, &elem_size); CeedChk(ierr); 943eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumComponents(rstr, &num_comp); CeedChk(ierr); 944eaf62fffSJeremy L Thompson *num_entries = elem_size*num_comp * elem_size*num_comp * num_elem; 945eaf62fffSJeremy L Thompson 946eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 947eaf62fffSJeremy L Thompson } 948eaf62fffSJeremy L Thompson 949eaf62fffSJeremy L Thompson /** 950eaf62fffSJeremy L Thompson @brief Common code for creating a multigrid coarse operator and level 951eaf62fffSJeremy L Thompson transfer operators for a CeedOperator 952eaf62fffSJeremy L Thompson 953eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 954eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 955eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 956eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 957eaf62fffSJeremy L Thompson @param[in] basis_c_to_f Basis for coarse to fine interpolation 958eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 959eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 960eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 961eaf62fffSJeremy L Thompson 962eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 963eaf62fffSJeremy L Thompson 964eaf62fffSJeremy L Thompson @ref Developer 965eaf62fffSJeremy L Thompson **/ 966eaf62fffSJeremy L Thompson static int CeedSingleOperatorMultigridLevel(CeedOperator op_fine, 967eaf62fffSJeremy L Thompson CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 968eaf62fffSJeremy L Thompson CeedBasis basis_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong, 969eaf62fffSJeremy L Thompson CeedOperator *op_restrict) { 970eaf62fffSJeremy L Thompson int ierr; 971eaf62fffSJeremy L Thompson Ceed ceed; 972eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr); 973eaf62fffSJeremy L Thompson 974eaf62fffSJeremy L Thompson // Check for composite operator 975eaf62fffSJeremy L Thompson bool is_composite; 976eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op_fine, &is_composite); CeedChk(ierr); 977eaf62fffSJeremy L Thompson if (is_composite) 978eaf62fffSJeremy L Thompson // LCOV_EXCL_START 979eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 980eaf62fffSJeremy L Thompson "Automatic multigrid setup for composite operators not supported"); 981eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 982eaf62fffSJeremy L Thompson 983eaf62fffSJeremy L Thompson // Coarse Grid 984eaf62fffSJeremy L Thompson ierr = CeedOperatorCreate(ceed, op_fine->qf, op_fine->dqf, op_fine->dqfT, 985eaf62fffSJeremy L Thompson op_coarse); CeedChk(ierr); 986eaf62fffSJeremy L Thompson CeedElemRestriction rstr_fine = NULL; 987eaf62fffSJeremy L Thompson // -- Clone input fields 98892ae7e47SJeremy L Thompson for (CeedInt i = 0; i < op_fine->qf->num_input_fields; i++) { 989eaf62fffSJeremy L Thompson if (op_fine->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 990eaf62fffSJeremy L Thompson rstr_fine = op_fine->input_fields[i]->elem_restr; 991eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name, 992eaf62fffSJeremy L Thompson rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE); 993eaf62fffSJeremy L Thompson CeedChk(ierr); 994eaf62fffSJeremy L Thompson } else { 995eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name, 996eaf62fffSJeremy L Thompson op_fine->input_fields[i]->elem_restr, 997eaf62fffSJeremy L Thompson op_fine->input_fields[i]->basis, 998eaf62fffSJeremy L Thompson op_fine->input_fields[i]->vec); CeedChk(ierr); 999eaf62fffSJeremy L Thompson } 1000eaf62fffSJeremy L Thompson } 1001eaf62fffSJeremy L Thompson // -- Clone output fields 100292ae7e47SJeremy L Thompson for (CeedInt i = 0; i < op_fine->qf->num_output_fields; i++) { 1003eaf62fffSJeremy L Thompson if (op_fine->output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1004eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name, 1005eaf62fffSJeremy L Thompson rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE); 1006eaf62fffSJeremy L Thompson CeedChk(ierr); 1007eaf62fffSJeremy L Thompson } else { 1008eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name, 1009eaf62fffSJeremy L Thompson op_fine->output_fields[i]->elem_restr, 1010eaf62fffSJeremy L Thompson op_fine->output_fields[i]->basis, 1011eaf62fffSJeremy L Thompson op_fine->output_fields[i]->vec); CeedChk(ierr); 1012eaf62fffSJeremy L Thompson } 1013eaf62fffSJeremy L Thompson } 1014af99e877SJeremy L Thompson // -- Clone QFunctionAssemblyData 1015af99e877SJeremy L Thompson ierr = CeedQFunctionAssemblyDataReferenceCopy(op_fine->qf_assembled, 1016af99e877SJeremy L Thompson &(*op_coarse)->qf_assembled); CeedChk(ierr); 1017eaf62fffSJeremy L Thompson 1018eaf62fffSJeremy L Thompson // Multiplicity vector 1019eaf62fffSJeremy L Thompson CeedVector mult_vec, mult_e_vec; 1020eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionCreateVector(rstr_fine, &mult_vec, &mult_e_vec); 1021eaf62fffSJeremy L Thompson CeedChk(ierr); 1022eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(mult_e_vec, 0.0); CeedChk(ierr); 1023eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionApply(rstr_fine, CEED_NOTRANSPOSE, p_mult_fine, 1024eaf62fffSJeremy L Thompson mult_e_vec, CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 1025eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(mult_vec, 0.0); CeedChk(ierr); 1026eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionApply(rstr_fine, CEED_TRANSPOSE, mult_e_vec, mult_vec, 1027eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 1028eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&mult_e_vec); CeedChk(ierr); 1029eaf62fffSJeremy L Thompson ierr = CeedVectorReciprocal(mult_vec); CeedChk(ierr); 1030eaf62fffSJeremy L Thompson 1031eaf62fffSJeremy L Thompson // Restriction 1032eaf62fffSJeremy L Thompson CeedInt num_comp; 1033eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis_coarse, &num_comp); CeedChk(ierr); 1034eaf62fffSJeremy L Thompson CeedQFunction qf_restrict; 1035eaf62fffSJeremy L Thompson ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_restrict); 1036eaf62fffSJeremy L Thompson CeedChk(ierr); 1037eaf62fffSJeremy L Thompson CeedInt *num_comp_r_data; 1038eaf62fffSJeremy L Thompson ierr = CeedCalloc(1, &num_comp_r_data); CeedChk(ierr); 1039eaf62fffSJeremy L Thompson num_comp_r_data[0] = num_comp; 1040eaf62fffSJeremy L Thompson CeedQFunctionContext ctx_r; 1041eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextCreate(ceed, &ctx_r); CeedChk(ierr); 1042eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextSetData(ctx_r, CEED_MEM_HOST, CEED_OWN_POINTER, 1043eaf62fffSJeremy L Thompson sizeof(*num_comp_r_data), num_comp_r_data); 1044eaf62fffSJeremy L Thompson CeedChk(ierr); 1045eaf62fffSJeremy L Thompson ierr = CeedQFunctionSetContext(qf_restrict, ctx_r); CeedChk(ierr); 1046eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextDestroy(&ctx_r); CeedChk(ierr); 1047eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_restrict, "input", num_comp, CEED_EVAL_NONE); 1048eaf62fffSJeremy L Thompson CeedChk(ierr); 1049eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_restrict, "scale", num_comp, CEED_EVAL_NONE); 1050eaf62fffSJeremy L Thompson CeedChk(ierr); 1051eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddOutput(qf_restrict, "output", num_comp, 1052eaf62fffSJeremy L Thompson CEED_EVAL_INTERP); CeedChk(ierr); 10536e15d496SJeremy L Thompson ierr = CeedQFunctionSetUserFlopsEstimate(qf_restrict, num_comp); CeedChk(ierr); 1054eaf62fffSJeremy L Thompson 1055eaf62fffSJeremy L Thompson ierr = CeedOperatorCreate(ceed, qf_restrict, CEED_QFUNCTION_NONE, 1056eaf62fffSJeremy L Thompson CEED_QFUNCTION_NONE, op_restrict); 1057eaf62fffSJeremy L Thompson CeedChk(ierr); 1058eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_restrict, "input", rstr_fine, 1059eaf62fffSJeremy L Thompson CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 1060eaf62fffSJeremy L Thompson CeedChk(ierr); 1061eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_restrict, "scale", rstr_fine, 1062eaf62fffSJeremy L Thompson CEED_BASIS_COLLOCATED, mult_vec); 1063eaf62fffSJeremy L Thompson CeedChk(ierr); 1064eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_restrict, "output", rstr_coarse, basis_c_to_f, 1065eaf62fffSJeremy L Thompson CEED_VECTOR_ACTIVE); CeedChk(ierr); 1066eaf62fffSJeremy L Thompson 1067eaf62fffSJeremy L Thompson // Prolongation 1068eaf62fffSJeremy L Thompson CeedQFunction qf_prolong; 1069eaf62fffSJeremy L Thompson ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_prolong); 1070eaf62fffSJeremy L Thompson CeedChk(ierr); 1071eaf62fffSJeremy L Thompson CeedInt *num_comp_p_data; 1072eaf62fffSJeremy L Thompson ierr = CeedCalloc(1, &num_comp_p_data); CeedChk(ierr); 1073eaf62fffSJeremy L Thompson num_comp_p_data[0] = num_comp; 1074eaf62fffSJeremy L Thompson CeedQFunctionContext ctx_p; 1075eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextCreate(ceed, &ctx_p); CeedChk(ierr); 1076eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextSetData(ctx_p, CEED_MEM_HOST, CEED_OWN_POINTER, 1077eaf62fffSJeremy L Thompson sizeof(*num_comp_p_data), num_comp_p_data); 1078eaf62fffSJeremy L Thompson CeedChk(ierr); 1079eaf62fffSJeremy L Thompson ierr = CeedQFunctionSetContext(qf_prolong, ctx_p); CeedChk(ierr); 1080eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextDestroy(&ctx_p); CeedChk(ierr); 1081eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_prolong, "input", num_comp, CEED_EVAL_INTERP); 1082eaf62fffSJeremy L Thompson CeedChk(ierr); 1083eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_prolong, "scale", num_comp, CEED_EVAL_NONE); 1084eaf62fffSJeremy L Thompson CeedChk(ierr); 1085eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddOutput(qf_prolong, "output", num_comp, CEED_EVAL_NONE); 1086eaf62fffSJeremy L Thompson CeedChk(ierr); 10876e15d496SJeremy L Thompson ierr = CeedQFunctionSetUserFlopsEstimate(qf_prolong, num_comp); CeedChk(ierr); 1088eaf62fffSJeremy L Thompson 1089eaf62fffSJeremy L Thompson ierr = CeedOperatorCreate(ceed, qf_prolong, CEED_QFUNCTION_NONE, 1090eaf62fffSJeremy L Thompson CEED_QFUNCTION_NONE, op_prolong); 1091eaf62fffSJeremy L Thompson CeedChk(ierr); 1092eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_prolong, "input", rstr_coarse, basis_c_to_f, 1093eaf62fffSJeremy L Thompson CEED_VECTOR_ACTIVE); CeedChk(ierr); 1094eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_prolong, "scale", rstr_fine, 1095eaf62fffSJeremy L Thompson CEED_BASIS_COLLOCATED, mult_vec); 1096eaf62fffSJeremy L Thompson CeedChk(ierr); 1097eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_prolong, "output", rstr_fine, 1098eaf62fffSJeremy L Thompson CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 1099eaf62fffSJeremy L Thompson CeedChk(ierr); 1100eaf62fffSJeremy L Thompson 1101ea6b5821SJeremy L Thompson // Clone name 1102ea6b5821SJeremy L Thompson bool has_name = op_fine->name; 1103ea6b5821SJeremy L Thompson size_t name_len = op_fine->name ? strlen(op_fine->name) : 0; 1104ea6b5821SJeremy L Thompson ierr = CeedOperatorSetName(*op_coarse, op_fine->name); CeedChk(ierr); 1105ea6b5821SJeremy L Thompson { 1106ea6b5821SJeremy L Thompson char *prolongation_name; 1107ea6b5821SJeremy L Thompson ierr = CeedCalloc(18 + name_len, &prolongation_name); CeedChk(ierr); 1108ea6b5821SJeremy L Thompson sprintf(prolongation_name, "prolongation%s%s", has_name ? " for " : "", 11093129f025Srezgarshakeri has_name ? op_fine->name : ""); 1110ea6b5821SJeremy L Thompson ierr = CeedOperatorSetName(*op_prolong, prolongation_name); CeedChk(ierr); 1111ea6b5821SJeremy L Thompson ierr = CeedFree(&prolongation_name); CeedChk(ierr); 1112ea6b5821SJeremy L Thompson } 1113ea6b5821SJeremy L Thompson { 1114ea6b5821SJeremy L Thompson char *restriction_name; 1115ea6b5821SJeremy L Thompson ierr = CeedCalloc(17 + name_len, &restriction_name); CeedChk(ierr); 1116ea6b5821SJeremy L Thompson sprintf(restriction_name, "restriction%s%s", has_name ? " for " : "", 11173129f025Srezgarshakeri has_name ? op_fine->name : ""); 1118ea6b5821SJeremy L Thompson ierr = CeedOperatorSetName(*op_restrict, restriction_name); CeedChk(ierr); 1119ea6b5821SJeremy L Thompson ierr = CeedFree(&restriction_name); CeedChk(ierr); 1120ea6b5821SJeremy L Thompson } 1121ea6b5821SJeremy L Thompson 1122eaf62fffSJeremy L Thompson // Cleanup 1123eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&mult_vec); CeedChk(ierr); 1124eaf62fffSJeremy L Thompson ierr = CeedBasisDestroy(&basis_c_to_f); CeedChk(ierr); 1125eaf62fffSJeremy L Thompson ierr = CeedQFunctionDestroy(&qf_restrict); CeedChk(ierr); 1126eaf62fffSJeremy L Thompson ierr = CeedQFunctionDestroy(&qf_prolong); CeedChk(ierr); 1127805fe78eSJeremy L Thompson 1128eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1129eaf62fffSJeremy L Thompson } 1130eaf62fffSJeremy L Thompson 1131eaf62fffSJeremy L Thompson /** 1132eaf62fffSJeremy L Thompson @brief Build 1D mass matrix and Laplacian with perturbation 1133eaf62fffSJeremy L Thompson 1134eaf62fffSJeremy L Thompson @param[in] interp_1d Interpolation matrix in one dimension 1135eaf62fffSJeremy L Thompson @param[in] grad_1d Gradient matrix in one dimension 1136eaf62fffSJeremy L Thompson @param[in] q_weight_1d Quadrature weights in one dimension 1137eaf62fffSJeremy L Thompson @param[in] P_1d Number of basis nodes in one dimension 1138eaf62fffSJeremy L Thompson @param[in] Q_1d Number of quadrature points in one dimension 1139eaf62fffSJeremy L Thompson @param[in] dim Dimension of basis 1140eaf62fffSJeremy L Thompson @param[out] mass Assembled mass matrix in one dimension 1141eaf62fffSJeremy L Thompson @param[out] laplace Assembled perturbed Laplacian in one dimension 1142eaf62fffSJeremy L Thompson 1143eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1144eaf62fffSJeremy L Thompson 1145eaf62fffSJeremy L Thompson @ref Developer 1146eaf62fffSJeremy L Thompson **/ 1147eaf62fffSJeremy L Thompson CeedPragmaOptimizeOff 1148eaf62fffSJeremy L Thompson static int CeedBuildMassLaplace(const CeedScalar *interp_1d, 1149eaf62fffSJeremy L Thompson const CeedScalar *grad_1d, 1150eaf62fffSJeremy L Thompson const CeedScalar *q_weight_1d, CeedInt P_1d, 1151eaf62fffSJeremy L Thompson CeedInt Q_1d, CeedInt dim, 1152eaf62fffSJeremy L Thompson CeedScalar *mass, CeedScalar *laplace) { 1153eaf62fffSJeremy L Thompson 1154eaf62fffSJeremy L Thompson for (CeedInt i=0; i<P_1d; i++) 1155eaf62fffSJeremy L Thompson for (CeedInt j=0; j<P_1d; j++) { 1156eaf62fffSJeremy L Thompson CeedScalar sum = 0.0; 1157eaf62fffSJeremy L Thompson for (CeedInt k=0; k<Q_1d; k++) 1158eaf62fffSJeremy L Thompson sum += interp_1d[k*P_1d+i]*q_weight_1d[k]*interp_1d[k*P_1d+j]; 1159eaf62fffSJeremy L Thompson mass[i+j*P_1d] = sum; 1160eaf62fffSJeremy L Thompson } 1161eaf62fffSJeremy L Thompson // -- Laplacian 1162eaf62fffSJeremy L Thompson for (CeedInt i=0; i<P_1d; i++) 1163eaf62fffSJeremy L Thompson for (CeedInt j=0; j<P_1d; j++) { 1164eaf62fffSJeremy L Thompson CeedScalar sum = 0.0; 1165eaf62fffSJeremy L Thompson for (CeedInt k=0; k<Q_1d; k++) 1166eaf62fffSJeremy L Thompson sum += grad_1d[k*P_1d+i]*q_weight_1d[k]*grad_1d[k*P_1d+j]; 1167eaf62fffSJeremy L Thompson laplace[i+j*P_1d] = sum; 1168eaf62fffSJeremy L Thompson } 1169eaf62fffSJeremy L Thompson CeedScalar perturbation = dim>2 ? 1e-6 : 1e-4; 1170eaf62fffSJeremy L Thompson for (CeedInt i=0; i<P_1d; i++) 1171eaf62fffSJeremy L Thompson laplace[i+P_1d*i] += perturbation; 1172eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1173eaf62fffSJeremy L Thompson } 1174eaf62fffSJeremy L Thompson CeedPragmaOptimizeOn 1175eaf62fffSJeremy L Thompson 1176eaf62fffSJeremy L Thompson /// @} 1177eaf62fffSJeremy L Thompson 1178eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 1179480fae85SJeremy L Thompson /// CeedOperator Backend API 1180480fae85SJeremy L Thompson /// ---------------------------------------------------------------------------- 1181480fae85SJeremy L Thompson /// @addtogroup CeedOperatorBackend 1182480fae85SJeremy L Thompson /// @{ 1183480fae85SJeremy L Thompson 1184480fae85SJeremy L Thompson /** 1185480fae85SJeremy L Thompson @brief Create object holding CeedQFunction assembly data for CeedOperator 1186480fae85SJeremy L Thompson 1187480fae85SJeremy L Thompson @param[in] ceed A Ceed object where the CeedQFunctionAssemblyData will be created 1188480fae85SJeremy L Thompson @param[out] data Address of the variable where the newly created 1189480fae85SJeremy L Thompson CeedQFunctionAssemblyData will be stored 1190480fae85SJeremy L Thompson 1191480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1192480fae85SJeremy L Thompson 1193480fae85SJeremy L Thompson @ref Backend 1194480fae85SJeremy L Thompson **/ 1195480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataCreate(Ceed ceed, 1196480fae85SJeremy L Thompson CeedQFunctionAssemblyData *data) { 1197480fae85SJeremy L Thompson int ierr; 1198480fae85SJeremy L Thompson 1199480fae85SJeremy L Thompson ierr = CeedCalloc(1, data); CeedChk(ierr); 1200480fae85SJeremy L Thompson (*data)->ref_count = 1; 1201480fae85SJeremy L Thompson (*data)->ceed = ceed; 1202480fae85SJeremy L Thompson ierr = CeedReference(ceed); CeedChk(ierr); 1203480fae85SJeremy L Thompson 1204480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1205480fae85SJeremy L Thompson } 1206480fae85SJeremy L Thompson 1207480fae85SJeremy L Thompson /** 1208480fae85SJeremy L Thompson @brief Increment the reference counter for a CeedQFunctionAssemblyData 1209480fae85SJeremy L Thompson 1210480fae85SJeremy L Thompson @param data CeedQFunctionAssemblyData to increment the reference counter 1211480fae85SJeremy L Thompson 1212480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1213480fae85SJeremy L Thompson 1214480fae85SJeremy L Thompson @ref Backend 1215480fae85SJeremy L Thompson **/ 1216480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataReference(CeedQFunctionAssemblyData data) { 1217480fae85SJeremy L Thompson data->ref_count++; 1218480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1219480fae85SJeremy L Thompson } 1220480fae85SJeremy L Thompson 1221480fae85SJeremy L Thompson /** 1222beecbf24SJeremy L Thompson @brief Set re-use of CeedQFunctionAssemblyData 12238b919e6bSJeremy L Thompson 1224beecbf24SJeremy L Thompson @param data CeedQFunctionAssemblyData to mark for reuse 1225beecbf24SJeremy L Thompson @param reuse_data Boolean flag indicating data re-use 12268b919e6bSJeremy L Thompson 12278b919e6bSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 12288b919e6bSJeremy L Thompson 12298b919e6bSJeremy L Thompson @ref Backend 12308b919e6bSJeremy L Thompson **/ 1231beecbf24SJeremy L Thompson int CeedQFunctionAssemblyDataSetReuse(CeedQFunctionAssemblyData data, 1232beecbf24SJeremy L Thompson bool reuse_data) { 1233beecbf24SJeremy L Thompson data->reuse_data = reuse_data; 1234beecbf24SJeremy L Thompson data->needs_data_update = true; 1235beecbf24SJeremy L Thompson return CEED_ERROR_SUCCESS; 1236beecbf24SJeremy L Thompson } 1237beecbf24SJeremy L Thompson 1238beecbf24SJeremy L Thompson /** 1239beecbf24SJeremy L Thompson @brief Mark QFunctionAssemblyData as stale 1240beecbf24SJeremy L Thompson 1241beecbf24SJeremy L Thompson @param data CeedQFunctionAssemblyData to mark as stale 1242beecbf24SJeremy L Thompson @param needs_data_update Boolean flag indicating if update is needed or completed 1243beecbf24SJeremy L Thompson 1244beecbf24SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1245beecbf24SJeremy L Thompson 1246beecbf24SJeremy L Thompson @ref Backend 1247beecbf24SJeremy L Thompson **/ 1248beecbf24SJeremy L Thompson int CeedQFunctionAssemblyDataSetUpdateNeeded(CeedQFunctionAssemblyData data, 1249beecbf24SJeremy L Thompson bool needs_data_update) { 1250beecbf24SJeremy L Thompson data->needs_data_update = needs_data_update; 12518b919e6bSJeremy L Thompson return CEED_ERROR_SUCCESS; 12528b919e6bSJeremy L Thompson } 12538b919e6bSJeremy L Thompson 12548b919e6bSJeremy L Thompson /** 12558b919e6bSJeremy L Thompson @brief Determine if QFunctionAssemblyData needs update 12568b919e6bSJeremy L Thompson 12578b919e6bSJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to mark as stale 12588b919e6bSJeremy L Thompson @param[out] is_update_needed Boolean flag indicating if re-assembly is required 12598b919e6bSJeremy L Thompson 12608b919e6bSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 12618b919e6bSJeremy L Thompson 12628b919e6bSJeremy L Thompson @ref Backend 12638b919e6bSJeremy L Thompson **/ 12648b919e6bSJeremy L Thompson int CeedQFunctionAssemblyDataIsUpdateNeeded(CeedQFunctionAssemblyData data, 12658b919e6bSJeremy L Thompson bool *is_update_needed) { 1266beecbf24SJeremy L Thompson *is_update_needed = !data->reuse_data || data->needs_data_update; 12678b919e6bSJeremy L Thompson return CEED_ERROR_SUCCESS; 12688b919e6bSJeremy L Thompson } 12698b919e6bSJeremy L Thompson 12708b919e6bSJeremy L Thompson /** 1271480fae85SJeremy L Thompson @brief Copy the pointer to a CeedQFunctionAssemblyData. Both pointers should 1272480fae85SJeremy L Thompson be destroyed with `CeedCeedQFunctionAssemblyDataDestroy()`; 1273480fae85SJeremy L Thompson Note: If `*data_copy` is non-NULL, then it is assumed that 1274480fae85SJeremy L Thompson `*data_copy` is a pointer to a CeedQFunctionAssemblyData. This 1275480fae85SJeremy L Thompson CeedQFunctionAssemblyData will be destroyed if `*data_copy` is 1276480fae85SJeremy L Thompson the only reference to this CeedQFunctionAssemblyData. 1277480fae85SJeremy L Thompson 1278480fae85SJeremy L Thompson @param data CeedQFunctionAssemblyData to copy reference to 1279480fae85SJeremy L Thompson @param[out] data_copy Variable to store copied reference 1280480fae85SJeremy L Thompson 1281480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1282480fae85SJeremy L Thompson 1283480fae85SJeremy L Thompson @ref Backend 1284480fae85SJeremy L Thompson **/ 1285480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataReferenceCopy(CeedQFunctionAssemblyData data, 1286480fae85SJeremy L Thompson CeedQFunctionAssemblyData *data_copy) { 1287480fae85SJeremy L Thompson int ierr; 1288480fae85SJeremy L Thompson 1289480fae85SJeremy L Thompson ierr = CeedQFunctionAssemblyDataReference(data); CeedChk(ierr); 1290480fae85SJeremy L Thompson ierr = CeedQFunctionAssemblyDataDestroy(data_copy); CeedChk(ierr); 1291480fae85SJeremy L Thompson *data_copy = data; 1292480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1293480fae85SJeremy L Thompson } 1294480fae85SJeremy L Thompson 1295480fae85SJeremy L Thompson /** 1296480fae85SJeremy L Thompson @brief Get setup status for internal objects for CeedQFunctionAssemblyData 1297480fae85SJeremy L Thompson 1298480fae85SJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to retreive status 1299480fae85SJeremy L Thompson @param[out] is_setup Boolean flag for setup status 1300480fae85SJeremy L Thompson 1301480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1302480fae85SJeremy L Thompson 1303480fae85SJeremy L Thompson @ref Backend 1304480fae85SJeremy L Thompson **/ 1305480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataIsSetup(CeedQFunctionAssemblyData data, 1306480fae85SJeremy L Thompson bool *is_setup) { 1307480fae85SJeremy L Thompson *is_setup = data->is_setup; 1308480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1309480fae85SJeremy L Thompson } 1310480fae85SJeremy L Thompson 1311480fae85SJeremy L Thompson /** 1312480fae85SJeremy L Thompson @brief Set internal objects for CeedQFunctionAssemblyData 1313480fae85SJeremy L Thompson 1314480fae85SJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to set objects 1315480fae85SJeremy L Thompson @param[in] vec CeedVector to store assembled CeedQFunction at quadrature points 1316480fae85SJeremy L Thompson @param[in] rstr CeedElemRestriction for CeedVector containing assembled CeedQFunction 1317480fae85SJeremy L Thompson 1318480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1319480fae85SJeremy L Thompson 1320480fae85SJeremy L Thompson @ref Backend 1321480fae85SJeremy L Thompson **/ 1322480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataSetObjects(CeedQFunctionAssemblyData data, 1323480fae85SJeremy L Thompson CeedVector vec, CeedElemRestriction rstr) { 1324480fae85SJeremy L Thompson int ierr; 1325480fae85SJeremy L Thompson 13262efa2d85SJeremy L Thompson ierr = CeedVectorReferenceCopy(vec, &data->vec); CeedChk(ierr); 13272efa2d85SJeremy L Thompson ierr = CeedElemRestrictionReferenceCopy(rstr, &data->rstr); CeedChk(ierr); 1328480fae85SJeremy L Thompson 1329480fae85SJeremy L Thompson data->is_setup = true; 1330480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1331480fae85SJeremy L Thompson } 1332480fae85SJeremy L Thompson 1333480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataGetObjects(CeedQFunctionAssemblyData data, 1334480fae85SJeremy L Thompson CeedVector *vec, CeedElemRestriction *rstr) { 13352efa2d85SJeremy L Thompson int ierr; 13362efa2d85SJeremy L Thompson 1337480fae85SJeremy L Thompson if (!data->is_setup) 1338480fae85SJeremy L Thompson // LCOV_EXCL_START 1339480fae85SJeremy L Thompson return CeedError(data->ceed, CEED_ERROR_INCOMPLETE, 1340480fae85SJeremy L Thompson "Internal objects not set; must call CeedQFunctionAssemblyDataSetObjects first."); 1341480fae85SJeremy L Thompson // LCOV_EXCL_STOP 1342480fae85SJeremy L Thompson 13432efa2d85SJeremy L Thompson ierr = CeedVectorReferenceCopy(data->vec, vec); CeedChk(ierr); 13442efa2d85SJeremy L Thompson ierr = CeedElemRestrictionReferenceCopy(data->rstr, rstr); CeedChk(ierr); 1345480fae85SJeremy L Thompson 1346480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1347480fae85SJeremy L Thompson } 1348480fae85SJeremy L Thompson 1349480fae85SJeremy L Thompson /** 1350480fae85SJeremy L Thompson @brief Destroy CeedQFunctionAssemblyData 1351480fae85SJeremy L Thompson 1352480fae85SJeremy L Thompson @param[out] data CeedQFunctionAssemblyData to destroy 1353480fae85SJeremy L Thompson 1354480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1355480fae85SJeremy L Thompson 1356480fae85SJeremy L Thompson @ref Backend 1357480fae85SJeremy L Thompson **/ 1358480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataDestroy(CeedQFunctionAssemblyData *data) { 1359480fae85SJeremy L Thompson int ierr; 1360480fae85SJeremy L Thompson 1361480fae85SJeremy L Thompson if (!*data || --(*data)->ref_count > 0) return CEED_ERROR_SUCCESS; 1362480fae85SJeremy L Thompson 1363480fae85SJeremy L Thompson ierr = CeedDestroy(&(*data)->ceed); CeedChk(ierr); 1364480fae85SJeremy L Thompson ierr = CeedVectorDestroy(&(*data)->vec); CeedChk(ierr); 1365480fae85SJeremy L Thompson ierr = CeedElemRestrictionDestroy(&(*data)->rstr); CeedChk(ierr); 1366480fae85SJeremy L Thompson 1367480fae85SJeremy L Thompson ierr = CeedFree(data); CeedChk(ierr); 1368480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1369480fae85SJeremy L Thompson } 1370480fae85SJeremy L Thompson 1371480fae85SJeremy L Thompson /// @} 1372480fae85SJeremy L Thompson 1373480fae85SJeremy L Thompson /// ---------------------------------------------------------------------------- 1374eaf62fffSJeremy L Thompson /// CeedOperator Public API 1375eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 1376eaf62fffSJeremy L Thompson /// @addtogroup CeedOperatorUser 1377eaf62fffSJeremy L Thompson /// @{ 1378eaf62fffSJeremy L Thompson 1379eaf62fffSJeremy L Thompson /** 1380eaf62fffSJeremy L Thompson @brief Assemble a linear CeedQFunction associated with a CeedOperator 1381eaf62fffSJeremy L Thompson 1382eaf62fffSJeremy L Thompson This returns a CeedVector containing a matrix at each quadrature point 1383eaf62fffSJeremy L Thompson providing the action of the CeedQFunction associated with the CeedOperator. 1384eaf62fffSJeremy L Thompson The vector 'assembled' is of shape 1385eaf62fffSJeremy L Thompson [num_elements, num_input_fields, num_output_fields, num_quad_points] 1386eaf62fffSJeremy L Thompson and contains column-major matrices representing the action of the 1387eaf62fffSJeremy L Thompson CeedQFunction for a corresponding quadrature point on an element. Inputs and 1388eaf62fffSJeremy L Thompson outputs are in the order provided by the user when adding CeedOperator fields. 1389eaf62fffSJeremy L Thompson For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and 1390eaf62fffSJeremy L Thompson 'v', provided in that order, would result in an assembled QFunction that 1391eaf62fffSJeremy L Thompson consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting 1392eaf62fffSJeremy L Thompson on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v]. 1393eaf62fffSJeremy L Thompson 1394f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1395f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1396f04ea552SJeremy L Thompson 1397eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1398eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedQFunction at 1399eaf62fffSJeremy L Thompson quadrature points 1400eaf62fffSJeremy L Thompson @param[out] rstr CeedElemRestriction for CeedVector containing assembled 1401eaf62fffSJeremy L Thompson CeedQFunction 1402eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1403eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1404eaf62fffSJeremy L Thompson 1405eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1406eaf62fffSJeremy L Thompson 1407eaf62fffSJeremy L Thompson @ref User 1408eaf62fffSJeremy L Thompson **/ 1409eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled, 1410eaf62fffSJeremy L Thompson CeedElemRestriction *rstr, 1411eaf62fffSJeremy L Thompson CeedRequest *request) { 1412eaf62fffSJeremy L Thompson int ierr; 1413eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1414eaf62fffSJeremy L Thompson 1415eaf62fffSJeremy L Thompson if (op->LinearAssembleQFunction) { 1416d04bbc78SJeremy L Thompson // Backend version 141770a7ffb3SJeremy L Thompson ierr = op->LinearAssembleQFunction(op, assembled, rstr, request); 141870a7ffb3SJeremy L Thompson CeedChk(ierr); 1419eaf62fffSJeremy L Thompson } else { 1420d04bbc78SJeremy L Thompson // Operator fallback 1421d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1422d04bbc78SJeremy L Thompson 1423d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1424d04bbc78SJeremy L Thompson if (op_fallback) { 1425d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunction(op_fallback, assembled, 1426eaf62fffSJeremy L Thompson rstr, request); CeedChk(ierr); 1427d04bbc78SJeremy L Thompson } else { 1428d04bbc78SJeremy L Thompson // LCOV_EXCL_START 1429d04bbc78SJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 1430d04bbc78SJeremy L Thompson "Backend does not support CeedOperatorLinearAssembleQFunction"); 1431d04bbc78SJeremy L Thompson // LCOV_EXCL_STOP 1432d04bbc78SJeremy L Thompson } 143370a7ffb3SJeremy L Thompson } 1434eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1435eaf62fffSJeremy L Thompson } 143670a7ffb3SJeremy L Thompson 143770a7ffb3SJeremy L Thompson /** 143870a7ffb3SJeremy L Thompson @brief Assemble CeedQFunction and store result internall. Return copied 143970a7ffb3SJeremy L Thompson references of stored data to the caller. Caller is responsible for 144070a7ffb3SJeremy L Thompson ownership and destruction of the copied references. See also 144170a7ffb3SJeremy L Thompson @ref CeedOperatorLinearAssembleQFunction 144270a7ffb3SJeremy L Thompson 144370a7ffb3SJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 144470a7ffb3SJeremy L Thompson @param assembled CeedVector to store assembled CeedQFunction at 144570a7ffb3SJeremy L Thompson quadrature points 144670a7ffb3SJeremy L Thompson @param rstr CeedElemRestriction for CeedVector containing assembled 144770a7ffb3SJeremy L Thompson CeedQFunction 144870a7ffb3SJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 144970a7ffb3SJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 145070a7ffb3SJeremy L Thompson 145170a7ffb3SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 145270a7ffb3SJeremy L Thompson 145370a7ffb3SJeremy L Thompson @ref User 145470a7ffb3SJeremy L Thompson **/ 145570a7ffb3SJeremy L Thompson int CeedOperatorLinearAssembleQFunctionBuildOrUpdate(CeedOperator op, 145670a7ffb3SJeremy L Thompson CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) { 145770a7ffb3SJeremy L Thompson int ierr; 145870a7ffb3SJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 145970a7ffb3SJeremy L Thompson 146070a7ffb3SJeremy L Thompson if (op->LinearAssembleQFunctionUpdate) { 1461d04bbc78SJeremy L Thompson // Backend version 1462480fae85SJeremy L Thompson bool qf_assembled_is_setup; 14632efa2d85SJeremy L Thompson CeedVector assembled_vec = NULL; 14642efa2d85SJeremy L Thompson CeedElemRestriction assembled_rstr = NULL; 1465480fae85SJeremy L Thompson 1466480fae85SJeremy L Thompson ierr = CeedQFunctionAssemblyDataIsSetup(op->qf_assembled, 1467480fae85SJeremy L Thompson &qf_assembled_is_setup); CeedChk(ierr); 1468480fae85SJeremy L Thompson if (qf_assembled_is_setup) { 1469d04bbc78SJeremy L Thompson bool update_needed; 1470d04bbc78SJeremy L Thompson 1471480fae85SJeremy L Thompson ierr = CeedQFunctionAssemblyDataGetObjects(op->qf_assembled, &assembled_vec, 1472480fae85SJeremy L Thompson &assembled_rstr); CeedChk(ierr); 14738b919e6bSJeremy L Thompson ierr = CeedQFunctionAssemblyDataIsUpdateNeeded(op->qf_assembled, 14748b919e6bSJeremy L Thompson &update_needed); CeedChk(ierr); 14758b919e6bSJeremy L Thompson if (update_needed) { 1476480fae85SJeremy L Thompson ierr = op->LinearAssembleQFunctionUpdate(op, assembled_vec, assembled_rstr, 1477480fae85SJeremy L Thompson request); CeedChk(ierr); 14788b919e6bSJeremy L Thompson } 147970a7ffb3SJeremy L Thompson } else { 1480480fae85SJeremy L Thompson ierr = op->LinearAssembleQFunction(op, &assembled_vec, &assembled_rstr, 1481480fae85SJeremy L Thompson request); CeedChk(ierr); 1482480fae85SJeremy L Thompson ierr = CeedQFunctionAssemblyDataSetObjects(op->qf_assembled, assembled_vec, 1483480fae85SJeremy L Thompson assembled_rstr); CeedChk(ierr); 148470a7ffb3SJeremy L Thompson } 1485beecbf24SJeremy L Thompson ierr = CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, false); 14868b919e6bSJeremy L Thompson CeedChk(ierr); 14872efa2d85SJeremy L Thompson 1488d04bbc78SJeremy L Thompson // Copy reference from internally held copy 148970a7ffb3SJeremy L Thompson *assembled = NULL; 149070a7ffb3SJeremy L Thompson *rstr = NULL; 1491480fae85SJeremy L Thompson ierr = CeedVectorReferenceCopy(assembled_vec, assembled); CeedChk(ierr); 14922efa2d85SJeremy L Thompson ierr = CeedVectorDestroy(&assembled_vec); CeedChk(ierr); 1493480fae85SJeremy L Thompson ierr = CeedElemRestrictionReferenceCopy(assembled_rstr, rstr); CeedChk(ierr); 14942efa2d85SJeremy L Thompson ierr = CeedElemRestrictionDestroy(&assembled_rstr); CeedChk(ierr); 149570a7ffb3SJeremy L Thompson } else { 1496d04bbc78SJeremy L Thompson // Operator fallback 1497d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1498d04bbc78SJeremy L Thompson 1499d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1500d04bbc78SJeremy L Thompson if (op_fallback) { 1501d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op_fallback, assembled, 1502d04bbc78SJeremy L Thompson rstr, request); CeedChk(ierr); 1503d04bbc78SJeremy L Thompson } else { 1504d04bbc78SJeremy L Thompson // LCOV_EXCL_START 1505d04bbc78SJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 1506d04bbc78SJeremy L Thompson "Backend does not support CeedOperatorLinearAssembleQFunctionUpdate"); 1507d04bbc78SJeremy L Thompson // LCOV_EXCL_STOP 150870a7ffb3SJeremy L Thompson } 150970a7ffb3SJeremy L Thompson } 151070a7ffb3SJeremy L Thompson 151170a7ffb3SJeremy L Thompson return CEED_ERROR_SUCCESS; 1512eaf62fffSJeremy L Thompson } 1513eaf62fffSJeremy L Thompson 1514eaf62fffSJeremy L Thompson /** 1515eaf62fffSJeremy L Thompson @brief Assemble the diagonal of a square linear CeedOperator 1516eaf62fffSJeremy L Thompson 1517eaf62fffSJeremy L Thompson This overwrites a CeedVector with the diagonal of a linear CeedOperator. 1518eaf62fffSJeremy L Thompson 1519eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1520eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1521eaf62fffSJeremy L Thompson 1522f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1523f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1524f04ea552SJeremy L Thompson 1525eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1526eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator diagonal 1527eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1528eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1529eaf62fffSJeremy L Thompson 1530eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1531eaf62fffSJeremy L Thompson 1532eaf62fffSJeremy L Thompson @ref User 1533eaf62fffSJeremy L Thompson **/ 1534eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled, 1535eaf62fffSJeremy L Thompson CeedRequest *request) { 1536eaf62fffSJeremy L Thompson int ierr; 1537eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1538eaf62fffSJeremy L Thompson 1539c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 1540c9366a6bSJeremy L Thompson ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size); 1541c9366a6bSJeremy L Thompson CeedChk(ierr); 1542c9366a6bSJeremy L Thompson if (input_size != output_size) 1543c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1544c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1545c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 1546c9366a6bSJeremy L Thompson 1547eaf62fffSJeremy L Thompson if (op->LinearAssembleDiagonal) { 1548d04bbc78SJeremy L Thompson // Backend version 1549eaf62fffSJeremy L Thompson ierr = op->LinearAssembleDiagonal(op, assembled, request); CeedChk(ierr); 1550eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1551eaf62fffSJeremy L Thompson } else if (op->LinearAssembleAddDiagonal) { 1552d04bbc78SJeremy L Thompson // Backend version with zeroing first 1553eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1554eaf62fffSJeremy L Thompson ierr = op->LinearAssembleAddDiagonal(op, assembled, request); CeedChk(ierr); 1555eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1556eaf62fffSJeremy L Thompson } else { 1557d04bbc78SJeremy L Thompson // Operator fallback 1558d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1559d04bbc78SJeremy L Thompson 1560d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1561d04bbc78SJeremy L Thompson if (op_fallback) { 1562d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssembleDiagonal(op_fallback, assembled, request); 1563eaf62fffSJeremy L Thompson CeedChk(ierr); 1564eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1565eaf62fffSJeremy L Thompson } 1566eaf62fffSJeremy L Thompson } 1567eaf62fffSJeremy L Thompson // Default interface implementation 1568eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1569eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssembleAddDiagonal(op, assembled, request); 1570eaf62fffSJeremy L Thompson CeedChk(ierr); 1571d04bbc78SJeremy L Thompson 1572eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1573eaf62fffSJeremy L Thompson } 1574eaf62fffSJeremy L Thompson 1575eaf62fffSJeremy L Thompson /** 1576eaf62fffSJeremy L Thompson @brief Assemble the diagonal of a square linear CeedOperator 1577eaf62fffSJeremy L Thompson 1578eaf62fffSJeremy L Thompson This sums into a CeedVector the diagonal of a linear CeedOperator. 1579eaf62fffSJeremy L Thompson 1580eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1581eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1582eaf62fffSJeremy L Thompson 1583f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1584f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1585f04ea552SJeremy L Thompson 1586eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1587eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator diagonal 1588eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1589eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1590eaf62fffSJeremy L Thompson 1591eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1592eaf62fffSJeremy L Thompson 1593eaf62fffSJeremy L Thompson @ref User 1594eaf62fffSJeremy L Thompson **/ 1595eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled, 1596eaf62fffSJeremy L Thompson CeedRequest *request) { 1597eaf62fffSJeremy L Thompson int ierr; 1598eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1599eaf62fffSJeremy L Thompson 1600c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 1601c9366a6bSJeremy L Thompson ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size); 1602c9366a6bSJeremy L Thompson CeedChk(ierr); 1603c9366a6bSJeremy L Thompson if (input_size != output_size) 1604c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1605c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1606c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 1607c9366a6bSJeremy L Thompson 1608eaf62fffSJeremy L Thompson if (op->LinearAssembleAddDiagonal) { 1609d04bbc78SJeremy L Thompson // Backend version 1610eaf62fffSJeremy L Thompson ierr = op->LinearAssembleAddDiagonal(op, assembled, request); CeedChk(ierr); 1611eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1612eaf62fffSJeremy L Thompson } else { 1613d04bbc78SJeremy L Thompson // Operator fallback 1614d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1615d04bbc78SJeremy L Thompson 1616d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1617d04bbc78SJeremy L Thompson if (op_fallback) { 1618d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssembleAddDiagonal(op_fallback, assembled, request); 1619eaf62fffSJeremy L Thompson CeedChk(ierr); 1620eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1621eaf62fffSJeremy L Thompson } 1622eaf62fffSJeremy L Thompson } 1623eaf62fffSJeremy L Thompson // Default interface implementation 1624eaf62fffSJeremy L Thompson bool is_composite; 1625eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1626eaf62fffSJeremy L Thompson if (is_composite) { 1627eaf62fffSJeremy L Thompson ierr = CeedCompositeOperatorLinearAssembleAddDiagonal(op, request, 1628eaf62fffSJeremy L Thompson false, assembled); CeedChk(ierr); 1629eaf62fffSJeremy L Thompson } else { 1630eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssembleAddDiagonal(op, request, false, assembled); 1631eaf62fffSJeremy L Thompson CeedChk(ierr); 1632eaf62fffSJeremy L Thompson } 1633d04bbc78SJeremy L Thompson 1634d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 1635eaf62fffSJeremy L Thompson } 1636eaf62fffSJeremy L Thompson 1637eaf62fffSJeremy L Thompson /** 1638eaf62fffSJeremy L Thompson @brief Assemble the point block diagonal of a square linear CeedOperator 1639eaf62fffSJeremy L Thompson 1640eaf62fffSJeremy L Thompson This overwrites a CeedVector with the point block diagonal of a linear 1641eaf62fffSJeremy L Thompson CeedOperator. 1642eaf62fffSJeremy L Thompson 1643eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1644eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1645eaf62fffSJeremy L Thompson 1646f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1647f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1648f04ea552SJeremy L Thompson 1649eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1650eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator point block 1651eaf62fffSJeremy L Thompson diagonal, provided in row-major form with an 1652eaf62fffSJeremy L Thompson @a num_comp * @a num_comp block at each node. The dimensions 1653eaf62fffSJeremy L Thompson of this vector are derived from the active vector 1654eaf62fffSJeremy L Thompson for the CeedOperator. The array has shape 1655eaf62fffSJeremy L Thompson [nodes, component out, component in]. 1656eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1657eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 1658eaf62fffSJeremy L Thompson 1659eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1660eaf62fffSJeremy L Thompson 1661eaf62fffSJeremy L Thompson @ref User 1662eaf62fffSJeremy L Thompson **/ 1663eaf62fffSJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op, 1664eaf62fffSJeremy L Thompson CeedVector assembled, CeedRequest *request) { 1665eaf62fffSJeremy L Thompson int ierr; 1666eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1667eaf62fffSJeremy L Thompson 1668c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 1669c9366a6bSJeremy L Thompson ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size); 1670c9366a6bSJeremy L Thompson CeedChk(ierr); 1671c9366a6bSJeremy L Thompson if (input_size != output_size) 1672c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1673c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1674c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 1675c9366a6bSJeremy L Thompson 1676eaf62fffSJeremy L Thompson if (op->LinearAssemblePointBlockDiagonal) { 1677d04bbc78SJeremy L Thompson // Backend version 1678eaf62fffSJeremy L Thompson ierr = op->LinearAssemblePointBlockDiagonal(op, assembled, request); 1679eaf62fffSJeremy L Thompson CeedChk(ierr); 1680eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1681eaf62fffSJeremy L Thompson } else if (op->LinearAssembleAddPointBlockDiagonal) { 1682d04bbc78SJeremy L Thompson // Backend version with zeroing first 1683eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1684eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, 1685eaf62fffSJeremy L Thompson request); CeedChk(ierr); 1686eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1687eaf62fffSJeremy L Thompson } else { 1688d04bbc78SJeremy L Thompson // Operator fallback 1689d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1690d04bbc78SJeremy L Thompson 1691d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1692d04bbc78SJeremy L Thompson if (op_fallback) { 1693d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssemblePointBlockDiagonal(op_fallback, assembled, 1694d04bbc78SJeremy L Thompson request); CeedChk(ierr); 1695eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1696eaf62fffSJeremy L Thompson } 1697eaf62fffSJeremy L Thompson } 1698eaf62fffSJeremy L Thompson // Default interface implementation 1699eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1700eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, request); 1701eaf62fffSJeremy L Thompson CeedChk(ierr); 1702d04bbc78SJeremy L Thompson 1703eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1704eaf62fffSJeremy L Thompson } 1705eaf62fffSJeremy L Thompson 1706eaf62fffSJeremy L Thompson /** 1707eaf62fffSJeremy L Thompson @brief Assemble the point block diagonal of a square linear CeedOperator 1708eaf62fffSJeremy L Thompson 1709eaf62fffSJeremy L Thompson This sums into a CeedVector with the point block diagonal of a linear 1710eaf62fffSJeremy L Thompson CeedOperator. 1711eaf62fffSJeremy L Thompson 1712eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1713eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1714eaf62fffSJeremy L Thompson 1715f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1716f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1717f04ea552SJeremy L Thompson 1718eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1719eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator point block 1720eaf62fffSJeremy L Thompson diagonal, provided in row-major form with an 1721eaf62fffSJeremy L Thompson @a num_comp * @a num_comp block at each node. The dimensions 1722eaf62fffSJeremy L Thompson of this vector are derived from the active vector 1723eaf62fffSJeremy L Thompson for the CeedOperator. The array has shape 1724eaf62fffSJeremy L Thompson [nodes, component out, component in]. 1725eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1726eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 1727eaf62fffSJeremy L Thompson 1728eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1729eaf62fffSJeremy L Thompson 1730eaf62fffSJeremy L Thompson @ref User 1731eaf62fffSJeremy L Thompson **/ 1732eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op, 1733eaf62fffSJeremy L Thompson CeedVector assembled, CeedRequest *request) { 1734eaf62fffSJeremy L Thompson int ierr; 1735eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1736eaf62fffSJeremy L Thompson 1737c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 1738c9366a6bSJeremy L Thompson ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size); 1739c9366a6bSJeremy L Thompson CeedChk(ierr); 1740c9366a6bSJeremy L Thompson if (input_size != output_size) 1741c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1742c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1743c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 1744c9366a6bSJeremy L Thompson 1745eaf62fffSJeremy L Thompson if (op->LinearAssembleAddPointBlockDiagonal) { 1746d04bbc78SJeremy L Thompson // Backend version 1747eaf62fffSJeremy L Thompson ierr = op->LinearAssembleAddPointBlockDiagonal(op, assembled, request); 1748eaf62fffSJeremy L Thompson CeedChk(ierr); 1749eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1750eaf62fffSJeremy L Thompson } else { 1751d04bbc78SJeremy L Thompson // Operator fallback 1752d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1753d04bbc78SJeremy L Thompson 1754d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1755d04bbc78SJeremy L Thompson if (op_fallback) { 1756d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssembleAddPointBlockDiagonal(op_fallback, assembled, 1757d04bbc78SJeremy L Thompson request); CeedChk(ierr); 1758eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1759eaf62fffSJeremy L Thompson } 1760eaf62fffSJeremy L Thompson } 1761eaf62fffSJeremy L Thompson // Default interface implemenation 1762eaf62fffSJeremy L Thompson bool is_composite; 1763eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1764eaf62fffSJeremy L Thompson if (is_composite) { 1765eaf62fffSJeremy L Thompson ierr = CeedCompositeOperatorLinearAssembleAddDiagonal(op, request, 1766eaf62fffSJeremy L Thompson true, assembled); CeedChk(ierr); 1767eaf62fffSJeremy L Thompson } else { 1768eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssembleAddDiagonal(op, request, true, assembled); 1769eaf62fffSJeremy L Thompson CeedChk(ierr); 1770eaf62fffSJeremy L Thompson } 1771d04bbc78SJeremy L Thompson 1772d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 1773eaf62fffSJeremy L Thompson } 1774eaf62fffSJeremy L Thompson 1775eaf62fffSJeremy L Thompson /** 1776eaf62fffSJeremy L Thompson @brief Fully assemble the nonzero pattern of a linear operator. 1777eaf62fffSJeremy L Thompson 1778eaf62fffSJeremy L Thompson Expected to be used in conjunction with CeedOperatorLinearAssemble() 1779eaf62fffSJeremy L Thompson 1780eaf62fffSJeremy L Thompson The assembly routines use coordinate format, with num_entries tuples of the 1781eaf62fffSJeremy L Thompson form (i, j, value) which indicate that value should be added to the matrix 1782eaf62fffSJeremy L Thompson in entry (i, j). Note that the (i, j) pairs are not unique and may repeat. 1783eaf62fffSJeremy L Thompson This function returns the number of entries and their (i, j) locations, 1784eaf62fffSJeremy L Thompson while CeedOperatorLinearAssemble() provides the values in the same 1785eaf62fffSJeremy L Thompson ordering. 1786eaf62fffSJeremy L Thompson 1787eaf62fffSJeremy L Thompson This will generally be slow unless your operator is low-order. 1788eaf62fffSJeremy L Thompson 1789f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1790f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1791f04ea552SJeremy L Thompson 1792eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 1793eaf62fffSJeremy L Thompson @param[out] num_entries Number of entries in coordinate nonzero pattern 1794eaf62fffSJeremy L Thompson @param[out] rows Row number for each entry 1795eaf62fffSJeremy L Thompson @param[out] cols Column number for each entry 1796eaf62fffSJeremy L Thompson 1797eaf62fffSJeremy L Thompson @ref User 1798eaf62fffSJeremy L Thompson **/ 1799c30b7fbdSJeremy L Thompson int CeedOperatorLinearAssembleSymbolic(CeedOperator op, CeedSize *num_entries, 1800eaf62fffSJeremy L Thompson CeedInt **rows, CeedInt **cols) { 1801eaf62fffSJeremy L Thompson int ierr; 1802eaf62fffSJeremy L Thompson CeedInt num_suboperators, single_entries; 1803eaf62fffSJeremy L Thompson CeedOperator *sub_operators; 1804eaf62fffSJeremy L Thompson bool is_composite; 1805eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1806eaf62fffSJeremy L Thompson 1807eaf62fffSJeremy L Thompson if (op->LinearAssembleSymbolic) { 1808d04bbc78SJeremy L Thompson // Backend version 1809eaf62fffSJeremy L Thompson ierr = op->LinearAssembleSymbolic(op, num_entries, rows, cols); CeedChk(ierr); 1810eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1811eaf62fffSJeremy L Thompson } else { 1812d04bbc78SJeremy L Thompson // Operator fallback 1813d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1814d04bbc78SJeremy L Thompson 1815d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1816d04bbc78SJeremy L Thompson if (op_fallback) { 1817d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssembleSymbolic(op_fallback, num_entries, rows, cols); 1818eaf62fffSJeremy L Thompson CeedChk(ierr); 1819eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1820eaf62fffSJeremy L Thompson } 1821eaf62fffSJeremy L Thompson } 1822eaf62fffSJeremy L Thompson 1823eaf62fffSJeremy L Thompson // Default interface implementation 1824eaf62fffSJeremy L Thompson 1825eaf62fffSJeremy L Thompson // count entries and allocate rows, cols arrays 1826eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1827eaf62fffSJeremy L Thompson *num_entries = 0; 1828eaf62fffSJeremy L Thompson if (is_composite) { 1829eaf62fffSJeremy L Thompson ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1830eaf62fffSJeremy L Thompson ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 183192ae7e47SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; ++k) { 1832eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k], 1833eaf62fffSJeremy L Thompson &single_entries); CeedChk(ierr); 1834eaf62fffSJeremy L Thompson *num_entries += single_entries; 1835eaf62fffSJeremy L Thompson } 1836eaf62fffSJeremy L Thompson } else { 1837eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemblyCountEntries(op, 1838eaf62fffSJeremy L Thompson &single_entries); CeedChk(ierr); 1839eaf62fffSJeremy L Thompson *num_entries += single_entries; 1840eaf62fffSJeremy L Thompson } 1841eaf62fffSJeremy L Thompson ierr = CeedCalloc(*num_entries, rows); CeedChk(ierr); 1842eaf62fffSJeremy L Thompson ierr = CeedCalloc(*num_entries, cols); CeedChk(ierr); 1843eaf62fffSJeremy L Thompson 1844eaf62fffSJeremy L Thompson // assemble nonzero locations 1845eaf62fffSJeremy L Thompson CeedInt offset = 0; 1846eaf62fffSJeremy L Thompson if (is_composite) { 1847eaf62fffSJeremy L Thompson ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1848eaf62fffSJeremy L Thompson ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 184992ae7e47SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; ++k) { 1850eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssembleSymbolic(sub_operators[k], offset, *rows, 1851eaf62fffSJeremy L Thompson *cols); CeedChk(ierr); 1852eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k], 1853eaf62fffSJeremy L Thompson &single_entries); 1854eaf62fffSJeremy L Thompson CeedChk(ierr); 1855eaf62fffSJeremy L Thompson offset += single_entries; 1856eaf62fffSJeremy L Thompson } 1857eaf62fffSJeremy L Thompson } else { 1858eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssembleSymbolic(op, offset, *rows, *cols); 1859eaf62fffSJeremy L Thompson CeedChk(ierr); 1860eaf62fffSJeremy L Thompson } 1861eaf62fffSJeremy L Thompson 1862eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1863eaf62fffSJeremy L Thompson } 1864eaf62fffSJeremy L Thompson 1865eaf62fffSJeremy L Thompson /** 1866eaf62fffSJeremy L Thompson @brief Fully assemble the nonzero entries of a linear operator. 1867eaf62fffSJeremy L Thompson 1868eaf62fffSJeremy L Thompson Expected to be used in conjunction with CeedOperatorLinearAssembleSymbolic() 1869eaf62fffSJeremy L Thompson 1870eaf62fffSJeremy L Thompson The assembly routines use coordinate format, with num_entries tuples of the 1871eaf62fffSJeremy L Thompson form (i, j, value) which indicate that value should be added to the matrix 1872eaf62fffSJeremy L Thompson in entry (i, j). Note that the (i, j) pairs are not unique and may repeat. 1873eaf62fffSJeremy L Thompson This function returns the values of the nonzero entries to be added, their 1874eaf62fffSJeremy L Thompson (i, j) locations are provided by CeedOperatorLinearAssembleSymbolic() 1875eaf62fffSJeremy L Thompson 1876eaf62fffSJeremy L Thompson This will generally be slow unless your operator is low-order. 1877eaf62fffSJeremy L Thompson 1878f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1879f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1880f04ea552SJeremy L Thompson 1881eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 1882eaf62fffSJeremy L Thompson @param[out] values Values to assemble into matrix 1883eaf62fffSJeremy L Thompson 1884eaf62fffSJeremy L Thompson @ref User 1885eaf62fffSJeremy L Thompson **/ 1886eaf62fffSJeremy L Thompson int CeedOperatorLinearAssemble(CeedOperator op, CeedVector values) { 1887eaf62fffSJeremy L Thompson int ierr; 1888eaf62fffSJeremy L Thompson CeedInt num_suboperators, single_entries = 0; 1889eaf62fffSJeremy L Thompson CeedOperator *sub_operators; 1890eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1891eaf62fffSJeremy L Thompson 1892eaf62fffSJeremy L Thompson if (op->LinearAssemble) { 1893d04bbc78SJeremy L Thompson // Backend version 1894eaf62fffSJeremy L Thompson ierr = op->LinearAssemble(op, values); CeedChk(ierr); 1895eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1896eaf62fffSJeremy L Thompson } else { 1897d04bbc78SJeremy L Thompson // Operator fallback 1898d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1899d04bbc78SJeremy L Thompson 1900d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1901d04bbc78SJeremy L Thompson if (op_fallback) { 1902d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssemble(op_fallback, values); CeedChk(ierr); 1903eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1904eaf62fffSJeremy L Thompson } 1905eaf62fffSJeremy L Thompson } 1906eaf62fffSJeremy L Thompson 1907eaf62fffSJeremy L Thompson // Default interface implementation 1908eaf62fffSJeremy L Thompson bool is_composite; 1909eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1910eaf62fffSJeremy L Thompson 1911eaf62fffSJeremy L Thompson CeedInt offset = 0; 1912eaf62fffSJeremy L Thompson if (is_composite) { 1913eaf62fffSJeremy L Thompson ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1914eaf62fffSJeremy L Thompson ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1915cefa2673SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; k++) { 1916eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemble(sub_operators[k], offset, values); 1917eaf62fffSJeremy L Thompson CeedChk(ierr); 1918eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k], 1919eaf62fffSJeremy L Thompson &single_entries); 1920eaf62fffSJeremy L Thompson CeedChk(ierr); 1921eaf62fffSJeremy L Thompson offset += single_entries; 1922eaf62fffSJeremy L Thompson } 1923eaf62fffSJeremy L Thompson } else { 1924eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemble(op, offset, values); CeedChk(ierr); 1925eaf62fffSJeremy L Thompson } 1926eaf62fffSJeremy L Thompson 1927eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1928eaf62fffSJeremy L Thompson } 1929eaf62fffSJeremy L Thompson 1930eaf62fffSJeremy L Thompson /** 1931eaf62fffSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators 1932eaf62fffSJeremy L Thompson for a CeedOperator, creating the prolongation basis from the 1933eaf62fffSJeremy L Thompson fine and coarse grid interpolation 1934eaf62fffSJeremy L Thompson 1935f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1936f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1937f04ea552SJeremy L Thompson 1938eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 1939eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 1940eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 1941eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 1942eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 1943eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 1944eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 1945eaf62fffSJeremy L Thompson 1946eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1947eaf62fffSJeremy L Thompson 1948eaf62fffSJeremy L Thompson @ref User 1949eaf62fffSJeremy L Thompson **/ 1950eaf62fffSJeremy L Thompson int CeedOperatorMultigridLevelCreate(CeedOperator op_fine, 1951eaf62fffSJeremy L Thompson CeedVector p_mult_fine, 1952eaf62fffSJeremy L Thompson CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 1953eaf62fffSJeremy L Thompson CeedOperator *op_coarse, CeedOperator *op_prolong, 1954eaf62fffSJeremy L Thompson CeedOperator *op_restrict) { 1955eaf62fffSJeremy L Thompson int ierr; 1956f04ea552SJeremy L Thompson ierr = CeedOperatorCheckReady(op_fine); CeedChk(ierr); 1957eaf62fffSJeremy L Thompson Ceed ceed; 1958eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr); 1959eaf62fffSJeremy L Thompson 1960eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 1961eaf62fffSJeremy L Thompson CeedBasis basis_fine; 1962eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr); 1963eaf62fffSJeremy L Thompson CeedInt Q_f, Q_c; 1964eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr); 1965eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr); 1966eaf62fffSJeremy L Thompson if (Q_f != Q_c) 1967eaf62fffSJeremy L Thompson // LCOV_EXCL_START 1968eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, 1969eaf62fffSJeremy L Thompson "Bases must have compatible quadrature spaces"); 1970eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 1971eaf62fffSJeremy L Thompson 1972eaf62fffSJeremy L Thompson // Coarse to fine basis 1973eaf62fffSJeremy L Thompson CeedInt P_f, P_c, Q = Q_f; 1974eaf62fffSJeremy L Thompson bool is_tensor_f, is_tensor_c; 1975eaf62fffSJeremy L Thompson ierr = CeedBasisIsTensor(basis_fine, &is_tensor_f); CeedChk(ierr); 1976eaf62fffSJeremy L Thompson ierr = CeedBasisIsTensor(basis_coarse, &is_tensor_c); CeedChk(ierr); 1977eaf62fffSJeremy L Thompson CeedScalar *interp_c, *interp_f, *interp_c_to_f, *tau; 1978eaf62fffSJeremy L Thompson if (is_tensor_f && is_tensor_c) { 1979eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes1D(basis_fine, &P_f); CeedChk(ierr); 1980eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes1D(basis_coarse, &P_c); CeedChk(ierr); 1981eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints1D(basis_coarse, &Q); CeedChk(ierr); 1982eaf62fffSJeremy L Thompson } else if (!is_tensor_f && !is_tensor_c) { 1983eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis_fine, &P_f); CeedChk(ierr); 1984eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis_coarse, &P_c); CeedChk(ierr); 1985eaf62fffSJeremy L Thompson } else { 1986eaf62fffSJeremy L Thompson // LCOV_EXCL_START 1987eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_MINOR, 1988eaf62fffSJeremy L Thompson "Bases must both be tensor or non-tensor"); 1989eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 1990eaf62fffSJeremy L Thompson } 1991eaf62fffSJeremy L Thompson 1992eaf62fffSJeremy L Thompson ierr = CeedMalloc(Q*P_f, &interp_f); CeedChk(ierr); 1993eaf62fffSJeremy L Thompson ierr = CeedMalloc(Q*P_c, &interp_c); CeedChk(ierr); 1994eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_c*P_f, &interp_c_to_f); CeedChk(ierr); 1995eaf62fffSJeremy L Thompson ierr = CeedMalloc(Q, &tau); CeedChk(ierr); 19968575dcacSJeremy L Thompson const CeedScalar *interp_f_source = NULL, *interp_c_source = NULL; 1997eaf62fffSJeremy L Thompson if (is_tensor_f) { 19988575dcacSJeremy L Thompson ierr = CeedBasisGetInterp1D(basis_fine, &interp_f_source); CeedChk(ierr); 19998575dcacSJeremy L Thompson ierr = CeedBasisGetInterp1D(basis_coarse, &interp_c_source); CeedChk(ierr); 2000eaf62fffSJeremy L Thompson } else { 20018575dcacSJeremy L Thompson ierr = CeedBasisGetInterp(basis_fine, &interp_f_source); CeedChk(ierr); 20028575dcacSJeremy L Thompson ierr = CeedBasisGetInterp(basis_coarse, &interp_c_source); CeedChk(ierr); 2003eaf62fffSJeremy L Thompson } 20048575dcacSJeremy L Thompson memcpy(interp_f, interp_f_source, Q*P_f*sizeof interp_f_source[0]); 20058575dcacSJeremy L Thompson memcpy(interp_c, interp_c_source, Q*P_c*sizeof interp_c_source[0]); 2006eaf62fffSJeremy L Thompson 2007eaf62fffSJeremy L Thompson // -- QR Factorization, interp_f = Q R 2008eaf62fffSJeremy L Thompson ierr = CeedQRFactorization(ceed, interp_f, tau, Q, P_f); CeedChk(ierr); 2009eaf62fffSJeremy L Thompson 2010eaf62fffSJeremy L Thompson // -- Apply Qtranspose, interp_c = Qtranspose interp_c 2011eaf62fffSJeremy L Thompson ierr = CeedHouseholderApplyQ(interp_c, interp_f, tau, CEED_TRANSPOSE, 2012eaf62fffSJeremy L Thompson Q, P_c, P_f, P_c, 1); CeedChk(ierr); 2013eaf62fffSJeremy L Thompson 2014eaf62fffSJeremy L Thompson // -- Apply Rinv, interp_c_to_f = Rinv interp_c 2015eaf62fffSJeremy L Thompson for (CeedInt j=0; j<P_c; j++) { // Column j 2016eaf62fffSJeremy L Thompson interp_c_to_f[j+P_c*(P_f-1)] = interp_c[j+P_c*(P_f-1)]/interp_f[P_f*P_f-1]; 2017eaf62fffSJeremy L Thompson for (CeedInt i=P_f-2; i>=0; i--) { // Row i 2018eaf62fffSJeremy L Thompson interp_c_to_f[j+P_c*i] = interp_c[j+P_c*i]; 2019eaf62fffSJeremy L Thompson for (CeedInt k=i+1; k<P_f; k++) 2020eaf62fffSJeremy L Thompson interp_c_to_f[j+P_c*i] -= interp_f[k+P_f*i]*interp_c_to_f[j+P_c*k]; 2021eaf62fffSJeremy L Thompson interp_c_to_f[j+P_c*i] /= interp_f[i+P_f*i]; 2022eaf62fffSJeremy L Thompson } 2023eaf62fffSJeremy L Thompson } 2024eaf62fffSJeremy L Thompson ierr = CeedFree(&tau); CeedChk(ierr); 2025eaf62fffSJeremy L Thompson ierr = CeedFree(&interp_c); CeedChk(ierr); 2026eaf62fffSJeremy L Thompson ierr = CeedFree(&interp_f); CeedChk(ierr); 2027eaf62fffSJeremy L Thompson 2028eaf62fffSJeremy L Thompson // Complete with interp_c_to_f versions of code 2029eaf62fffSJeremy L Thompson if (is_tensor_f) { 2030eaf62fffSJeremy L Thompson ierr = CeedOperatorMultigridLevelCreateTensorH1(op_fine, p_mult_fine, 2031eaf62fffSJeremy L Thompson rstr_coarse, basis_coarse, interp_c_to_f, op_coarse, op_prolong, op_restrict); 2032eaf62fffSJeremy L Thompson CeedChk(ierr); 2033eaf62fffSJeremy L Thompson } else { 2034eaf62fffSJeremy L Thompson ierr = CeedOperatorMultigridLevelCreateH1(op_fine, p_mult_fine, 2035eaf62fffSJeremy L Thompson rstr_coarse, basis_coarse, interp_c_to_f, op_coarse, op_prolong, op_restrict); 2036eaf62fffSJeremy L Thompson CeedChk(ierr); 2037eaf62fffSJeremy L Thompson } 2038eaf62fffSJeremy L Thompson 2039eaf62fffSJeremy L Thompson // Cleanup 2040eaf62fffSJeremy L Thompson ierr = CeedFree(&interp_c_to_f); CeedChk(ierr); 2041eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2042eaf62fffSJeremy L Thompson } 2043eaf62fffSJeremy L Thompson 2044eaf62fffSJeremy L Thompson /** 2045eaf62fffSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators 2046eaf62fffSJeremy L Thompson for a CeedOperator with a tensor basis for the active basis 2047eaf62fffSJeremy L Thompson 2048f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 2049f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 2050f04ea552SJeremy L Thompson 2051eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 2052eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 2053eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 2054eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 2055eaf62fffSJeremy L Thompson @param[in] interp_c_to_f Matrix for coarse to fine interpolation 2056eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 2057eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 2058eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 2059eaf62fffSJeremy L Thompson 2060eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2061eaf62fffSJeremy L Thompson 2062eaf62fffSJeremy L Thompson @ref User 2063eaf62fffSJeremy L Thompson **/ 2064eaf62fffSJeremy L Thompson int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator op_fine, 2065eaf62fffSJeremy L Thompson CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 2066eaf62fffSJeremy L Thompson const CeedScalar *interp_c_to_f, CeedOperator *op_coarse, 2067eaf62fffSJeremy L Thompson CeedOperator *op_prolong, CeedOperator *op_restrict) { 2068eaf62fffSJeremy L Thompson int ierr; 2069f04ea552SJeremy L Thompson ierr = CeedOperatorCheckReady(op_fine); CeedChk(ierr); 2070eaf62fffSJeremy L Thompson Ceed ceed; 2071eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr); 2072eaf62fffSJeremy L Thompson 2073eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 2074eaf62fffSJeremy L Thompson CeedBasis basis_fine; 2075eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr); 2076eaf62fffSJeremy L Thompson CeedInt Q_f, Q_c; 2077eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr); 2078eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr); 2079eaf62fffSJeremy L Thompson if (Q_f != Q_c) 2080eaf62fffSJeremy L Thompson // LCOV_EXCL_START 2081eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, 2082eaf62fffSJeremy L Thompson "Bases must have compatible quadrature spaces"); 2083eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 2084eaf62fffSJeremy L Thompson 2085eaf62fffSJeremy L Thompson // Coarse to fine basis 2086eaf62fffSJeremy L Thompson CeedInt dim, num_comp, num_nodes_c, P_1d_f, P_1d_c; 2087eaf62fffSJeremy L Thompson ierr = CeedBasisGetDimension(basis_fine, &dim); CeedChk(ierr); 2088eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis_fine, &num_comp); CeedChk(ierr); 2089eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes1D(basis_fine, &P_1d_f); CeedChk(ierr); 2090eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c); 2091eaf62fffSJeremy L Thompson CeedChk(ierr); 2092eaf62fffSJeremy L Thompson P_1d_c = dim == 1 ? num_nodes_c : 2093eaf62fffSJeremy L Thompson dim == 2 ? sqrt(num_nodes_c) : 2094eaf62fffSJeremy L Thompson cbrt(num_nodes_c); 2095eaf62fffSJeremy L Thompson CeedScalar *q_ref, *q_weight, *grad; 2096eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d_f, &q_ref); CeedChk(ierr); 2097eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d_f, &q_weight); CeedChk(ierr); 2098eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d_f*P_1d_c*dim, &grad); CeedChk(ierr); 2099eaf62fffSJeremy L Thompson CeedBasis basis_c_to_f; 2100eaf62fffSJeremy L Thompson ierr = CeedBasisCreateTensorH1(ceed, dim, num_comp, P_1d_c, P_1d_f, 2101eaf62fffSJeremy L Thompson interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f); 2102eaf62fffSJeremy L Thompson CeedChk(ierr); 2103eaf62fffSJeremy L Thompson ierr = CeedFree(&q_ref); CeedChk(ierr); 2104eaf62fffSJeremy L Thompson ierr = CeedFree(&q_weight); CeedChk(ierr); 2105eaf62fffSJeremy L Thompson ierr = CeedFree(&grad); CeedChk(ierr); 2106eaf62fffSJeremy L Thompson 2107eaf62fffSJeremy L Thompson // Core code 2108eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, 2109eaf62fffSJeremy L Thompson basis_coarse, basis_c_to_f, op_coarse, 2110eaf62fffSJeremy L Thompson op_prolong, op_restrict); 2111eaf62fffSJeremy L Thompson CeedChk(ierr); 2112eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2113eaf62fffSJeremy L Thompson } 2114eaf62fffSJeremy L Thompson 2115eaf62fffSJeremy L Thompson /** 2116eaf62fffSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators 2117eaf62fffSJeremy L Thompson for a CeedOperator with a non-tensor basis for the active vector 2118eaf62fffSJeremy L Thompson 2119f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 2120f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 2121f04ea552SJeremy L Thompson 2122eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 2123eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 2124eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 2125eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 2126eaf62fffSJeremy L Thompson @param[in] interp_c_to_f Matrix for coarse to fine interpolation 2127eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 2128eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 2129eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 2130eaf62fffSJeremy L Thompson 2131eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2132eaf62fffSJeremy L Thompson 2133eaf62fffSJeremy L Thompson @ref User 2134eaf62fffSJeremy L Thompson **/ 2135eaf62fffSJeremy L Thompson int CeedOperatorMultigridLevelCreateH1(CeedOperator op_fine, 2136eaf62fffSJeremy L Thompson CeedVector p_mult_fine, 2137eaf62fffSJeremy L Thompson CeedElemRestriction rstr_coarse, 2138eaf62fffSJeremy L Thompson CeedBasis basis_coarse, 2139eaf62fffSJeremy L Thompson const CeedScalar *interp_c_to_f, 2140eaf62fffSJeremy L Thompson CeedOperator *op_coarse, 2141eaf62fffSJeremy L Thompson CeedOperator *op_prolong, 2142eaf62fffSJeremy L Thompson CeedOperator *op_restrict) { 2143eaf62fffSJeremy L Thompson int ierr; 2144f04ea552SJeremy L Thompson ierr = CeedOperatorCheckReady(op_fine); CeedChk(ierr); 2145eaf62fffSJeremy L Thompson Ceed ceed; 2146eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr); 2147eaf62fffSJeremy L Thompson 2148eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 2149eaf62fffSJeremy L Thompson CeedBasis basis_fine; 2150eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr); 2151eaf62fffSJeremy L Thompson CeedInt Q_f, Q_c; 2152eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr); 2153eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr); 2154eaf62fffSJeremy L Thompson if (Q_f != Q_c) 2155eaf62fffSJeremy L Thompson // LCOV_EXCL_START 2156eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, 2157eaf62fffSJeremy L Thompson "Bases must have compatible quadrature spaces"); 2158eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 2159eaf62fffSJeremy L Thompson 2160eaf62fffSJeremy L Thompson // Coarse to fine basis 2161eaf62fffSJeremy L Thompson CeedElemTopology topo; 2162eaf62fffSJeremy L Thompson ierr = CeedBasisGetTopology(basis_fine, &topo); CeedChk(ierr); 2163eaf62fffSJeremy L Thompson CeedInt dim, num_comp, num_nodes_c, num_nodes_f; 2164eaf62fffSJeremy L Thompson ierr = CeedBasisGetDimension(basis_fine, &dim); CeedChk(ierr); 2165eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis_fine, &num_comp); CeedChk(ierr); 2166eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis_fine, &num_nodes_f); CeedChk(ierr); 2167eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c); 2168eaf62fffSJeremy L Thompson CeedChk(ierr); 2169eaf62fffSJeremy L Thompson CeedScalar *q_ref, *q_weight, *grad; 2170f9e0419eSJeremy L Thompson ierr = CeedCalloc(num_nodes_f*dim, &q_ref); CeedChk(ierr); 2171eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_nodes_f, &q_weight); CeedChk(ierr); 2172eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_nodes_f*num_nodes_c*dim, &grad); CeedChk(ierr); 2173eaf62fffSJeremy L Thompson CeedBasis basis_c_to_f; 2174eaf62fffSJeremy L Thompson ierr = CeedBasisCreateH1(ceed, topo, num_comp, num_nodes_c, num_nodes_f, 2175eaf62fffSJeremy L Thompson interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f); 2176eaf62fffSJeremy L Thompson CeedChk(ierr); 2177eaf62fffSJeremy L Thompson ierr = CeedFree(&q_ref); CeedChk(ierr); 2178eaf62fffSJeremy L Thompson ierr = CeedFree(&q_weight); CeedChk(ierr); 2179eaf62fffSJeremy L Thompson ierr = CeedFree(&grad); CeedChk(ierr); 2180eaf62fffSJeremy L Thompson 2181eaf62fffSJeremy L Thompson // Core code 2182eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, 2183eaf62fffSJeremy L Thompson basis_coarse, basis_c_to_f, op_coarse, 2184eaf62fffSJeremy L Thompson op_prolong, op_restrict); 2185eaf62fffSJeremy L Thompson CeedChk(ierr); 2186eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2187eaf62fffSJeremy L Thompson } 2188eaf62fffSJeremy L Thompson 2189eaf62fffSJeremy L Thompson /** 2190eaf62fffSJeremy L Thompson @brief Build a FDM based approximate inverse for each element for a 2191eaf62fffSJeremy L Thompson CeedOperator 2192eaf62fffSJeremy L Thompson 2193eaf62fffSJeremy L Thompson This returns a CeedOperator and CeedVector to apply a Fast Diagonalization 2194eaf62fffSJeremy L Thompson Method based approximate inverse. This function obtains the simultaneous 2195eaf62fffSJeremy L Thompson diagonalization for the 1D mass and Laplacian operators, 2196eaf62fffSJeremy L Thompson M = V^T V, K = V^T S V. 2197eaf62fffSJeremy L Thompson The assembled QFunction is used to modify the eigenvalues from simultaneous 2198eaf62fffSJeremy L Thompson diagonalization and obtain an approximate inverse of the form 2199eaf62fffSJeremy L Thompson V^T S^hat V. The CeedOperator must be linear and non-composite. The 2200eaf62fffSJeremy L Thompson associated CeedQFunction must therefore also be linear. 2201eaf62fffSJeremy L Thompson 2202f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 2203f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 2204f04ea552SJeremy L Thompson 2205eaf62fffSJeremy L Thompson @param op CeedOperator to create element inverses 2206eaf62fffSJeremy L Thompson @param[out] fdm_inv CeedOperator to apply the action of a FDM based inverse 2207eaf62fffSJeremy L Thompson for each element 2208eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 2209eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 2210eaf62fffSJeremy L Thompson 2211eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2212eaf62fffSJeremy L Thompson 2213480fae85SJeremy L Thompson @ref User 2214eaf62fffSJeremy L Thompson **/ 2215eaf62fffSJeremy L Thompson int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdm_inv, 2216eaf62fffSJeremy L Thompson CeedRequest *request) { 2217eaf62fffSJeremy L Thompson int ierr; 2218eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 2219eaf62fffSJeremy L Thompson 2220eaf62fffSJeremy L Thompson if (op->CreateFDMElementInverse) { 2221d04bbc78SJeremy L Thompson // Backend version 2222eaf62fffSJeremy L Thompson ierr = op->CreateFDMElementInverse(op, fdm_inv, request); CeedChk(ierr); 2223eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2224eaf62fffSJeremy L Thompson } else { 2225d04bbc78SJeremy L Thompson // Operator fallback 2226d04bbc78SJeremy L Thompson CeedOperator op_fallback; 2227d04bbc78SJeremy L Thompson 2228d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 2229d04bbc78SJeremy L Thompson if (op_fallback) { 2230d04bbc78SJeremy L Thompson ierr = CeedOperatorCreateFDMElementInverse(op_fallback, fdm_inv, request); 2231eaf62fffSJeremy L Thompson CeedChk(ierr); 2232eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2233eaf62fffSJeremy L Thompson } 2234eaf62fffSJeremy L Thompson } 2235eaf62fffSJeremy L Thompson 2236d04bbc78SJeremy L Thompson // Default interface implementation 2237eaf62fffSJeremy L Thompson Ceed ceed, ceed_parent; 2238eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 2239eaf62fffSJeremy L Thompson ierr = CeedGetOperatorFallbackParentCeed(ceed, &ceed_parent); CeedChk(ierr); 2240eaf62fffSJeremy L Thompson ceed_parent = ceed_parent ? ceed_parent : ceed; 2241eaf62fffSJeremy L Thompson CeedQFunction qf; 2242eaf62fffSJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr); 2243eaf62fffSJeremy L Thompson 2244eaf62fffSJeremy L Thompson // Determine active input basis 2245eaf62fffSJeremy L Thompson bool interp = false, grad = false; 2246eaf62fffSJeremy L Thompson CeedBasis basis = NULL; 2247eaf62fffSJeremy L Thompson CeedElemRestriction rstr = NULL; 2248eaf62fffSJeremy L Thompson CeedOperatorField *op_fields; 2249eaf62fffSJeremy L Thompson CeedQFunctionField *qf_fields; 2250eaf62fffSJeremy L Thompson CeedInt num_input_fields; 22517e7773b5SJeremy L Thompson ierr = CeedOperatorGetFields(op, &num_input_fields, &op_fields, NULL, NULL); 22527e7773b5SJeremy L Thompson CeedChk(ierr); 22537e7773b5SJeremy L Thompson ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL); CeedChk(ierr); 2254eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_input_fields; i++) { 2255eaf62fffSJeremy L Thompson CeedVector vec; 2256eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChk(ierr); 2257eaf62fffSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 2258eaf62fffSJeremy L Thompson CeedEvalMode eval_mode; 2259eaf62fffSJeremy L Thompson ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); CeedChk(ierr); 2260eaf62fffSJeremy L Thompson interp = interp || eval_mode == CEED_EVAL_INTERP; 2261eaf62fffSJeremy L Thompson grad = grad || eval_mode == CEED_EVAL_GRAD; 2262eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis); CeedChk(ierr); 2263eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr); CeedChk(ierr); 2264eaf62fffSJeremy L Thompson } 2265eaf62fffSJeremy L Thompson } 2266eaf62fffSJeremy L Thompson if (!basis) 2267eaf62fffSJeremy L Thompson // LCOV_EXCL_START 2268eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "No active field set"); 2269eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 2270e79b91d9SJeremy L Thompson CeedSize l_size = 1; 2271e79b91d9SJeremy L Thompson CeedInt P_1d, Q_1d, elem_size, num_qpts, dim, num_comp = 1, num_elem = 1; 2272eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes1D(basis, &P_1d); CeedChk(ierr); 2273eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis, &elem_size); CeedChk(ierr); 2274eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d); CeedChk(ierr); 2275eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis, &num_qpts); CeedChk(ierr); 2276eaf62fffSJeremy L Thompson ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr); 2277eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis, &num_comp); CeedChk(ierr); 2278eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr); 2279eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetLVectorSize(rstr, &l_size); CeedChk(ierr); 2280eaf62fffSJeremy L Thompson 2281eaf62fffSJeremy L Thompson // Build and diagonalize 1D Mass and Laplacian 2282eaf62fffSJeremy L Thompson bool tensor_basis; 2283eaf62fffSJeremy L Thompson ierr = CeedBasisIsTensor(basis, &tensor_basis); CeedChk(ierr); 2284eaf62fffSJeremy L Thompson if (!tensor_basis) 2285eaf62fffSJeremy L Thompson // LCOV_EXCL_START 2286eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 2287eaf62fffSJeremy L Thompson "FDMElementInverse only supported for tensor " 2288eaf62fffSJeremy L Thompson "bases"); 2289eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 2290eaf62fffSJeremy L Thompson CeedScalar *mass, *laplace, *x, *fdm_interp, *lambda; 2291eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &mass); CeedChk(ierr); 2292eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &laplace); CeedChk(ierr); 2293eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &x); CeedChk(ierr); 2294eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &fdm_interp); CeedChk(ierr); 2295eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d, &lambda); CeedChk(ierr); 2296eaf62fffSJeremy L Thompson // -- Build matrices 2297eaf62fffSJeremy L Thompson const CeedScalar *interp_1d, *grad_1d, *q_weight_1d; 2298eaf62fffSJeremy L Thompson ierr = CeedBasisGetInterp1D(basis, &interp_1d); CeedChk(ierr); 2299eaf62fffSJeremy L Thompson ierr = CeedBasisGetGrad1D(basis, &grad_1d); CeedChk(ierr); 2300eaf62fffSJeremy L Thompson ierr = CeedBasisGetQWeights(basis, &q_weight_1d); CeedChk(ierr); 2301eaf62fffSJeremy L Thompson ierr = CeedBuildMassLaplace(interp_1d, grad_1d, q_weight_1d, P_1d, Q_1d, dim, 2302eaf62fffSJeremy L Thompson mass, laplace); CeedChk(ierr); 2303eaf62fffSJeremy L Thompson 2304eaf62fffSJeremy L Thompson // -- Diagonalize 2305eaf62fffSJeremy L Thompson ierr = CeedSimultaneousDiagonalization(ceed, laplace, mass, x, lambda, P_1d); 2306eaf62fffSJeremy L Thompson CeedChk(ierr); 2307eaf62fffSJeremy L Thompson ierr = CeedFree(&mass); CeedChk(ierr); 2308eaf62fffSJeremy L Thompson ierr = CeedFree(&laplace); CeedChk(ierr); 2309eaf62fffSJeremy L Thompson for (CeedInt i=0; i<P_1d; i++) 2310eaf62fffSJeremy L Thompson for (CeedInt j=0; j<P_1d; j++) 2311eaf62fffSJeremy L Thompson fdm_interp[i+j*P_1d] = x[j+i*P_1d]; 2312eaf62fffSJeremy L Thompson ierr = CeedFree(&x); CeedChk(ierr); 2313eaf62fffSJeremy L Thompson 2314eaf62fffSJeremy L Thompson // Assemble QFunction 2315eaf62fffSJeremy L Thompson CeedVector assembled; 2316eaf62fffSJeremy L Thompson CeedElemRestriction rstr_qf; 231770a7ffb3SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled, 231870a7ffb3SJeremy L Thompson &rstr_qf, request); CeedChk(ierr); 2319eaf62fffSJeremy L Thompson CeedInt layout[3]; 2320eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetELayout(rstr_qf, &layout); CeedChk(ierr); 2321eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr_qf); CeedChk(ierr); 2322eaf62fffSJeremy L Thompson CeedScalar max_norm = 0; 2323eaf62fffSJeremy L Thompson ierr = CeedVectorNorm(assembled, CEED_NORM_MAX, &max_norm); CeedChk(ierr); 2324eaf62fffSJeremy L Thompson 2325eaf62fffSJeremy L Thompson // Calculate element averages 2326eaf62fffSJeremy L Thompson CeedInt num_modes = (interp?1:0) + (grad?dim:0); 2327eaf62fffSJeremy L Thompson CeedScalar *elem_avg; 2328eaf62fffSJeremy L Thompson const CeedScalar *assembled_array, *q_weight_array; 2329eaf62fffSJeremy L Thompson CeedVector q_weight; 2330eaf62fffSJeremy L Thompson ierr = CeedVectorCreate(ceed_parent, num_qpts, &q_weight); CeedChk(ierr); 2331eaf62fffSJeremy L Thompson ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, 2332eaf62fffSJeremy L Thompson CEED_VECTOR_NONE, q_weight); CeedChk(ierr); 2333eaf62fffSJeremy L Thompson ierr = CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembled_array); 2334eaf62fffSJeremy L Thompson CeedChk(ierr); 2335eaf62fffSJeremy L Thompson ierr = CeedVectorGetArrayRead(q_weight, CEED_MEM_HOST, &q_weight_array); 2336eaf62fffSJeremy L Thompson CeedChk(ierr); 2337eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_elem, &elem_avg); CeedChk(ierr); 2338eaf62fffSJeremy L Thompson const CeedScalar qf_value_bound = max_norm*100*CEED_EPSILON; 2339eaf62fffSJeremy L Thompson for (CeedInt e=0; e<num_elem; e++) { 2340eaf62fffSJeremy L Thompson CeedInt count = 0; 2341eaf62fffSJeremy L Thompson for (CeedInt q=0; q<num_qpts; q++) 2342eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_comp*num_comp*num_modes*num_modes; i++) 2343eaf62fffSJeremy L Thompson if (fabs(assembled_array[q*layout[0] + i*layout[1] + e*layout[2]]) > 2344eaf62fffSJeremy L Thompson qf_value_bound) { 2345eaf62fffSJeremy L Thompson elem_avg[e] += assembled_array[q*layout[0] + i*layout[1] + e*layout[2]] / 2346eaf62fffSJeremy L Thompson q_weight_array[q]; 2347eaf62fffSJeremy L Thompson count++; 2348eaf62fffSJeremy L Thompson } 2349eaf62fffSJeremy L Thompson if (count) { 2350eaf62fffSJeremy L Thompson elem_avg[e] /= count; 2351eaf62fffSJeremy L Thompson } else { 2352eaf62fffSJeremy L Thompson elem_avg[e] = 1.0; 2353eaf62fffSJeremy L Thompson } 2354eaf62fffSJeremy L Thompson } 2355eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArrayRead(assembled, &assembled_array); CeedChk(ierr); 2356eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&assembled); CeedChk(ierr); 2357eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArrayRead(q_weight, &q_weight_array); CeedChk(ierr); 2358eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&q_weight); CeedChk(ierr); 2359eaf62fffSJeremy L Thompson 2360eaf62fffSJeremy L Thompson // Build FDM diagonal 2361eaf62fffSJeremy L Thompson CeedVector q_data; 2362eaf62fffSJeremy L Thompson CeedScalar *q_data_array, *fdm_diagonal; 2363eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_comp*elem_size, &fdm_diagonal); CeedChk(ierr); 2364eaf62fffSJeremy L Thompson const CeedScalar fdm_diagonal_bound = elem_size*CEED_EPSILON; 2365eaf62fffSJeremy L Thompson for (CeedInt c=0; c<num_comp; c++) 2366eaf62fffSJeremy L Thompson for (CeedInt n=0; n<elem_size; n++) { 2367eaf62fffSJeremy L Thompson if (interp) 2368eaf62fffSJeremy L Thompson fdm_diagonal[c*elem_size + n] = 1.0; 2369eaf62fffSJeremy L Thompson if (grad) 2370eaf62fffSJeremy L Thompson for (CeedInt d=0; d<dim; d++) { 2371eaf62fffSJeremy L Thompson CeedInt i = (n / CeedIntPow(P_1d, d)) % P_1d; 2372eaf62fffSJeremy L Thompson fdm_diagonal[c*elem_size + n] += lambda[i]; 2373eaf62fffSJeremy L Thompson } 2374eaf62fffSJeremy L Thompson if (fabs(fdm_diagonal[c*elem_size + n]) < fdm_diagonal_bound) 2375eaf62fffSJeremy L Thompson fdm_diagonal[c*elem_size + n] = fdm_diagonal_bound; 2376eaf62fffSJeremy L Thompson } 2377eaf62fffSJeremy L Thompson ierr = CeedVectorCreate(ceed_parent, num_elem*num_comp*elem_size, &q_data); 2378eaf62fffSJeremy L Thompson CeedChk(ierr); 2379eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(q_data, 0.0); CeedChk(ierr); 23809c774eddSJeremy L Thompson ierr = CeedVectorGetArrayWrite(q_data, CEED_MEM_HOST, &q_data_array); 23819c774eddSJeremy L Thompson CeedChk(ierr); 2382eaf62fffSJeremy L Thompson for (CeedInt e=0; e<num_elem; e++) 2383eaf62fffSJeremy L Thompson for (CeedInt c=0; c<num_comp; c++) 2384eaf62fffSJeremy L Thompson for (CeedInt n=0; n<elem_size; n++) 2385eaf62fffSJeremy L Thompson q_data_array[(e*num_comp+c)*elem_size+n] = 1. / (elem_avg[e] * 2386eaf62fffSJeremy L Thompson fdm_diagonal[c*elem_size + n]); 2387eaf62fffSJeremy L Thompson ierr = CeedFree(&elem_avg); CeedChk(ierr); 2388eaf62fffSJeremy L Thompson ierr = CeedFree(&fdm_diagonal); CeedChk(ierr); 2389eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArray(q_data, &q_data_array); CeedChk(ierr); 2390eaf62fffSJeremy L Thompson 2391eaf62fffSJeremy L Thompson // Setup FDM operator 2392eaf62fffSJeremy L Thompson // -- Basis 2393eaf62fffSJeremy L Thompson CeedBasis fdm_basis; 2394eaf62fffSJeremy L Thompson CeedScalar *grad_dummy, *q_ref_dummy, *q_weight_dummy; 2395eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &grad_dummy); CeedChk(ierr); 2396eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d, &q_ref_dummy); CeedChk(ierr); 2397eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d, &q_weight_dummy); CeedChk(ierr); 2398eaf62fffSJeremy L Thompson ierr = CeedBasisCreateTensorH1(ceed_parent, dim, num_comp, P_1d, P_1d, 2399eaf62fffSJeremy L Thompson fdm_interp, grad_dummy, q_ref_dummy, 2400eaf62fffSJeremy L Thompson q_weight_dummy, &fdm_basis); CeedChk(ierr); 2401eaf62fffSJeremy L Thompson ierr = CeedFree(&fdm_interp); CeedChk(ierr); 2402eaf62fffSJeremy L Thompson ierr = CeedFree(&grad_dummy); CeedChk(ierr); 2403eaf62fffSJeremy L Thompson ierr = CeedFree(&q_ref_dummy); CeedChk(ierr); 2404eaf62fffSJeremy L Thompson ierr = CeedFree(&q_weight_dummy); CeedChk(ierr); 2405eaf62fffSJeremy L Thompson ierr = CeedFree(&lambda); CeedChk(ierr); 2406eaf62fffSJeremy L Thompson 2407eaf62fffSJeremy L Thompson // -- Restriction 2408eaf62fffSJeremy L Thompson CeedElemRestriction rstr_qd_i; 2409eaf62fffSJeremy L Thompson CeedInt strides[3] = {1, elem_size, elem_size*num_comp}; 2410eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionCreateStrided(ceed_parent, num_elem, elem_size, 2411eaf62fffSJeremy L Thompson num_comp, num_elem*num_comp*elem_size, 2412eaf62fffSJeremy L Thompson strides, &rstr_qd_i); CeedChk(ierr); 2413eaf62fffSJeremy L Thompson // -- QFunction 2414eaf62fffSJeremy L Thompson CeedQFunction qf_fdm; 2415eaf62fffSJeremy L Thompson ierr = CeedQFunctionCreateInteriorByName(ceed_parent, "Scale", &qf_fdm); 2416eaf62fffSJeremy L Thompson CeedChk(ierr); 2417eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_fdm, "input", num_comp, CEED_EVAL_INTERP); 2418eaf62fffSJeremy L Thompson CeedChk(ierr); 2419eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_fdm, "scale", num_comp, CEED_EVAL_NONE); 2420eaf62fffSJeremy L Thompson CeedChk(ierr); 2421eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddOutput(qf_fdm, "output", num_comp, CEED_EVAL_INTERP); 2422eaf62fffSJeremy L Thompson CeedChk(ierr); 24236e15d496SJeremy L Thompson ierr = CeedQFunctionSetUserFlopsEstimate(qf_fdm, num_comp); CeedChk(ierr); 2424eaf62fffSJeremy L Thompson // -- QFunction context 2425eaf62fffSJeremy L Thompson CeedInt *num_comp_data; 2426eaf62fffSJeremy L Thompson ierr = CeedCalloc(1, &num_comp_data); CeedChk(ierr); 2427eaf62fffSJeremy L Thompson num_comp_data[0] = num_comp; 2428eaf62fffSJeremy L Thompson CeedQFunctionContext ctx_fdm; 2429eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextCreate(ceed, &ctx_fdm); CeedChk(ierr); 2430eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextSetData(ctx_fdm, CEED_MEM_HOST, CEED_OWN_POINTER, 2431eaf62fffSJeremy L Thompson sizeof(*num_comp_data), num_comp_data); 2432eaf62fffSJeremy L Thompson CeedChk(ierr); 2433eaf62fffSJeremy L Thompson ierr = CeedQFunctionSetContext(qf_fdm, ctx_fdm); CeedChk(ierr); 2434eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextDestroy(&ctx_fdm); CeedChk(ierr); 2435eaf62fffSJeremy L Thompson // -- Operator 2436eaf62fffSJeremy L Thompson ierr = CeedOperatorCreate(ceed_parent, qf_fdm, NULL, NULL, fdm_inv); 2437eaf62fffSJeremy L Thompson CeedChk(ierr); 2438eaf62fffSJeremy L Thompson CeedOperatorSetField(*fdm_inv, "input", rstr, fdm_basis, CEED_VECTOR_ACTIVE); 2439eaf62fffSJeremy L Thompson CeedChk(ierr); 2440eaf62fffSJeremy L Thompson CeedOperatorSetField(*fdm_inv, "scale", rstr_qd_i, CEED_BASIS_COLLOCATED, 2441eaf62fffSJeremy L Thompson q_data); CeedChk(ierr); 2442eaf62fffSJeremy L Thompson CeedOperatorSetField(*fdm_inv, "output", rstr, fdm_basis, CEED_VECTOR_ACTIVE); 2443eaf62fffSJeremy L Thompson CeedChk(ierr); 2444eaf62fffSJeremy L Thompson 2445eaf62fffSJeremy L Thompson // Cleanup 2446eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&q_data); CeedChk(ierr); 2447eaf62fffSJeremy L Thompson ierr = CeedBasisDestroy(&fdm_basis); CeedChk(ierr); 2448eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr_qd_i); CeedChk(ierr); 2449eaf62fffSJeremy L Thompson ierr = CeedQFunctionDestroy(&qf_fdm); CeedChk(ierr); 2450eaf62fffSJeremy L Thompson 2451eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2452eaf62fffSJeremy L Thompson } 2453eaf62fffSJeremy L Thompson 2454eaf62fffSJeremy L Thompson /// @} 2455