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> 12ed9e99e6SJeremy L Thompson #include <assert.h> 13eaf62fffSJeremy L Thompson #include <stdbool.h> 14eaf62fffSJeremy L Thompson #include <stdio.h> 15eaf62fffSJeremy L Thompson #include <string.h> 16eaf62fffSJeremy L Thompson 17eaf62fffSJeremy L Thompson /// @file 18eaf62fffSJeremy L Thompson /// Implementation of CeedOperator preconditioning interfaces 19eaf62fffSJeremy L Thompson 20eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 21eaf62fffSJeremy L Thompson /// CeedOperator Library Internal Preconditioning Functions 22eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 23eaf62fffSJeremy L Thompson /// @addtogroup CeedOperatorDeveloper 24eaf62fffSJeremy L Thompson /// @{ 25eaf62fffSJeremy L Thompson 26eaf62fffSJeremy L Thompson /** 279e77b9c8SJeremy L Thompson @brief Duplicate a CeedQFunction with a reference Ceed to fallback for advanced 289e77b9c8SJeremy L Thompson CeedOperator functionality 299e77b9c8SJeremy L Thompson 3001ea9c81SJed Brown @param[in] fallback_ceed Ceed on which to create fallback CeedQFunction 319e77b9c8SJeremy L Thompson @param[in] qf CeedQFunction to create fallback for 3201ea9c81SJed Brown @param[out] qf_fallback fallback CeedQFunction 339e77b9c8SJeremy L Thompson 349e77b9c8SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 359e77b9c8SJeremy L Thompson 369e77b9c8SJeremy L Thompson @ref Developer 379e77b9c8SJeremy L Thompson **/ 389e77b9c8SJeremy L Thompson static int CeedQFunctionCreateFallback(Ceed fallback_ceed, CeedQFunction qf, 399e77b9c8SJeremy L Thompson CeedQFunction *qf_fallback) { 409e77b9c8SJeremy L Thompson int ierr; 419e77b9c8SJeremy L Thompson 429e77b9c8SJeremy L Thompson // Check if NULL qf passed in 439e77b9c8SJeremy L Thompson if (!qf) return CEED_ERROR_SUCCESS; 449e77b9c8SJeremy L Thompson 45d04bbc78SJeremy L Thompson CeedDebug256(qf->ceed, 1, "---------- CeedOperator Fallback ----------\n"); 46d04bbc78SJeremy L Thompson CeedDebug256(qf->ceed, 255, "Creating fallback CeedQFunction\n"); 47d04bbc78SJeremy L Thompson 489e77b9c8SJeremy L Thompson char *source_path_with_name = ""; 499e77b9c8SJeremy L Thompson if (qf->source_path) { 509e77b9c8SJeremy L Thompson size_t path_len = strlen(qf->source_path), 519e77b9c8SJeremy L Thompson name_len = strlen(qf->kernel_name); 529e77b9c8SJeremy L Thompson ierr = CeedCalloc(path_len + name_len + 2, &source_path_with_name); 539e77b9c8SJeremy L Thompson CeedChk(ierr); 549e77b9c8SJeremy L Thompson memcpy(source_path_with_name, qf->source_path, path_len); 559e77b9c8SJeremy L Thompson memcpy(&source_path_with_name[path_len], ":", 1); 569e77b9c8SJeremy L Thompson memcpy(&source_path_with_name[path_len + 1], qf->kernel_name, name_len); 579e77b9c8SJeremy L Thompson } else { 589e77b9c8SJeremy L Thompson ierr = CeedCalloc(1, &source_path_with_name); CeedChk(ierr); 599e77b9c8SJeremy L Thompson } 609e77b9c8SJeremy L Thompson 619e77b9c8SJeremy L Thompson ierr = CeedQFunctionCreateInterior(fallback_ceed, qf->vec_length, 629e77b9c8SJeremy L Thompson qf->function, source_path_with_name, 639e77b9c8SJeremy L Thompson qf_fallback); CeedChk(ierr); 649e77b9c8SJeremy L Thompson { 659e77b9c8SJeremy L Thompson CeedQFunctionContext ctx; 669e77b9c8SJeremy L Thompson 679e77b9c8SJeremy L Thompson ierr = CeedQFunctionGetContext(qf, &ctx); CeedChk(ierr); 689e77b9c8SJeremy L Thompson ierr = CeedQFunctionSetContext(*qf_fallback, ctx); CeedChk(ierr); 699e77b9c8SJeremy L Thompson } 709e77b9c8SJeremy L Thompson for (CeedInt i = 0; i < qf->num_input_fields; i++) { 719e77b9c8SJeremy L Thompson ierr = CeedQFunctionAddInput(*qf_fallback, qf->input_fields[i]->field_name, 729e77b9c8SJeremy L Thompson qf->input_fields[i]->size, 739e77b9c8SJeremy L Thompson qf->input_fields[i]->eval_mode); CeedChk(ierr); 749e77b9c8SJeremy L Thompson } 759e77b9c8SJeremy L Thompson for (CeedInt i = 0; i < qf->num_output_fields; i++) { 769e77b9c8SJeremy L Thompson ierr = CeedQFunctionAddOutput(*qf_fallback, qf->output_fields[i]->field_name, 779e77b9c8SJeremy L Thompson qf->output_fields[i]->size, 789e77b9c8SJeremy L Thompson qf->output_fields[i]->eval_mode); CeedChk(ierr); 799e77b9c8SJeremy L Thompson } 809e77b9c8SJeremy L Thompson ierr = CeedFree(&source_path_with_name); CeedChk(ierr); 819e77b9c8SJeremy L Thompson 829e77b9c8SJeremy L Thompson return CEED_ERROR_SUCCESS; 839e77b9c8SJeremy L Thompson } 849e77b9c8SJeremy L Thompson 859e77b9c8SJeremy L Thompson /** 86eaf62fffSJeremy L Thompson @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced 87eaf62fffSJeremy L Thompson CeedOperator functionality 88eaf62fffSJeremy L Thompson 89eaf62fffSJeremy L Thompson @param op CeedOperator to create fallback for 90eaf62fffSJeremy L Thompson 91eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 92eaf62fffSJeremy L Thompson 93eaf62fffSJeremy L Thompson @ref Developer 94eaf62fffSJeremy L Thompson **/ 95d04bbc78SJeremy L Thompson static int CeedOperatorCreateFallback(CeedOperator op) { 96eaf62fffSJeremy L Thompson int ierr; 979e77b9c8SJeremy L Thompson Ceed ceed_fallback; 98eaf62fffSJeremy L Thompson 99805fe78eSJeremy L Thompson // Check not already created 100805fe78eSJeremy L Thompson if (op->op_fallback) return CEED_ERROR_SUCCESS; 101805fe78eSJeremy L Thompson 102eaf62fffSJeremy L Thompson // Fallback Ceed 1039e77b9c8SJeremy L Thompson ierr = CeedGetOperatorFallbackCeed(op->ceed, &ceed_fallback); CeedChk(ierr); 104d04bbc78SJeremy L Thompson if (!ceed_fallback) return CEED_ERROR_SUCCESS; 105d04bbc78SJeremy L Thompson 106d04bbc78SJeremy L Thompson CeedDebug256(op->ceed, 1, "---------- CeedOperator Fallback ----------\n"); 107d04bbc78SJeremy L Thompson CeedDebug256(op->ceed, 255, "Creating fallback CeedOperator\n"); 108eaf62fffSJeremy L Thompson 109eaf62fffSJeremy L Thompson // Clone Op 110805fe78eSJeremy L Thompson CeedOperator op_fallback; 111805fe78eSJeremy L Thompson if (op->is_composite) { 1129e77b9c8SJeremy L Thompson ierr = CeedCompositeOperatorCreate(ceed_fallback, &op_fallback); 113805fe78eSJeremy L Thompson CeedChk(ierr); 114805fe78eSJeremy L Thompson for (CeedInt i = 0; i < op->num_suboperators; i++) { 115d04bbc78SJeremy L Thompson CeedOperator op_sub_fallback; 116d04bbc78SJeremy L Thompson 117d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op->sub_operators[i], &op_sub_fallback); 118805fe78eSJeremy L Thompson CeedChk(ierr); 119d04bbc78SJeremy L Thompson ierr = CeedCompositeOperatorAddSub(op_fallback, op_sub_fallback); CeedChk(ierr); 120805fe78eSJeremy L Thompson } 121805fe78eSJeremy L Thompson } else { 1229e77b9c8SJeremy L Thompson CeedQFunction qf_fallback = NULL, dqf_fallback = NULL, dqfT_fallback = NULL; 1239e77b9c8SJeremy L Thompson ierr = CeedQFunctionCreateFallback(ceed_fallback, op->qf, &qf_fallback); 1249e77b9c8SJeremy L Thompson CeedChk(ierr); 1259e77b9c8SJeremy L Thompson ierr = CeedQFunctionCreateFallback(ceed_fallback, op->dqf, &dqf_fallback); 1269e77b9c8SJeremy L Thompson CeedChk(ierr); 1279e77b9c8SJeremy L Thompson ierr = CeedQFunctionCreateFallback(ceed_fallback, op->dqfT, &dqfT_fallback); 1289e77b9c8SJeremy L Thompson CeedChk(ierr); 1299e77b9c8SJeremy L Thompson ierr = CeedOperatorCreate(ceed_fallback, qf_fallback, dqf_fallback, 1309e77b9c8SJeremy L Thompson dqfT_fallback, &op_fallback); CeedChk(ierr); 131805fe78eSJeremy L Thompson for (CeedInt i = 0; i < op->qf->num_input_fields; i++) { 132805fe78eSJeremy L Thompson ierr = CeedOperatorSetField(op_fallback, op->input_fields[i]->field_name, 133805fe78eSJeremy L Thompson op->input_fields[i]->elem_restr, 134805fe78eSJeremy L Thompson op->input_fields[i]->basis, 135805fe78eSJeremy L Thompson op->input_fields[i]->vec); CeedChk(ierr); 136805fe78eSJeremy L Thompson } 137805fe78eSJeremy L Thompson for (CeedInt i = 0; i < op->qf->num_output_fields; i++) { 138805fe78eSJeremy L Thompson ierr = CeedOperatorSetField(op_fallback, op->output_fields[i]->field_name, 139805fe78eSJeremy L Thompson op->output_fields[i]->elem_restr, 140805fe78eSJeremy L Thompson op->output_fields[i]->basis, 141805fe78eSJeremy L Thompson op->output_fields[i]->vec); CeedChk(ierr); 142805fe78eSJeremy L Thompson } 143480fae85SJeremy L Thompson ierr = CeedQFunctionAssemblyDataReferenceCopy(op->qf_assembled, 144805fe78eSJeremy L Thompson &op_fallback->qf_assembled); CeedChk(ierr); 145805fe78eSJeremy L Thompson if (op_fallback->num_qpts == 0) { 146805fe78eSJeremy L Thompson ierr = CeedOperatorSetNumQuadraturePoints(op_fallback, op->num_qpts); 147805fe78eSJeremy L Thompson CeedChk(ierr); 148805fe78eSJeremy L Thompson } 1499e77b9c8SJeremy L Thompson // Cleanup 1509e77b9c8SJeremy L Thompson ierr = CeedQFunctionDestroy(&qf_fallback); CeedChk(ierr); 1519e77b9c8SJeremy L Thompson ierr = CeedQFunctionDestroy(&dqf_fallback); CeedChk(ierr); 1529e77b9c8SJeremy L Thompson ierr = CeedQFunctionDestroy(&dqfT_fallback); CeedChk(ierr); 153805fe78eSJeremy L Thompson } 154805fe78eSJeremy L Thompson ierr = CeedOperatorSetName(op_fallback, op->name); CeedChk(ierr); 155805fe78eSJeremy L Thompson ierr = CeedOperatorCheckReady(op_fallback); CeedChk(ierr); 156805fe78eSJeremy L Thompson op->op_fallback = op_fallback; 157eaf62fffSJeremy L Thompson 158eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 159eaf62fffSJeremy L Thompson } 160eaf62fffSJeremy L Thompson 161eaf62fffSJeremy L Thompson /** 162d04bbc78SJeremy L Thompson @brief Retreive fallback CeedOperator with a reference Ceed for advanced CeedOperator functionality 163d04bbc78SJeremy L Thompson 164d04bbc78SJeremy L Thompson @param[in] op CeedOperator to retrieve fallback for 165d04bbc78SJeremy L Thompson @param[out] op_fallback Fallback CeedOperator 166d04bbc78SJeremy L Thompson 167d04bbc78SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 168d04bbc78SJeremy L Thompson 169d04bbc78SJeremy L Thompson @ref Developer 170d04bbc78SJeremy L Thompson **/ 171d04bbc78SJeremy L Thompson int CeedOperatorGetFallback(CeedOperator op, CeedOperator *op_fallback) { 172d04bbc78SJeremy L Thompson int ierr; 173d04bbc78SJeremy L Thompson 174d04bbc78SJeremy L Thompson // Create if needed 175d04bbc78SJeremy L Thompson if (!op->op_fallback) { 176d04bbc78SJeremy L Thompson ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 177d04bbc78SJeremy L Thompson } 178d04bbc78SJeremy L Thompson if (op->op_fallback) { 179d04bbc78SJeremy L Thompson bool is_debug; 180d04bbc78SJeremy L Thompson 181d04bbc78SJeremy L Thompson ierr = CeedIsDebug(op->ceed, &is_debug); CeedChk(ierr); 182d04bbc78SJeremy L Thompson if (is_debug) { 183d04bbc78SJeremy L Thompson Ceed ceed_fallback; 184d04bbc78SJeremy L Thompson const char *resource, *resource_fallback; 185d04bbc78SJeremy L Thompson 186d04bbc78SJeremy L Thompson ierr = CeedGetOperatorFallbackCeed(op->ceed, &ceed_fallback); CeedChk(ierr); 187d04bbc78SJeremy L Thompson ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr); 188d04bbc78SJeremy L Thompson ierr = CeedGetResource(ceed_fallback, &resource_fallback); CeedChk(ierr); 189d04bbc78SJeremy L Thompson 190d04bbc78SJeremy L Thompson CeedDebug256(op->ceed, 1, "---------- CeedOperator Fallback ----------\n"); 191d04bbc78SJeremy L Thompson CeedDebug256(op->ceed, 255, 192d04bbc78SJeremy L Thompson "Falling back from %s operator at address %ld to %s operator at address %ld\n", 193d04bbc78SJeremy L Thompson resource, op, resource_fallback, op->op_fallback); 194d04bbc78SJeremy L Thompson } 195d04bbc78SJeremy L Thompson } 196d04bbc78SJeremy L Thompson *op_fallback = op->op_fallback; 197d04bbc78SJeremy L Thompson 198d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 199d04bbc78SJeremy L Thompson } 200d04bbc78SJeremy L Thompson 201d04bbc78SJeremy L Thompson /** 202eaf62fffSJeremy L Thompson @brief Select correct basis matrix pointer based on CeedEvalMode 203eaf62fffSJeremy L Thompson 204eaf62fffSJeremy L Thompson @param[in] eval_mode Current basis evaluation mode 205eaf62fffSJeremy L Thompson @param[in] identity Pointer to identity matrix 206eaf62fffSJeremy L Thompson @param[in] interp Pointer to interpolation matrix 207eaf62fffSJeremy L Thompson @param[in] grad Pointer to gradient matrix 208eaf62fffSJeremy L Thompson @param[out] basis_ptr Basis pointer to set 209eaf62fffSJeremy L Thompson 210eaf62fffSJeremy L Thompson @ref Developer 211eaf62fffSJeremy L Thompson **/ 212eaf62fffSJeremy L Thompson static inline void CeedOperatorGetBasisPointer(CeedEvalMode eval_mode, 213eaf62fffSJeremy L Thompson const CeedScalar *identity, const CeedScalar *interp, 214eaf62fffSJeremy L Thompson const CeedScalar *grad, const CeedScalar **basis_ptr) { 215eaf62fffSJeremy L Thompson switch (eval_mode) { 216eaf62fffSJeremy L Thompson case CEED_EVAL_NONE: 217eaf62fffSJeremy L Thompson *basis_ptr = identity; 218eaf62fffSJeremy L Thompson break; 219eaf62fffSJeremy L Thompson case CEED_EVAL_INTERP: 220eaf62fffSJeremy L Thompson *basis_ptr = interp; 221eaf62fffSJeremy L Thompson break; 222eaf62fffSJeremy L Thompson case CEED_EVAL_GRAD: 223eaf62fffSJeremy L Thompson *basis_ptr = grad; 224eaf62fffSJeremy L Thompson break; 225eaf62fffSJeremy L Thompson case CEED_EVAL_WEIGHT: 226eaf62fffSJeremy L Thompson case CEED_EVAL_DIV: 227eaf62fffSJeremy L Thompson case CEED_EVAL_CURL: 228eaf62fffSJeremy L Thompson break; // Caught by QF Assembly 229eaf62fffSJeremy L Thompson } 230ed9e99e6SJeremy L Thompson assert(*basis_ptr != NULL); 231eaf62fffSJeremy L Thompson } 232eaf62fffSJeremy L Thompson 233eaf62fffSJeremy L Thompson /** 234eaf62fffSJeremy L Thompson @brief Create point block restriction for active operator field 235eaf62fffSJeremy L Thompson 236eaf62fffSJeremy L Thompson @param[in] rstr Original CeedElemRestriction for active field 237eaf62fffSJeremy L Thompson @param[out] pointblock_rstr Address of the variable where the newly created 238eaf62fffSJeremy L Thompson CeedElemRestriction will be stored 239eaf62fffSJeremy L Thompson 240eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 241eaf62fffSJeremy L Thompson 242eaf62fffSJeremy L Thompson @ref Developer 243eaf62fffSJeremy L Thompson **/ 244eaf62fffSJeremy L Thompson static int CeedOperatorCreateActivePointBlockRestriction( 245eaf62fffSJeremy L Thompson CeedElemRestriction rstr, 246eaf62fffSJeremy L Thompson CeedElemRestriction *pointblock_rstr) { 247eaf62fffSJeremy L Thompson int ierr; 248eaf62fffSJeremy L Thompson Ceed ceed; 249eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetCeed(rstr, &ceed); CeedChk(ierr); 250eaf62fffSJeremy L Thompson const CeedInt *offsets; 251eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets); 252eaf62fffSJeremy L Thompson CeedChk(ierr); 253eaf62fffSJeremy L Thompson 254eaf62fffSJeremy L Thompson // Expand offsets 255eaf62fffSJeremy L Thompson CeedInt num_elem, num_comp, elem_size, comp_stride, max = 1, 256eaf62fffSJeremy L Thompson *pointblock_offsets; 257eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr); 258eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumComponents(rstr, &num_comp); CeedChk(ierr); 259eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr, &elem_size); CeedChk(ierr); 260eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetCompStride(rstr, &comp_stride); CeedChk(ierr); 261eaf62fffSJeremy L Thompson CeedInt shift = num_comp; 262eaf62fffSJeremy L Thompson if (comp_stride != 1) 263eaf62fffSJeremy L Thompson shift *= num_comp; 264eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_elem*elem_size, &pointblock_offsets); 265eaf62fffSJeremy L Thompson CeedChk(ierr); 266eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_elem*elem_size; i++) { 267eaf62fffSJeremy L Thompson pointblock_offsets[i] = offsets[i]*shift; 268eaf62fffSJeremy L Thompson if (pointblock_offsets[i] > max) 269eaf62fffSJeremy L Thompson max = pointblock_offsets[i]; 270eaf62fffSJeremy L Thompson } 271eaf62fffSJeremy L Thompson 272eaf62fffSJeremy L Thompson // Create new restriction 273eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionCreate(ceed, num_elem, elem_size, num_comp*num_comp, 274eaf62fffSJeremy L Thompson 1, max + num_comp*num_comp, CEED_MEM_HOST, 275eaf62fffSJeremy L Thompson CEED_OWN_POINTER, pointblock_offsets, pointblock_rstr); 276eaf62fffSJeremy L Thompson CeedChk(ierr); 277eaf62fffSJeremy L Thompson 278eaf62fffSJeremy L Thompson // Cleanup 279eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionRestoreOffsets(rstr, &offsets); CeedChk(ierr); 280eaf62fffSJeremy L Thompson 281eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 282eaf62fffSJeremy L Thompson } 283eaf62fffSJeremy L Thompson 284eaf62fffSJeremy L Thompson /** 285eaf62fffSJeremy L Thompson @brief Core logic for assembling operator diagonal or point block diagonal 286eaf62fffSJeremy L Thompson 287eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble point block diagonal 288eaf62fffSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else 289eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 290eaf62fffSJeremy L Thompson @param[in] is_pointblock Boolean flag to assemble diagonal or point block diagonal 291eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled diagonal 292eaf62fffSJeremy L Thompson 293eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 294eaf62fffSJeremy L Thompson 295eaf62fffSJeremy L Thompson @ref Developer 296eaf62fffSJeremy L Thompson **/ 297eaf62fffSJeremy L Thompson static inline int CeedSingleOperatorAssembleAddDiagonal(CeedOperator op, 298eaf62fffSJeremy L Thompson CeedRequest *request, const bool is_pointblock, CeedVector assembled) { 299eaf62fffSJeremy L Thompson int ierr; 300eaf62fffSJeremy L Thompson Ceed ceed; 301eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 302eaf62fffSJeremy L Thompson 303eaf62fffSJeremy L Thompson // Assemble QFunction 304eaf62fffSJeremy L Thompson CeedQFunction qf; 305eaf62fffSJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr); 306eaf62fffSJeremy L Thompson CeedInt num_input_fields, num_output_fields; 307eaf62fffSJeremy L Thompson ierr= CeedQFunctionGetNumArgs(qf, &num_input_fields, &num_output_fields); 308eaf62fffSJeremy L Thompson CeedChk(ierr); 309eaf62fffSJeremy L Thompson CeedVector assembled_qf; 310eaf62fffSJeremy L Thompson CeedElemRestriction rstr; 31170a7ffb3SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled_qf, 31270a7ffb3SJeremy L Thompson &rstr, request); CeedChk(ierr); 313eaf62fffSJeremy L Thompson CeedInt layout[3]; 314eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetELayout(rstr, &layout); CeedChk(ierr); 315eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr); 316eaf62fffSJeremy L Thompson CeedScalar max_norm = 0; 317eaf62fffSJeremy L Thompson ierr = CeedVectorNorm(assembled_qf, CEED_NORM_MAX, &max_norm); CeedChk(ierr); 318eaf62fffSJeremy L Thompson 319ed9e99e6SJeremy L Thompson // Get assembly data 320ed9e99e6SJeremy L Thompson CeedOperatorAssemblyData data; 321ed9e99e6SJeremy L Thompson ierr = CeedOperatorGetOperatorAssemblyData(op, &data); CeedChk(ierr); 322ed9e99e6SJeremy L Thompson const CeedEvalMode *eval_mode_in, *eval_mode_out; 323ed9e99e6SJeremy L Thompson CeedInt num_eval_mode_in, num_eval_mode_out; 324ed9e99e6SJeremy L Thompson ierr = CeedOperatorAssemblyDataGetEvalModes(data, &num_eval_mode_in, 325ed9e99e6SJeremy L Thompson &eval_mode_in, &num_eval_mode_out, &eval_mode_out); CeedChk(ierr); 326ed9e99e6SJeremy L Thompson CeedBasis basis_in, basis_out; 327ed9e99e6SJeremy L Thompson ierr = CeedOperatorAssemblyDataGetBases(data, &basis_in, NULL, &basis_out, 328ed9e99e6SJeremy L Thompson NULL); CeedChk(ierr); 329ed9e99e6SJeremy L Thompson CeedInt num_comp; 330eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis_in, &num_comp); CeedChk(ierr); 331eaf62fffSJeremy L Thompson 332eaf62fffSJeremy L Thompson // Assemble point block diagonal restriction, if needed 333ed9e99e6SJeremy L Thompson CeedElemRestriction diag_rstr; 334ed9e99e6SJeremy L Thompson ierr = CeedOperatorGetActiveElemRestriction(op, &diag_rstr); CeedChk(ierr); 335eaf62fffSJeremy L Thompson if (is_pointblock) { 336ed9e99e6SJeremy L Thompson CeedElemRestriction point_block_rstr; 337ed9e99e6SJeremy L Thompson ierr = CeedOperatorCreateActivePointBlockRestriction(diag_rstr, 338ed9e99e6SJeremy L Thompson &point_block_rstr); 339eaf62fffSJeremy L Thompson CeedChk(ierr); 340ed9e99e6SJeremy L Thompson diag_rstr = point_block_rstr; 341eaf62fffSJeremy L Thompson } 342eaf62fffSJeremy L Thompson 343eaf62fffSJeremy L Thompson // Create diagonal vector 344eaf62fffSJeremy L Thompson CeedVector elem_diag; 345eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionCreateVector(diag_rstr, NULL, &elem_diag); 346eaf62fffSJeremy L Thompson CeedChk(ierr); 347eaf62fffSJeremy L Thompson 348eaf62fffSJeremy L Thompson // Assemble element operator diagonals 3499c774eddSJeremy L Thompson CeedScalar *elem_diag_array; 3509c774eddSJeremy L Thompson const CeedScalar *assembled_qf_array; 351eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(elem_diag, 0.0); CeedChk(ierr); 352eaf62fffSJeremy L Thompson ierr = CeedVectorGetArray(elem_diag, CEED_MEM_HOST, &elem_diag_array); 353eaf62fffSJeremy L Thompson CeedChk(ierr); 3549c774eddSJeremy L Thompson ierr = CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array); 355eaf62fffSJeremy L Thompson CeedChk(ierr); 356eaf62fffSJeremy L Thompson CeedInt num_elem, num_nodes, num_qpts; 357eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(diag_rstr, &num_elem); CeedChk(ierr); 358eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis_in, &num_nodes); CeedChk(ierr); 359eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts); CeedChk(ierr); 360ed9e99e6SJeremy L Thompson 361eaf62fffSJeremy L Thompson // Basis matrices 362eaf62fffSJeremy L Thompson const CeedScalar *interp_in, *interp_out, *grad_in, *grad_out; 363eaf62fffSJeremy L Thompson CeedScalar *identity = NULL; 364ed9e99e6SJeremy L Thompson bool has_eval_none = false; 365ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < num_eval_mode_in; i++) { 366ed9e99e6SJeremy L Thompson has_eval_none = has_eval_none || (eval_mode_in[i] == CEED_EVAL_NONE); 367ed9e99e6SJeremy L Thompson } 368ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i<num_eval_mode_out; i++) { 369ed9e99e6SJeremy L Thompson has_eval_none = has_eval_none || (eval_mode_out[i] == CEED_EVAL_NONE); 370ed9e99e6SJeremy L Thompson } 371ed9e99e6SJeremy L Thompson if (has_eval_none) { 372eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_qpts*num_nodes, &identity); CeedChk(ierr); 373eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < (num_nodes < num_qpts ? num_nodes : num_qpts); i++) 374eaf62fffSJeremy L Thompson identity[i*num_nodes+i] = 1.0; 375eaf62fffSJeremy L Thompson } 376eaf62fffSJeremy L Thompson ierr = CeedBasisGetInterp(basis_in, &interp_in); CeedChk(ierr); 377eaf62fffSJeremy L Thompson ierr = CeedBasisGetInterp(basis_out, &interp_out); CeedChk(ierr); 378eaf62fffSJeremy L Thompson ierr = CeedBasisGetGrad(basis_in, &grad_in); CeedChk(ierr); 379eaf62fffSJeremy L Thompson ierr = CeedBasisGetGrad(basis_out, &grad_out); CeedChk(ierr); 380eaf62fffSJeremy L Thompson // Compute the diagonal of B^T D B 381eaf62fffSJeremy L Thompson // Each element 382eaf62fffSJeremy L Thompson const CeedScalar qf_value_bound = max_norm*100*CEED_EPSILON; 383eaf62fffSJeremy L Thompson for (CeedInt e=0; e<num_elem; e++) { 384eaf62fffSJeremy L Thompson CeedInt d_out = -1; 385eaf62fffSJeremy L Thompson // Each basis eval mode pair 386eaf62fffSJeremy L Thompson for (CeedInt e_out=0; e_out<num_eval_mode_out; e_out++) { 387eaf62fffSJeremy L Thompson const CeedScalar *bt = NULL; 388eaf62fffSJeremy L Thompson if (eval_mode_out[e_out] == CEED_EVAL_GRAD) 389eaf62fffSJeremy L Thompson d_out += 1; 390eaf62fffSJeremy L Thompson CeedOperatorGetBasisPointer(eval_mode_out[e_out], identity, interp_out, 391eaf62fffSJeremy L Thompson &grad_out[d_out*num_qpts*num_nodes], &bt); 392eaf62fffSJeremy L Thompson CeedInt d_in = -1; 393eaf62fffSJeremy L Thompson for (CeedInt e_in=0; e_in<num_eval_mode_in; e_in++) { 394eaf62fffSJeremy L Thompson const CeedScalar *b = NULL; 395eaf62fffSJeremy L Thompson if (eval_mode_in[e_in] == CEED_EVAL_GRAD) 396eaf62fffSJeremy L Thompson d_in += 1; 397eaf62fffSJeremy L Thompson CeedOperatorGetBasisPointer(eval_mode_in[e_in], identity, interp_in, 398eaf62fffSJeremy L Thompson &grad_in[d_in*num_qpts*num_nodes], &b); 399eaf62fffSJeremy L Thompson // Each component 400eaf62fffSJeremy L Thompson for (CeedInt c_out=0; c_out<num_comp; c_out++) 401eaf62fffSJeremy L Thompson // Each qpoint/node pair 402eaf62fffSJeremy L Thompson for (CeedInt q=0; q<num_qpts; q++) 403eaf62fffSJeremy L Thompson if (is_pointblock) { 404eaf62fffSJeremy L Thompson // Point Block Diagonal 405eaf62fffSJeremy L Thompson for (CeedInt c_in=0; c_in<num_comp; c_in++) { 406eaf62fffSJeremy L Thompson const CeedScalar qf_value = 407eaf62fffSJeremy L Thompson assembled_qf_array[q*layout[0] + (((e_in*num_comp+c_in)* 408eaf62fffSJeremy L Thompson num_eval_mode_out+e_out)*num_comp+c_out)*layout[1] + e*layout[2]]; 409eaf62fffSJeremy L Thompson if (fabs(qf_value) > qf_value_bound) 410eaf62fffSJeremy L Thompson for (CeedInt n=0; n<num_nodes; n++) 411eaf62fffSJeremy L Thompson elem_diag_array[((e*num_comp+c_out)*num_comp+c_in)*num_nodes+n] += 412eaf62fffSJeremy L Thompson bt[q*num_nodes+n] * qf_value * b[q*num_nodes+n]; 413eaf62fffSJeremy L Thompson } 414eaf62fffSJeremy L Thompson } else { 415eaf62fffSJeremy L Thompson // Diagonal Only 416eaf62fffSJeremy L Thompson const CeedScalar qf_value = 417eaf62fffSJeremy L Thompson assembled_qf_array[q*layout[0] + (((e_in*num_comp+c_out)* 418eaf62fffSJeremy L Thompson num_eval_mode_out+e_out)*num_comp+c_out)*layout[1] + e*layout[2]]; 419eaf62fffSJeremy L Thompson if (fabs(qf_value) > qf_value_bound) 420eaf62fffSJeremy L Thompson for (CeedInt n=0; n<num_nodes; n++) 421eaf62fffSJeremy L Thompson elem_diag_array[(e*num_comp+c_out)*num_nodes+n] += 422eaf62fffSJeremy L Thompson bt[q*num_nodes+n] * qf_value * b[q*num_nodes+n]; 423eaf62fffSJeremy L Thompson } 424eaf62fffSJeremy L Thompson } 425eaf62fffSJeremy L Thompson } 426eaf62fffSJeremy L Thompson } 427eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArray(elem_diag, &elem_diag_array); CeedChk(ierr); 4289c774eddSJeremy L Thompson ierr = CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array); 4299c774eddSJeremy L Thompson CeedChk(ierr); 430eaf62fffSJeremy L Thompson 431eaf62fffSJeremy L Thompson // Assemble local operator diagonal 432eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionApply(diag_rstr, CEED_TRANSPOSE, elem_diag, 433eaf62fffSJeremy L Thompson assembled, request); CeedChk(ierr); 434eaf62fffSJeremy L Thompson 435eaf62fffSJeremy L Thompson // Cleanup 436eaf62fffSJeremy L Thompson if (is_pointblock) { 437eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&diag_rstr); CeedChk(ierr); 438eaf62fffSJeremy L Thompson } 439eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&assembled_qf); CeedChk(ierr); 440eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&elem_diag); CeedChk(ierr); 441eaf62fffSJeremy L Thompson ierr = CeedFree(&identity); CeedChk(ierr); 442eaf62fffSJeremy L Thompson 443eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 444eaf62fffSJeremy L Thompson } 445eaf62fffSJeremy L Thompson 446eaf62fffSJeremy L Thompson /** 447eaf62fffSJeremy L Thompson @brief Core logic for assembling composite operator diagonal 448eaf62fffSJeremy L Thompson 449eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble point block diagonal 450eaf62fffSJeremy L Thompson @param[in] request Address of CeedRequest for non-blocking completion, else 451eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 452eaf62fffSJeremy L Thompson @param[in] is_pointblock Boolean flag to assemble diagonal or point block diagonal 453eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled diagonal 454eaf62fffSJeremy L Thompson 455eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 456eaf62fffSJeremy L Thompson 457eaf62fffSJeremy L Thompson @ref Developer 458eaf62fffSJeremy L Thompson **/ 459eaf62fffSJeremy L Thompson static inline int CeedCompositeOperatorLinearAssembleAddDiagonal( 460eaf62fffSJeremy L Thompson CeedOperator op, CeedRequest *request, const bool is_pointblock, 461eaf62fffSJeremy L Thompson CeedVector assembled) { 462eaf62fffSJeremy L Thompson int ierr; 463eaf62fffSJeremy L Thompson CeedInt num_sub; 464eaf62fffSJeremy L Thompson CeedOperator *suboperators; 465eaf62fffSJeremy L Thompson ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr); 466eaf62fffSJeremy L Thompson ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr); 467eaf62fffSJeremy L Thompson for (CeedInt i = 0; i < num_sub; i++) { 4686aa95790SJeremy L Thompson if (is_pointblock) { 4696aa95790SJeremy L Thompson ierr = CeedOperatorLinearAssembleAddPointBlockDiagonal(suboperators[i], 4706aa95790SJeremy L Thompson assembled, request); CeedChk(ierr); 4716aa95790SJeremy L Thompson } else { 4726aa95790SJeremy L Thompson ierr = CeedOperatorLinearAssembleAddDiagonal(suboperators[i], assembled, 4736aa95790SJeremy L Thompson request); CeedChk(ierr); 4746aa95790SJeremy L Thompson } 475eaf62fffSJeremy L Thompson } 476eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 477eaf62fffSJeremy L Thompson } 478eaf62fffSJeremy L Thompson 479eaf62fffSJeremy L Thompson /** 480eaf62fffSJeremy L Thompson @brief Build nonzero pattern for non-composite operator 481eaf62fffSJeremy L Thompson 482eaf62fffSJeremy L Thompson Users should generally use CeedOperatorLinearAssembleSymbolic() 483eaf62fffSJeremy L Thompson 484eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble nonzero pattern 485eaf62fffSJeremy L Thompson @param[in] offset Offset for number of entries 486eaf62fffSJeremy L Thompson @param[out] rows Row number for each entry 487eaf62fffSJeremy L Thompson @param[out] cols Column number for each entry 488eaf62fffSJeremy L Thompson 489eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 490eaf62fffSJeremy L Thompson 491eaf62fffSJeremy L Thompson @ref Developer 492eaf62fffSJeremy L Thompson **/ 493eaf62fffSJeremy L Thompson static int CeedSingleOperatorAssembleSymbolic(CeedOperator op, CeedInt offset, 494eaf62fffSJeremy L Thompson CeedInt *rows, CeedInt *cols) { 495eaf62fffSJeremy L Thompson int ierr; 496eaf62fffSJeremy L Thompson Ceed ceed = op->ceed; 497f04ea552SJeremy L Thompson if (op->is_composite) 498eaf62fffSJeremy L Thompson // LCOV_EXCL_START 499eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 500eaf62fffSJeremy L Thompson "Composite operator not supported"); 501eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 502eaf62fffSJeremy L Thompson 503c9366a6bSJeremy L Thompson CeedSize num_nodes; 504c9366a6bSJeremy L Thompson ierr = CeedOperatorGetActiveVectorLengths(op, &num_nodes, NULL); CeedChk(ierr); 505eaf62fffSJeremy L Thompson CeedElemRestriction rstr_in; 506eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveElemRestriction(op, &rstr_in); CeedChk(ierr); 507e79b91d9SJeremy L Thompson CeedInt num_elem, elem_size, num_comp; 508eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(rstr_in, &num_elem); CeedChk(ierr); 509eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr_in, &elem_size); CeedChk(ierr); 510eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumComponents(rstr_in, &num_comp); CeedChk(ierr); 511eaf62fffSJeremy L Thompson CeedInt layout_er[3]; 512eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetELayout(rstr_in, &layout_er); CeedChk(ierr); 513eaf62fffSJeremy L Thompson 514eaf62fffSJeremy L Thompson CeedInt local_num_entries = elem_size*num_comp * elem_size*num_comp * num_elem; 515eaf62fffSJeremy L Thompson 516eaf62fffSJeremy L Thompson // Determine elem_dof relation 517eaf62fffSJeremy L Thompson CeedVector index_vec; 518eaf62fffSJeremy L Thompson ierr = CeedVectorCreate(ceed, num_nodes, &index_vec); CeedChk(ierr); 519eaf62fffSJeremy L Thompson CeedScalar *array; 5209c774eddSJeremy L Thompson ierr = CeedVectorGetArrayWrite(index_vec, CEED_MEM_HOST, &array); CeedChk(ierr); 521ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < num_nodes; i++) array[i] = i; 522eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArray(index_vec, &array); CeedChk(ierr); 523eaf62fffSJeremy L Thompson CeedVector elem_dof; 524eaf62fffSJeremy L Thompson ierr = CeedVectorCreate(ceed, num_elem * elem_size * num_comp, &elem_dof); 525eaf62fffSJeremy L Thompson CeedChk(ierr); 526eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(elem_dof, 0.0); CeedChk(ierr); 527eaf62fffSJeremy L Thompson CeedElemRestrictionApply(rstr_in, CEED_NOTRANSPOSE, index_vec, 528eaf62fffSJeremy L Thompson elem_dof, CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 529eaf62fffSJeremy L Thompson const CeedScalar *elem_dof_a; 530eaf62fffSJeremy L Thompson ierr = CeedVectorGetArrayRead(elem_dof, CEED_MEM_HOST, &elem_dof_a); 531eaf62fffSJeremy L Thompson CeedChk(ierr); 532eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&index_vec); CeedChk(ierr); 533eaf62fffSJeremy L Thompson 534eaf62fffSJeremy L Thompson // Determine i, j locations for element matrices 535eaf62fffSJeremy L Thompson CeedInt count = 0; 536ed9e99e6SJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) { 537ed9e99e6SJeremy L Thompson for (CeedInt comp_in = 0; comp_in < num_comp; comp_in++) { 538ed9e99e6SJeremy L Thompson for (CeedInt comp_out = 0; comp_out < num_comp; comp_out++) { 539ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < elem_size; i++) { 540ed9e99e6SJeremy L Thompson for (CeedInt j = 0; j < elem_size; j++) { 541ed9e99e6SJeremy L Thompson const CeedInt elem_dof_index_row = i*layout_er[0] + 542eaf62fffSJeremy L Thompson (comp_out)*layout_er[1] + e*layout_er[2]; 543ed9e99e6SJeremy L Thompson const CeedInt elem_dof_index_col = j*layout_er[0] + 544ed9e99e6SJeremy L Thompson comp_in*layout_er[1] + e*layout_er[2]; 545eaf62fffSJeremy L Thompson 546eaf62fffSJeremy L Thompson const CeedInt row = elem_dof_a[elem_dof_index_row]; 547eaf62fffSJeremy L Thompson const CeedInt col = elem_dof_a[elem_dof_index_col]; 548eaf62fffSJeremy L Thompson 549eaf62fffSJeremy L Thompson rows[offset + count] = row; 550eaf62fffSJeremy L Thompson cols[offset + count] = col; 551eaf62fffSJeremy L Thompson count++; 552eaf62fffSJeremy L Thompson } 553eaf62fffSJeremy L Thompson } 554eaf62fffSJeremy L Thompson } 555eaf62fffSJeremy L Thompson } 556eaf62fffSJeremy L Thompson } 557eaf62fffSJeremy L Thompson if (count != local_num_entries) 558eaf62fffSJeremy L Thompson // LCOV_EXCL_START 559eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing assembled entries"); 560eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 561eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArrayRead(elem_dof, &elem_dof_a); CeedChk(ierr); 562eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&elem_dof); CeedChk(ierr); 563eaf62fffSJeremy L Thompson 564eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 565eaf62fffSJeremy L Thompson } 566eaf62fffSJeremy L Thompson 567eaf62fffSJeremy L Thompson /** 568eaf62fffSJeremy L Thompson @brief Assemble nonzero entries for non-composite operator 569eaf62fffSJeremy L Thompson 570eaf62fffSJeremy L Thompson Users should generally use CeedOperatorLinearAssemble() 571eaf62fffSJeremy L Thompson 572eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 57352b3e6a7SJed Brown @param[in] offset Offest for number of entries 574eaf62fffSJeremy L Thompson @param[out] values Values to assemble into matrix 575eaf62fffSJeremy L Thompson 576eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 577eaf62fffSJeremy L Thompson 578eaf62fffSJeremy L Thompson @ref Developer 579eaf62fffSJeremy L Thompson **/ 580eaf62fffSJeremy L Thompson static int CeedSingleOperatorAssemble(CeedOperator op, CeedInt offset, 581eaf62fffSJeremy L Thompson CeedVector values) { 582eaf62fffSJeremy L Thompson int ierr; 583eaf62fffSJeremy L Thompson Ceed ceed = op->ceed; 584f04ea552SJeremy L Thompson if (op->is_composite) 585eaf62fffSJeremy L Thompson // LCOV_EXCL_START 586eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 587eaf62fffSJeremy L Thompson "Composite operator not supported"); 588eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 58952b3e6a7SJed Brown if (op->num_elem == 0) return CEED_ERROR_SUCCESS; 590eaf62fffSJeremy L Thompson 591cefa2673SJeremy L Thompson if (op->LinearAssembleSingle) { 592cefa2673SJeremy L Thompson // Backend version 593cefa2673SJeremy L Thompson ierr = op->LinearAssembleSingle(op, offset, values); CeedChk(ierr); 594cefa2673SJeremy L Thompson return CEED_ERROR_SUCCESS; 595cefa2673SJeremy L Thompson } else { 596cefa2673SJeremy L Thompson // Operator fallback 597cefa2673SJeremy L Thompson CeedOperator op_fallback; 598cefa2673SJeremy L Thompson 599cefa2673SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 600cefa2673SJeremy L Thompson if (op_fallback) { 601cefa2673SJeremy L Thompson ierr = CeedSingleOperatorAssemble(op_fallback, offset, values); 602cefa2673SJeremy L Thompson CeedChk(ierr); 603cefa2673SJeremy L Thompson return CEED_ERROR_SUCCESS; 604cefa2673SJeremy L Thompson } 605cefa2673SJeremy L Thompson } 606cefa2673SJeremy L Thompson 607eaf62fffSJeremy L Thompson // Assemble QFunction 608eaf62fffSJeremy L Thompson CeedQFunction qf; 609eaf62fffSJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr); 610eaf62fffSJeremy L Thompson CeedVector assembled_qf; 611eaf62fffSJeremy L Thompson CeedElemRestriction rstr_q; 61270a7ffb3SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate( 613eaf62fffSJeremy L Thompson op, &assembled_qf, &rstr_q, CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 614ed9e99e6SJeremy L Thompson CeedScalar max_norm = 0; 615ed9e99e6SJeremy L Thompson ierr = CeedVectorNorm(assembled_qf, CEED_NORM_MAX, &max_norm); CeedChk(ierr); 6161f9221feSJeremy L Thompson CeedSize qf_length; 617eaf62fffSJeremy L Thompson ierr = CeedVectorGetLength(assembled_qf, &qf_length); CeedChk(ierr); 618eaf62fffSJeremy L Thompson 6197e7773b5SJeremy L Thompson CeedInt num_input_fields, num_output_fields; 620eaf62fffSJeremy L Thompson CeedOperatorField *input_fields; 621eaf62fffSJeremy L Thompson CeedOperatorField *output_fields; 6227e7773b5SJeremy L Thompson ierr = CeedOperatorGetFields(op, &num_input_fields, &input_fields, 6237e7773b5SJeremy L Thompson &num_output_fields, &output_fields); CeedChk(ierr); 624eaf62fffSJeremy L Thompson 625ed9e99e6SJeremy L Thompson // Get assembly data 626ed9e99e6SJeremy L Thompson CeedOperatorAssemblyData data; 627ed9e99e6SJeremy L Thompson ierr = CeedOperatorGetOperatorAssemblyData(op, &data); CeedChk(ierr); 628ed9e99e6SJeremy L Thompson const CeedEvalMode *eval_mode_in, *eval_mode_out; 629ed9e99e6SJeremy L Thompson CeedInt num_eval_mode_in, num_eval_mode_out; 630ed9e99e6SJeremy L Thompson ierr = CeedOperatorAssemblyDataGetEvalModes(data, &num_eval_mode_in, 631ed9e99e6SJeremy L Thompson &eval_mode_in, &num_eval_mode_out, &eval_mode_out); CeedChk(ierr); 632ed9e99e6SJeremy L Thompson CeedBasis basis_in, basis_out; 633ed9e99e6SJeremy L Thompson ierr = CeedOperatorAssemblyDataGetBases(data, &basis_in, NULL, &basis_out, 634ed9e99e6SJeremy L Thompson NULL); CeedChk(ierr); 635eaf62fffSJeremy L Thompson 636eaf62fffSJeremy L Thompson if (num_eval_mode_in == 0 || num_eval_mode_out == 0) 637eaf62fffSJeremy L Thompson // LCOV_EXCL_START 638eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 639eaf62fffSJeremy L Thompson "Cannot assemble operator with out inputs/outputs"); 640eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 641eaf62fffSJeremy L Thompson 642ed9e99e6SJeremy L Thompson CeedElemRestriction active_rstr; 643eaf62fffSJeremy L Thompson CeedInt num_elem, elem_size, num_qpts, num_comp; 644ed9e99e6SJeremy L Thompson ierr = CeedOperatorGetActiveElemRestriction(op, &active_rstr); CeedChk(ierr); 645ed9e99e6SJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(active_rstr, &num_elem); CeedChk(ierr); 646ed9e99e6SJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(active_rstr, &elem_size); 647ed9e99e6SJeremy L Thompson CeedChk(ierr); 648ed9e99e6SJeremy L Thompson ierr = CeedElemRestrictionGetNumComponents(active_rstr, &num_comp); 649ed9e99e6SJeremy L Thompson CeedChk(ierr); 650eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts); CeedChk(ierr); 651eaf62fffSJeremy L Thompson 652eaf62fffSJeremy L Thompson CeedInt local_num_entries = elem_size*num_comp * elem_size*num_comp * num_elem; 653eaf62fffSJeremy L Thompson 654eaf62fffSJeremy L Thompson // loop over elements and put in data structure 655eaf62fffSJeremy L Thompson const CeedScalar *interp_in, *grad_in; 656eaf62fffSJeremy L Thompson ierr = CeedBasisGetInterp(basis_in, &interp_in); CeedChk(ierr); 657eaf62fffSJeremy L Thompson ierr = CeedBasisGetGrad(basis_in, &grad_in); CeedChk(ierr); 658eaf62fffSJeremy L Thompson 659eaf62fffSJeremy L Thompson const CeedScalar *assembled_qf_array; 660eaf62fffSJeremy L Thompson ierr = CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array); 661eaf62fffSJeremy L Thompson CeedChk(ierr); 662eaf62fffSJeremy L Thompson 663eaf62fffSJeremy L Thompson CeedInt layout_qf[3]; 664eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetELayout(rstr_q, &layout_qf); CeedChk(ierr); 665eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr_q); CeedChk(ierr); 666eaf62fffSJeremy L Thompson 667eaf62fffSJeremy L Thompson // we store B_mat_in, B_mat_out, BTD, elem_mat in row-major order 668ed9e99e6SJeremy L Thompson const CeedScalar *B_mat_in, *B_mat_out; 669ed9e99e6SJeremy L Thompson ierr = CeedOperatorAssemblyDataGetBases(data, NULL, &B_mat_in, NULL, 670ed9e99e6SJeremy L Thompson &B_mat_out); CeedChk(ierr); 671ed9e99e6SJeremy L Thompson CeedScalar BTD_mat[elem_size * num_qpts*num_eval_mode_in]; 672eaf62fffSJeremy L Thompson CeedScalar elem_mat[elem_size * elem_size]; 67392ae7e47SJeremy L Thompson CeedInt count = 0; 674eaf62fffSJeremy L Thompson CeedScalar *vals; 6759c774eddSJeremy L Thompson ierr = CeedVectorGetArrayWrite(values, CEED_MEM_HOST, &vals); CeedChk(ierr); 676ed9e99e6SJeremy L Thompson const CeedScalar qf_value_bound = max_norm*100*CEED_EPSILON; 677ed9e99e6SJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) { 678ed9e99e6SJeremy L Thompson for (CeedInt comp_in = 0; comp_in < num_comp; comp_in++) { 679ed9e99e6SJeremy L Thompson for (CeedInt comp_out = 0; comp_out < num_comp; comp_out++) { 680ed9e99e6SJeremy L Thompson // Compute B^T*D 681ed9e99e6SJeremy L Thompson for (CeedInt n = 0; n < elem_size; n++) { 682ed9e99e6SJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 683ed9e99e6SJeremy L Thompson for (CeedInt e_in = 0; e_in < num_eval_mode_in; e_in++) { 684ed9e99e6SJeremy L Thompson const CeedInt btd_index = n*(num_qpts*num_eval_mode_in) + 685ed9e99e6SJeremy L Thompson (num_eval_mode_in*q + e_in); 686*067fd99fSJeremy L Thompson CeedScalar sum = 0.0; 687*067fd99fSJeremy L Thompson for (CeedInt e_out = 0; e_out < num_eval_mode_out; e_out++) { 688ed9e99e6SJeremy L Thompson const CeedInt b_out_index = (num_eval_mode_out*q + e_out)*elem_size + n; 689ed9e99e6SJeremy L Thompson const CeedInt eval_mode_index = ((e_in*num_comp+comp_in)*num_eval_mode_out 690ed9e99e6SJeremy L Thompson +e_out)*num_comp + comp_out; 691ed9e99e6SJeremy L Thompson const CeedInt qf_index = q*layout_qf[0] + eval_mode_index*layout_qf[1] + 692ed9e99e6SJeremy L Thompson e*layout_qf[2]; 693ed9e99e6SJeremy L Thompson if (fabs(assembled_qf_array[qf_index]) > qf_value_bound) { 694*067fd99fSJeremy L Thompson sum += B_mat_out[b_out_index] * assembled_qf_array[qf_index]; 695eaf62fffSJeremy L Thompson } 696eaf62fffSJeremy L Thompson } 697*067fd99fSJeremy L Thompson BTD_mat[btd_index] = sum; 698ed9e99e6SJeremy L Thompson } 699ed9e99e6SJeremy L Thompson } 700eaf62fffSJeremy L Thompson } 701eaf62fffSJeremy L Thompson // form element matrix itself (for each block component) 702ed9e99e6SJeremy L Thompson ierr = CeedMatrixMatrixMultiply(ceed, BTD_mat, B_mat_in, elem_mat, elem_size, 703eaf62fffSJeremy L Thompson elem_size, num_qpts*num_eval_mode_in); CeedChk(ierr); 704eaf62fffSJeremy L Thompson 705eaf62fffSJeremy L Thompson // put element matrix in coordinate data structure 706ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < elem_size; i++) { 707ed9e99e6SJeremy L Thompson for (CeedInt j = 0; j < elem_size; j++) { 708eaf62fffSJeremy L Thompson vals[offset + count] = elem_mat[i*elem_size + j]; 709eaf62fffSJeremy L Thompson count++; 710eaf62fffSJeremy L Thompson } 711eaf62fffSJeremy L Thompson } 712eaf62fffSJeremy L Thompson } 713eaf62fffSJeremy L Thompson } 714eaf62fffSJeremy L Thompson } 715eaf62fffSJeremy L Thompson if (count != local_num_entries) 716eaf62fffSJeremy L Thompson // LCOV_EXCL_START 717eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing entries"); 718eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 719eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArray(values, &vals); CeedChk(ierr); 720eaf62fffSJeremy L Thompson 721eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array); 722eaf62fffSJeremy L Thompson CeedChk(ierr); 723eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&assembled_qf); CeedChk(ierr); 724eaf62fffSJeremy L Thompson 725eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 726eaf62fffSJeremy L Thompson } 727eaf62fffSJeremy L Thompson 728eaf62fffSJeremy L Thompson /** 729eaf62fffSJeremy L Thompson @brief Count number of entries for assembled CeedOperator 730eaf62fffSJeremy L Thompson 731eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 732eaf62fffSJeremy L Thompson @param[out] num_entries Number of entries in assembled representation 733eaf62fffSJeremy L Thompson 734eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 735eaf62fffSJeremy L Thompson 736eaf62fffSJeremy L Thompson @ref Utility 737eaf62fffSJeremy L Thompson **/ 738eaf62fffSJeremy L Thompson static int CeedSingleOperatorAssemblyCountEntries(CeedOperator op, 739eaf62fffSJeremy L Thompson CeedInt *num_entries) { 740eaf62fffSJeremy L Thompson int ierr; 741eaf62fffSJeremy L Thompson CeedElemRestriction rstr; 742eaf62fffSJeremy L Thompson CeedInt num_elem, elem_size, num_comp; 743eaf62fffSJeremy L Thompson 744f04ea552SJeremy L Thompson if (op->is_composite) 745eaf62fffSJeremy L Thompson // LCOV_EXCL_START 746eaf62fffSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 747eaf62fffSJeremy L Thompson "Composite operator not supported"); 748eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 749eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveElemRestriction(op, &rstr); CeedChk(ierr); 750eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr); 751eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr, &elem_size); CeedChk(ierr); 752eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumComponents(rstr, &num_comp); CeedChk(ierr); 753eaf62fffSJeremy L Thompson *num_entries = elem_size*num_comp * elem_size*num_comp * num_elem; 754eaf62fffSJeremy L Thompson 755eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 756eaf62fffSJeremy L Thompson } 757eaf62fffSJeremy L Thompson 758eaf62fffSJeremy L Thompson /** 759eaf62fffSJeremy L Thompson @brief Common code for creating a multigrid coarse operator and level 760eaf62fffSJeremy L Thompson transfer operators for a CeedOperator 761eaf62fffSJeremy L Thompson 762eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 763eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 764eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 765eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 766eaf62fffSJeremy L Thompson @param[in] basis_c_to_f Basis for coarse to fine interpolation 767eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 768eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 769eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 770eaf62fffSJeremy L Thompson 771eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 772eaf62fffSJeremy L Thompson 773eaf62fffSJeremy L Thompson @ref Developer 774eaf62fffSJeremy L Thompson **/ 775eaf62fffSJeremy L Thompson static int CeedSingleOperatorMultigridLevel(CeedOperator op_fine, 776eaf62fffSJeremy L Thompson CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 777eaf62fffSJeremy L Thompson CeedBasis basis_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong, 778eaf62fffSJeremy L Thompson CeedOperator *op_restrict) { 779eaf62fffSJeremy L Thompson int ierr; 780eaf62fffSJeremy L Thompson Ceed ceed; 781eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr); 782eaf62fffSJeremy L Thompson 783eaf62fffSJeremy L Thompson // Check for composite operator 784eaf62fffSJeremy L Thompson bool is_composite; 785eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op_fine, &is_composite); CeedChk(ierr); 786eaf62fffSJeremy L Thompson if (is_composite) 787eaf62fffSJeremy L Thompson // LCOV_EXCL_START 788eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 789eaf62fffSJeremy L Thompson "Automatic multigrid setup for composite operators not supported"); 790eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 791eaf62fffSJeremy L Thompson 792eaf62fffSJeremy L Thompson // Coarse Grid 793eaf62fffSJeremy L Thompson ierr = CeedOperatorCreate(ceed, op_fine->qf, op_fine->dqf, op_fine->dqfT, 794eaf62fffSJeremy L Thompson op_coarse); CeedChk(ierr); 795eaf62fffSJeremy L Thompson CeedElemRestriction rstr_fine = NULL; 796eaf62fffSJeremy L Thompson // -- Clone input fields 79792ae7e47SJeremy L Thompson for (CeedInt i = 0; i < op_fine->qf->num_input_fields; i++) { 798eaf62fffSJeremy L Thompson if (op_fine->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 799eaf62fffSJeremy L Thompson rstr_fine = op_fine->input_fields[i]->elem_restr; 800eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name, 801eaf62fffSJeremy L Thompson rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE); 802eaf62fffSJeremy L Thompson CeedChk(ierr); 803eaf62fffSJeremy L Thompson } else { 804eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name, 805eaf62fffSJeremy L Thompson op_fine->input_fields[i]->elem_restr, 806eaf62fffSJeremy L Thompson op_fine->input_fields[i]->basis, 807eaf62fffSJeremy L Thompson op_fine->input_fields[i]->vec); CeedChk(ierr); 808eaf62fffSJeremy L Thompson } 809eaf62fffSJeremy L Thompson } 810eaf62fffSJeremy L Thompson // -- Clone output fields 81192ae7e47SJeremy L Thompson for (CeedInt i = 0; i < op_fine->qf->num_output_fields; i++) { 812eaf62fffSJeremy L Thompson if (op_fine->output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 813eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name, 814eaf62fffSJeremy L Thompson rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE); 815eaf62fffSJeremy L Thompson CeedChk(ierr); 816eaf62fffSJeremy L Thompson } else { 817eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name, 818eaf62fffSJeremy L Thompson op_fine->output_fields[i]->elem_restr, 819eaf62fffSJeremy L Thompson op_fine->output_fields[i]->basis, 820eaf62fffSJeremy L Thompson op_fine->output_fields[i]->vec); CeedChk(ierr); 821eaf62fffSJeremy L Thompson } 822eaf62fffSJeremy L Thompson } 823af99e877SJeremy L Thompson // -- Clone QFunctionAssemblyData 824af99e877SJeremy L Thompson ierr = CeedQFunctionAssemblyDataReferenceCopy(op_fine->qf_assembled, 825af99e877SJeremy L Thompson &(*op_coarse)->qf_assembled); CeedChk(ierr); 826eaf62fffSJeremy L Thompson 827eaf62fffSJeremy L Thompson // Multiplicity vector 828eaf62fffSJeremy L Thompson CeedVector mult_vec, mult_e_vec; 829eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionCreateVector(rstr_fine, &mult_vec, &mult_e_vec); 830eaf62fffSJeremy L Thompson CeedChk(ierr); 831eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(mult_e_vec, 0.0); CeedChk(ierr); 832eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionApply(rstr_fine, CEED_NOTRANSPOSE, p_mult_fine, 833eaf62fffSJeremy L Thompson mult_e_vec, CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 834eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(mult_vec, 0.0); CeedChk(ierr); 835eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionApply(rstr_fine, CEED_TRANSPOSE, mult_e_vec, mult_vec, 836eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 837eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&mult_e_vec); CeedChk(ierr); 838eaf62fffSJeremy L Thompson ierr = CeedVectorReciprocal(mult_vec); CeedChk(ierr); 839eaf62fffSJeremy L Thompson 840eaf62fffSJeremy L Thompson // Restriction 841eaf62fffSJeremy L Thompson CeedInt num_comp; 842eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis_coarse, &num_comp); CeedChk(ierr); 843eaf62fffSJeremy L Thompson CeedQFunction qf_restrict; 844eaf62fffSJeremy L Thompson ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_restrict); 845eaf62fffSJeremy L Thompson CeedChk(ierr); 846eaf62fffSJeremy L Thompson CeedInt *num_comp_r_data; 847eaf62fffSJeremy L Thompson ierr = CeedCalloc(1, &num_comp_r_data); CeedChk(ierr); 848eaf62fffSJeremy L Thompson num_comp_r_data[0] = num_comp; 849eaf62fffSJeremy L Thompson CeedQFunctionContext ctx_r; 850eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextCreate(ceed, &ctx_r); CeedChk(ierr); 851eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextSetData(ctx_r, CEED_MEM_HOST, CEED_OWN_POINTER, 852eaf62fffSJeremy L Thompson sizeof(*num_comp_r_data), num_comp_r_data); 853eaf62fffSJeremy L Thompson CeedChk(ierr); 854eaf62fffSJeremy L Thompson ierr = CeedQFunctionSetContext(qf_restrict, ctx_r); CeedChk(ierr); 855eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextDestroy(&ctx_r); CeedChk(ierr); 856eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_restrict, "input", num_comp, CEED_EVAL_NONE); 857eaf62fffSJeremy L Thompson CeedChk(ierr); 858eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_restrict, "scale", num_comp, CEED_EVAL_NONE); 859eaf62fffSJeremy L Thompson CeedChk(ierr); 860eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddOutput(qf_restrict, "output", num_comp, 861eaf62fffSJeremy L Thompson CEED_EVAL_INTERP); CeedChk(ierr); 8626e15d496SJeremy L Thompson ierr = CeedQFunctionSetUserFlopsEstimate(qf_restrict, num_comp); CeedChk(ierr); 863eaf62fffSJeremy L Thompson 864eaf62fffSJeremy L Thompson ierr = CeedOperatorCreate(ceed, qf_restrict, CEED_QFUNCTION_NONE, 865eaf62fffSJeremy L Thompson CEED_QFUNCTION_NONE, op_restrict); 866eaf62fffSJeremy L Thompson CeedChk(ierr); 867eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_restrict, "input", rstr_fine, 868eaf62fffSJeremy L Thompson CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 869eaf62fffSJeremy L Thompson CeedChk(ierr); 870eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_restrict, "scale", rstr_fine, 871eaf62fffSJeremy L Thompson CEED_BASIS_COLLOCATED, mult_vec); 872eaf62fffSJeremy L Thompson CeedChk(ierr); 873eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_restrict, "output", rstr_coarse, basis_c_to_f, 874eaf62fffSJeremy L Thompson CEED_VECTOR_ACTIVE); CeedChk(ierr); 875eaf62fffSJeremy L Thompson 876eaf62fffSJeremy L Thompson // Prolongation 877eaf62fffSJeremy L Thompson CeedQFunction qf_prolong; 878eaf62fffSJeremy L Thompson ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_prolong); 879eaf62fffSJeremy L Thompson CeedChk(ierr); 880eaf62fffSJeremy L Thompson CeedInt *num_comp_p_data; 881eaf62fffSJeremy L Thompson ierr = CeedCalloc(1, &num_comp_p_data); CeedChk(ierr); 882eaf62fffSJeremy L Thompson num_comp_p_data[0] = num_comp; 883eaf62fffSJeremy L Thompson CeedQFunctionContext ctx_p; 884eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextCreate(ceed, &ctx_p); CeedChk(ierr); 885eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextSetData(ctx_p, CEED_MEM_HOST, CEED_OWN_POINTER, 886eaf62fffSJeremy L Thompson sizeof(*num_comp_p_data), num_comp_p_data); 887eaf62fffSJeremy L Thompson CeedChk(ierr); 888eaf62fffSJeremy L Thompson ierr = CeedQFunctionSetContext(qf_prolong, ctx_p); CeedChk(ierr); 889eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextDestroy(&ctx_p); CeedChk(ierr); 890eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_prolong, "input", num_comp, CEED_EVAL_INTERP); 891eaf62fffSJeremy L Thompson CeedChk(ierr); 892eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_prolong, "scale", num_comp, CEED_EVAL_NONE); 893eaf62fffSJeremy L Thompson CeedChk(ierr); 894eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddOutput(qf_prolong, "output", num_comp, CEED_EVAL_NONE); 895eaf62fffSJeremy L Thompson CeedChk(ierr); 8966e15d496SJeremy L Thompson ierr = CeedQFunctionSetUserFlopsEstimate(qf_prolong, num_comp); CeedChk(ierr); 897eaf62fffSJeremy L Thompson 898eaf62fffSJeremy L Thompson ierr = CeedOperatorCreate(ceed, qf_prolong, CEED_QFUNCTION_NONE, 899eaf62fffSJeremy L Thompson CEED_QFUNCTION_NONE, op_prolong); 900eaf62fffSJeremy L Thompson CeedChk(ierr); 901eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_prolong, "input", rstr_coarse, basis_c_to_f, 902eaf62fffSJeremy L Thompson CEED_VECTOR_ACTIVE); CeedChk(ierr); 903eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_prolong, "scale", rstr_fine, 904eaf62fffSJeremy L Thompson CEED_BASIS_COLLOCATED, mult_vec); 905eaf62fffSJeremy L Thompson CeedChk(ierr); 906eaf62fffSJeremy L Thompson ierr = CeedOperatorSetField(*op_prolong, "output", rstr_fine, 907eaf62fffSJeremy L Thompson CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 908eaf62fffSJeremy L Thompson CeedChk(ierr); 909eaf62fffSJeremy L Thompson 910ea6b5821SJeremy L Thompson // Clone name 911ea6b5821SJeremy L Thompson bool has_name = op_fine->name; 912ea6b5821SJeremy L Thompson size_t name_len = op_fine->name ? strlen(op_fine->name) : 0; 913ea6b5821SJeremy L Thompson ierr = CeedOperatorSetName(*op_coarse, op_fine->name); CeedChk(ierr); 914ea6b5821SJeremy L Thompson { 915ea6b5821SJeremy L Thompson char *prolongation_name; 916ea6b5821SJeremy L Thompson ierr = CeedCalloc(18 + name_len, &prolongation_name); CeedChk(ierr); 917ea6b5821SJeremy L Thompson sprintf(prolongation_name, "prolongation%s%s", has_name ? " for " : "", 9183129f025Srezgarshakeri has_name ? op_fine->name : ""); 919ea6b5821SJeremy L Thompson ierr = CeedOperatorSetName(*op_prolong, prolongation_name); CeedChk(ierr); 920ea6b5821SJeremy L Thompson ierr = CeedFree(&prolongation_name); CeedChk(ierr); 921ea6b5821SJeremy L Thompson } 922ea6b5821SJeremy L Thompson { 923ea6b5821SJeremy L Thompson char *restriction_name; 924ea6b5821SJeremy L Thompson ierr = CeedCalloc(17 + name_len, &restriction_name); CeedChk(ierr); 925ea6b5821SJeremy L Thompson sprintf(restriction_name, "restriction%s%s", has_name ? " for " : "", 9263129f025Srezgarshakeri has_name ? op_fine->name : ""); 927ea6b5821SJeremy L Thompson ierr = CeedOperatorSetName(*op_restrict, restriction_name); CeedChk(ierr); 928ea6b5821SJeremy L Thompson ierr = CeedFree(&restriction_name); CeedChk(ierr); 929ea6b5821SJeremy L Thompson } 930ea6b5821SJeremy L Thompson 931eaf62fffSJeremy L Thompson // Cleanup 932eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&mult_vec); CeedChk(ierr); 933eaf62fffSJeremy L Thompson ierr = CeedBasisDestroy(&basis_c_to_f); CeedChk(ierr); 934eaf62fffSJeremy L Thompson ierr = CeedQFunctionDestroy(&qf_restrict); CeedChk(ierr); 935eaf62fffSJeremy L Thompson ierr = CeedQFunctionDestroy(&qf_prolong); CeedChk(ierr); 936805fe78eSJeremy L Thompson 937eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 938eaf62fffSJeremy L Thompson } 939eaf62fffSJeremy L Thompson 940eaf62fffSJeremy L Thompson /** 941eaf62fffSJeremy L Thompson @brief Build 1D mass matrix and Laplacian with perturbation 942eaf62fffSJeremy L Thompson 943eaf62fffSJeremy L Thompson @param[in] interp_1d Interpolation matrix in one dimension 944eaf62fffSJeremy L Thompson @param[in] grad_1d Gradient matrix in one dimension 945eaf62fffSJeremy L Thompson @param[in] q_weight_1d Quadrature weights in one dimension 946eaf62fffSJeremy L Thompson @param[in] P_1d Number of basis nodes in one dimension 947eaf62fffSJeremy L Thompson @param[in] Q_1d Number of quadrature points in one dimension 948eaf62fffSJeremy L Thompson @param[in] dim Dimension of basis 949eaf62fffSJeremy L Thompson @param[out] mass Assembled mass matrix in one dimension 950eaf62fffSJeremy L Thompson @param[out] laplace Assembled perturbed Laplacian in one dimension 951eaf62fffSJeremy L Thompson 952eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 953eaf62fffSJeremy L Thompson 954eaf62fffSJeremy L Thompson @ref Developer 955eaf62fffSJeremy L Thompson **/ 956eaf62fffSJeremy L Thompson CeedPragmaOptimizeOff 957eaf62fffSJeremy L Thompson static int CeedBuildMassLaplace(const CeedScalar *interp_1d, 958eaf62fffSJeremy L Thompson const CeedScalar *grad_1d, 959eaf62fffSJeremy L Thompson const CeedScalar *q_weight_1d, CeedInt P_1d, 960eaf62fffSJeremy L Thompson CeedInt Q_1d, CeedInt dim, 961eaf62fffSJeremy L Thompson CeedScalar *mass, CeedScalar *laplace) { 962eaf62fffSJeremy L Thompson 963eaf62fffSJeremy L Thompson for (CeedInt i=0; i<P_1d; i++) 964eaf62fffSJeremy L Thompson for (CeedInt j=0; j<P_1d; j++) { 965eaf62fffSJeremy L Thompson CeedScalar sum = 0.0; 966eaf62fffSJeremy L Thompson for (CeedInt k=0; k<Q_1d; k++) 967eaf62fffSJeremy L Thompson sum += interp_1d[k*P_1d+i]*q_weight_1d[k]*interp_1d[k*P_1d+j]; 968eaf62fffSJeremy L Thompson mass[i+j*P_1d] = sum; 969eaf62fffSJeremy L Thompson } 970eaf62fffSJeremy L Thompson // -- Laplacian 971eaf62fffSJeremy L Thompson for (CeedInt i=0; i<P_1d; i++) 972eaf62fffSJeremy L Thompson for (CeedInt j=0; j<P_1d; j++) { 973eaf62fffSJeremy L Thompson CeedScalar sum = 0.0; 974eaf62fffSJeremy L Thompson for (CeedInt k=0; k<Q_1d; k++) 975eaf62fffSJeremy L Thompson sum += grad_1d[k*P_1d+i]*q_weight_1d[k]*grad_1d[k*P_1d+j]; 976eaf62fffSJeremy L Thompson laplace[i+j*P_1d] = sum; 977eaf62fffSJeremy L Thompson } 978eaf62fffSJeremy L Thompson CeedScalar perturbation = dim>2 ? 1e-6 : 1e-4; 979eaf62fffSJeremy L Thompson for (CeedInt i=0; i<P_1d; i++) 980eaf62fffSJeremy L Thompson laplace[i+P_1d*i] += perturbation; 981eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 982eaf62fffSJeremy L Thompson } 983eaf62fffSJeremy L Thompson CeedPragmaOptimizeOn 984eaf62fffSJeremy L Thompson 985eaf62fffSJeremy L Thompson /// @} 986eaf62fffSJeremy L Thompson 987eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 988480fae85SJeremy L Thompson /// CeedOperator Backend API 989480fae85SJeremy L Thompson /// ---------------------------------------------------------------------------- 990480fae85SJeremy L Thompson /// @addtogroup CeedOperatorBackend 991480fae85SJeremy L Thompson /// @{ 992480fae85SJeremy L Thompson 993480fae85SJeremy L Thompson /** 994480fae85SJeremy L Thompson @brief Create object holding CeedQFunction assembly data for CeedOperator 995480fae85SJeremy L Thompson 996480fae85SJeremy L Thompson @param[in] ceed A Ceed object where the CeedQFunctionAssemblyData will be created 997480fae85SJeremy L Thompson @param[out] data Address of the variable where the newly created 998480fae85SJeremy L Thompson CeedQFunctionAssemblyData will be stored 999480fae85SJeremy L Thompson 1000480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1001480fae85SJeremy L Thompson 1002480fae85SJeremy L Thompson @ref Backend 1003480fae85SJeremy L Thompson **/ 1004480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataCreate(Ceed ceed, 1005480fae85SJeremy L Thompson CeedQFunctionAssemblyData *data) { 1006480fae85SJeremy L Thompson int ierr; 1007480fae85SJeremy L Thompson 1008480fae85SJeremy L Thompson ierr = CeedCalloc(1, data); CeedChk(ierr); 1009480fae85SJeremy L Thompson (*data)->ref_count = 1; 1010480fae85SJeremy L Thompson (*data)->ceed = ceed; 1011480fae85SJeremy L Thompson ierr = CeedReference(ceed); CeedChk(ierr); 1012480fae85SJeremy L Thompson 1013480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1014480fae85SJeremy L Thompson } 1015480fae85SJeremy L Thompson 1016480fae85SJeremy L Thompson /** 1017480fae85SJeremy L Thompson @brief Increment the reference counter for a CeedQFunctionAssemblyData 1018480fae85SJeremy L Thompson 1019480fae85SJeremy L Thompson @param data CeedQFunctionAssemblyData to increment the reference counter 1020480fae85SJeremy L Thompson 1021480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1022480fae85SJeremy L Thompson 1023480fae85SJeremy L Thompson @ref Backend 1024480fae85SJeremy L Thompson **/ 1025480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataReference(CeedQFunctionAssemblyData data) { 1026480fae85SJeremy L Thompson data->ref_count++; 1027480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1028480fae85SJeremy L Thompson } 1029480fae85SJeremy L Thompson 1030480fae85SJeremy L Thompson /** 1031beecbf24SJeremy L Thompson @brief Set re-use of CeedQFunctionAssemblyData 10328b919e6bSJeremy L Thompson 1033beecbf24SJeremy L Thompson @param data CeedQFunctionAssemblyData to mark for reuse 1034beecbf24SJeremy L Thompson @param reuse_data Boolean flag indicating data re-use 10358b919e6bSJeremy L Thompson 10368b919e6bSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 10378b919e6bSJeremy L Thompson 10388b919e6bSJeremy L Thompson @ref Backend 10398b919e6bSJeremy L Thompson **/ 1040beecbf24SJeremy L Thompson int CeedQFunctionAssemblyDataSetReuse(CeedQFunctionAssemblyData data, 1041beecbf24SJeremy L Thompson bool reuse_data) { 1042beecbf24SJeremy L Thompson data->reuse_data = reuse_data; 1043beecbf24SJeremy L Thompson data->needs_data_update = true; 1044beecbf24SJeremy L Thompson return CEED_ERROR_SUCCESS; 1045beecbf24SJeremy L Thompson } 1046beecbf24SJeremy L Thompson 1047beecbf24SJeremy L Thompson /** 1048beecbf24SJeremy L Thompson @brief Mark QFunctionAssemblyData as stale 1049beecbf24SJeremy L Thompson 1050beecbf24SJeremy L Thompson @param data CeedQFunctionAssemblyData to mark as stale 1051beecbf24SJeremy L Thompson @param needs_data_update Boolean flag indicating if update is needed or completed 1052beecbf24SJeremy L Thompson 1053beecbf24SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1054beecbf24SJeremy L Thompson 1055beecbf24SJeremy L Thompson @ref Backend 1056beecbf24SJeremy L Thompson **/ 1057beecbf24SJeremy L Thompson int CeedQFunctionAssemblyDataSetUpdateNeeded(CeedQFunctionAssemblyData data, 1058beecbf24SJeremy L Thompson bool needs_data_update) { 1059beecbf24SJeremy L Thompson data->needs_data_update = needs_data_update; 10608b919e6bSJeremy L Thompson return CEED_ERROR_SUCCESS; 10618b919e6bSJeremy L Thompson } 10628b919e6bSJeremy L Thompson 10638b919e6bSJeremy L Thompson /** 10648b919e6bSJeremy L Thompson @brief Determine if QFunctionAssemblyData needs update 10658b919e6bSJeremy L Thompson 10668b919e6bSJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to mark as stale 10678b919e6bSJeremy L Thompson @param[out] is_update_needed Boolean flag indicating if re-assembly is required 10688b919e6bSJeremy L Thompson 10698b919e6bSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 10708b919e6bSJeremy L Thompson 10718b919e6bSJeremy L Thompson @ref Backend 10728b919e6bSJeremy L Thompson **/ 10738b919e6bSJeremy L Thompson int CeedQFunctionAssemblyDataIsUpdateNeeded(CeedQFunctionAssemblyData data, 10748b919e6bSJeremy L Thompson bool *is_update_needed) { 1075beecbf24SJeremy L Thompson *is_update_needed = !data->reuse_data || data->needs_data_update; 10768b919e6bSJeremy L Thompson return CEED_ERROR_SUCCESS; 10778b919e6bSJeremy L Thompson } 10788b919e6bSJeremy L Thompson 10798b919e6bSJeremy L Thompson /** 1080480fae85SJeremy L Thompson @brief Copy the pointer to a CeedQFunctionAssemblyData. Both pointers should 1081480fae85SJeremy L Thompson be destroyed with `CeedCeedQFunctionAssemblyDataDestroy()`; 1082480fae85SJeremy L Thompson Note: If `*data_copy` is non-NULL, then it is assumed that 1083480fae85SJeremy L Thompson `*data_copy` is a pointer to a CeedQFunctionAssemblyData. This 1084480fae85SJeremy L Thompson CeedQFunctionAssemblyData will be destroyed if `*data_copy` is 1085480fae85SJeremy L Thompson the only reference to this CeedQFunctionAssemblyData. 1086480fae85SJeremy L Thompson 1087480fae85SJeremy L Thompson @param data CeedQFunctionAssemblyData to copy reference to 1088480fae85SJeremy L Thompson @param[out] data_copy Variable to store copied reference 1089480fae85SJeremy L Thompson 1090480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1091480fae85SJeremy L Thompson 1092480fae85SJeremy L Thompson @ref Backend 1093480fae85SJeremy L Thompson **/ 1094480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataReferenceCopy(CeedQFunctionAssemblyData data, 1095480fae85SJeremy L Thompson CeedQFunctionAssemblyData *data_copy) { 1096480fae85SJeremy L Thompson int ierr; 1097480fae85SJeremy L Thompson 1098480fae85SJeremy L Thompson ierr = CeedQFunctionAssemblyDataReference(data); CeedChk(ierr); 1099480fae85SJeremy L Thompson ierr = CeedQFunctionAssemblyDataDestroy(data_copy); CeedChk(ierr); 1100480fae85SJeremy L Thompson *data_copy = data; 1101480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1102480fae85SJeremy L Thompson } 1103480fae85SJeremy L Thompson 1104480fae85SJeremy L Thompson /** 1105480fae85SJeremy L Thompson @brief Get setup status for internal objects for CeedQFunctionAssemblyData 1106480fae85SJeremy L Thompson 1107480fae85SJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to retreive status 1108480fae85SJeremy L Thompson @param[out] is_setup Boolean flag for setup status 1109480fae85SJeremy L Thompson 1110480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1111480fae85SJeremy L Thompson 1112480fae85SJeremy L Thompson @ref Backend 1113480fae85SJeremy L Thompson **/ 1114480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataIsSetup(CeedQFunctionAssemblyData data, 1115480fae85SJeremy L Thompson bool *is_setup) { 1116480fae85SJeremy L Thompson *is_setup = data->is_setup; 1117480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1118480fae85SJeremy L Thompson } 1119480fae85SJeremy L Thompson 1120480fae85SJeremy L Thompson /** 1121480fae85SJeremy L Thompson @brief Set internal objects for CeedQFunctionAssemblyData 1122480fae85SJeremy L Thompson 1123480fae85SJeremy L Thompson @param[in] data CeedQFunctionAssemblyData to set objects 1124480fae85SJeremy L Thompson @param[in] vec CeedVector to store assembled CeedQFunction at quadrature points 1125480fae85SJeremy L Thompson @param[in] rstr CeedElemRestriction for CeedVector containing assembled CeedQFunction 1126480fae85SJeremy L Thompson 1127480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1128480fae85SJeremy L Thompson 1129480fae85SJeremy L Thompson @ref Backend 1130480fae85SJeremy L Thompson **/ 1131480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataSetObjects(CeedQFunctionAssemblyData data, 1132480fae85SJeremy L Thompson CeedVector vec, CeedElemRestriction rstr) { 1133480fae85SJeremy L Thompson int ierr; 1134480fae85SJeremy L Thompson 11352efa2d85SJeremy L Thompson ierr = CeedVectorReferenceCopy(vec, &data->vec); CeedChk(ierr); 11362efa2d85SJeremy L Thompson ierr = CeedElemRestrictionReferenceCopy(rstr, &data->rstr); CeedChk(ierr); 1137480fae85SJeremy L Thompson 1138480fae85SJeremy L Thompson data->is_setup = true; 1139480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1140480fae85SJeremy L Thompson } 1141480fae85SJeremy L Thompson 1142480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataGetObjects(CeedQFunctionAssemblyData data, 1143480fae85SJeremy L Thompson CeedVector *vec, CeedElemRestriction *rstr) { 11442efa2d85SJeremy L Thompson int ierr; 11452efa2d85SJeremy L Thompson 1146480fae85SJeremy L Thompson if (!data->is_setup) 1147480fae85SJeremy L Thompson // LCOV_EXCL_START 1148480fae85SJeremy L Thompson return CeedError(data->ceed, CEED_ERROR_INCOMPLETE, 1149480fae85SJeremy L Thompson "Internal objects not set; must call CeedQFunctionAssemblyDataSetObjects first."); 1150480fae85SJeremy L Thompson // LCOV_EXCL_STOP 1151480fae85SJeremy L Thompson 11522efa2d85SJeremy L Thompson ierr = CeedVectorReferenceCopy(data->vec, vec); CeedChk(ierr); 11532efa2d85SJeremy L Thompson ierr = CeedElemRestrictionReferenceCopy(data->rstr, rstr); CeedChk(ierr); 1154480fae85SJeremy L Thompson 1155480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1156480fae85SJeremy L Thompson } 1157480fae85SJeremy L Thompson 1158480fae85SJeremy L Thompson /** 1159480fae85SJeremy L Thompson @brief Destroy CeedQFunctionAssemblyData 1160480fae85SJeremy L Thompson 1161480fae85SJeremy L Thompson @param[out] data CeedQFunctionAssemblyData to destroy 1162480fae85SJeremy L Thompson 1163480fae85SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1164480fae85SJeremy L Thompson 1165480fae85SJeremy L Thompson @ref Backend 1166480fae85SJeremy L Thompson **/ 1167480fae85SJeremy L Thompson int CeedQFunctionAssemblyDataDestroy(CeedQFunctionAssemblyData *data) { 1168480fae85SJeremy L Thompson int ierr; 1169480fae85SJeremy L Thompson 1170480fae85SJeremy L Thompson if (!*data || --(*data)->ref_count > 0) return CEED_ERROR_SUCCESS; 1171480fae85SJeremy L Thompson 1172480fae85SJeremy L Thompson ierr = CeedDestroy(&(*data)->ceed); CeedChk(ierr); 1173480fae85SJeremy L Thompson ierr = CeedVectorDestroy(&(*data)->vec); CeedChk(ierr); 1174480fae85SJeremy L Thompson ierr = CeedElemRestrictionDestroy(&(*data)->rstr); CeedChk(ierr); 1175480fae85SJeremy L Thompson 1176480fae85SJeremy L Thompson ierr = CeedFree(data); CeedChk(ierr); 1177480fae85SJeremy L Thompson return CEED_ERROR_SUCCESS; 1178480fae85SJeremy L Thompson } 1179480fae85SJeremy L Thompson 1180ed9e99e6SJeremy L Thompson /** 1181ed9e99e6SJeremy L Thompson @brief Get CeedOperatorAssemblyData 1182ed9e99e6SJeremy L Thompson 1183ed9e99e6SJeremy L Thompson @param[in] op CeedOperator to assemble 1184ed9e99e6SJeremy L Thompson @param[out] data CeedQFunctionAssemblyData 1185ed9e99e6SJeremy L Thompson 1186ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1187ed9e99e6SJeremy L Thompson 1188ed9e99e6SJeremy L Thompson @ref Backend 1189ed9e99e6SJeremy L Thompson **/ 1190ed9e99e6SJeremy L Thompson int CeedOperatorGetOperatorAssemblyData(CeedOperator op, 1191ed9e99e6SJeremy L Thompson CeedOperatorAssemblyData *data) { 1192ed9e99e6SJeremy L Thompson int ierr; 1193ed9e99e6SJeremy L Thompson 1194ed9e99e6SJeremy L Thompson if (!op->op_assembled) { 1195ed9e99e6SJeremy L Thompson CeedOperatorAssemblyData data; 1196ed9e99e6SJeremy L Thompson 1197ed9e99e6SJeremy L Thompson ierr = CeedOperatorAssemblyDataCreate(op->ceed, op, &data); CeedChk(ierr); 1198ed9e99e6SJeremy L Thompson op->op_assembled = data; 1199ed9e99e6SJeremy L Thompson } 1200ed9e99e6SJeremy L Thompson *data = op->op_assembled; 1201ed9e99e6SJeremy L Thompson 1202ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1203ed9e99e6SJeremy L Thompson } 1204ed9e99e6SJeremy L Thompson 1205ed9e99e6SJeremy L Thompson /** 1206ed9e99e6SJeremy L Thompson @brief Create object holding CeedOperator assembly data 1207ed9e99e6SJeremy L Thompson 1208ed9e99e6SJeremy L Thompson @param[in] ceed A Ceed object where the CeedOperatorAssemblyData will be created 1209ed9e99e6SJeremy L Thompson @param[in] op CeedOperator to be assembled 1210ed9e99e6SJeremy L Thompson @param[out] data Address of the variable where the newly created 1211ed9e99e6SJeremy L Thompson CeedOperatorAssemblyData will be stored 1212ed9e99e6SJeremy L Thompson 1213ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1214ed9e99e6SJeremy L Thompson 1215ed9e99e6SJeremy L Thompson @ref Backend 1216ed9e99e6SJeremy L Thompson **/ 1217ed9e99e6SJeremy L Thompson int CeedOperatorAssemblyDataCreate(Ceed ceed, CeedOperator op, 1218ed9e99e6SJeremy L Thompson CeedOperatorAssemblyData *data) { 1219ed9e99e6SJeremy L Thompson int ierr; 1220ed9e99e6SJeremy L Thompson 1221ed9e99e6SJeremy L Thompson ierr = CeedCalloc(1, data); CeedChk(ierr); 1222ed9e99e6SJeremy L Thompson (*data)->ceed = ceed; 1223ed9e99e6SJeremy L Thompson ierr = CeedReference(ceed); CeedChk(ierr); 1224ed9e99e6SJeremy L Thompson 1225ed9e99e6SJeremy L Thompson // Build OperatorAssembly data 1226ed9e99e6SJeremy L Thompson CeedQFunction qf; 1227ed9e99e6SJeremy L Thompson CeedQFunctionField *qf_fields; 1228ed9e99e6SJeremy L Thompson CeedOperatorField *op_fields; 1229ed9e99e6SJeremy L Thompson CeedInt num_input_fields; 1230ed9e99e6SJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr); 1231ed9e99e6SJeremy L Thompson ierr = CeedQFunctionGetFields(qf, &num_input_fields, &qf_fields, NULL, NULL); 1232ed9e99e6SJeremy L Thompson CeedChk(ierr); 1233ed9e99e6SJeremy L Thompson ierr = CeedOperatorGetFields(op, NULL, &op_fields, NULL, NULL); CeedChk(ierr); 1234ed9e99e6SJeremy L Thompson 1235ed9e99e6SJeremy L Thompson // Determine active input basis 1236ed9e99e6SJeremy L Thompson CeedInt num_eval_mode_in = 0, dim = 1; 1237ed9e99e6SJeremy L Thompson CeedEvalMode *eval_mode_in = NULL; 1238ed9e99e6SJeremy L Thompson CeedBasis basis_in = NULL; 1239ed9e99e6SJeremy L Thompson for (CeedInt i=0; i<num_input_fields; i++) { 1240ed9e99e6SJeremy L Thompson CeedVector vec; 1241ed9e99e6SJeremy L Thompson ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChk(ierr); 1242ed9e99e6SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 1243ed9e99e6SJeremy L Thompson ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis_in); 1244ed9e99e6SJeremy L Thompson CeedChk(ierr); 1245ed9e99e6SJeremy L Thompson ierr = CeedBasisGetDimension(basis_in, &dim); CeedChk(ierr); 1246ed9e99e6SJeremy L Thompson CeedEvalMode eval_mode; 1247ed9e99e6SJeremy L Thompson ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); 1248ed9e99e6SJeremy L Thompson CeedChk(ierr); 1249ed9e99e6SJeremy L Thompson switch (eval_mode) { 1250ed9e99e6SJeremy L Thompson case CEED_EVAL_NONE: 1251ed9e99e6SJeremy L Thompson case CEED_EVAL_INTERP: 1252ed9e99e6SJeremy L Thompson ierr = CeedRealloc(num_eval_mode_in + 1, &eval_mode_in); CeedChk(ierr); 1253ed9e99e6SJeremy L Thompson eval_mode_in[num_eval_mode_in] = eval_mode; 1254ed9e99e6SJeremy L Thompson num_eval_mode_in += 1; 1255ed9e99e6SJeremy L Thompson break; 1256ed9e99e6SJeremy L Thompson case CEED_EVAL_GRAD: 1257ed9e99e6SJeremy L Thompson ierr = CeedRealloc(num_eval_mode_in + dim, &eval_mode_in); CeedChk(ierr); 1258ed9e99e6SJeremy L Thompson for (CeedInt d=0; d<dim; d++) { 1259ed9e99e6SJeremy L Thompson eval_mode_in[num_eval_mode_in+d] = eval_mode; 1260ed9e99e6SJeremy L Thompson } 1261ed9e99e6SJeremy L Thompson num_eval_mode_in += dim; 1262ed9e99e6SJeremy L Thompson break; 1263ed9e99e6SJeremy L Thompson case CEED_EVAL_WEIGHT: 1264ed9e99e6SJeremy L Thompson case CEED_EVAL_DIV: 1265ed9e99e6SJeremy L Thompson case CEED_EVAL_CURL: 1266ed9e99e6SJeremy L Thompson break; // Caught by QF Assembly 1267ed9e99e6SJeremy L Thompson } 1268ed9e99e6SJeremy L Thompson } 1269ed9e99e6SJeremy L Thompson } 1270ed9e99e6SJeremy L Thompson (*data)->num_eval_mode_in = num_eval_mode_in; 1271ed9e99e6SJeremy L Thompson (*data)->eval_mode_in = eval_mode_in; 1272ed9e99e6SJeremy L Thompson ierr = CeedBasisReferenceCopy(basis_in, &(*data)->basis_in); CeedChk(ierr); 1273ed9e99e6SJeremy L Thompson 1274ed9e99e6SJeremy L Thompson // Determine active output basis 1275ed9e99e6SJeremy L Thompson CeedInt num_output_fields; 1276ed9e99e6SJeremy L Thompson ierr = CeedQFunctionGetFields(qf, NULL, NULL, &num_output_fields, &qf_fields); 1277ed9e99e6SJeremy L Thompson CeedChk(ierr); 1278ed9e99e6SJeremy L Thompson ierr = CeedOperatorGetFields(op, NULL, NULL, NULL, &op_fields); CeedChk(ierr); 1279ed9e99e6SJeremy L Thompson CeedInt num_eval_mode_out = 0; 1280ed9e99e6SJeremy L Thompson CeedEvalMode *eval_mode_out = NULL; 1281ed9e99e6SJeremy L Thompson CeedBasis basis_out = NULL; 1282ed9e99e6SJeremy L Thompson for (CeedInt i=0; i<num_output_fields; i++) { 1283ed9e99e6SJeremy L Thompson CeedVector vec; 1284ed9e99e6SJeremy L Thompson ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChk(ierr); 1285ed9e99e6SJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 1286ed9e99e6SJeremy L Thompson ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis_out); 1287ed9e99e6SJeremy L Thompson CeedChk(ierr); 1288ed9e99e6SJeremy L Thompson CeedEvalMode eval_mode; 1289ed9e99e6SJeremy L Thompson ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); 1290ed9e99e6SJeremy L Thompson CeedChk(ierr); 1291ed9e99e6SJeremy L Thompson switch (eval_mode) { 1292ed9e99e6SJeremy L Thompson case CEED_EVAL_NONE: 1293ed9e99e6SJeremy L Thompson case CEED_EVAL_INTERP: 1294ed9e99e6SJeremy L Thompson ierr = CeedRealloc(num_eval_mode_out + 1, &eval_mode_out); CeedChk(ierr); 1295ed9e99e6SJeremy L Thompson eval_mode_out[num_eval_mode_out] = eval_mode; 1296ed9e99e6SJeremy L Thompson num_eval_mode_out += 1; 1297ed9e99e6SJeremy L Thompson break; 1298ed9e99e6SJeremy L Thompson case CEED_EVAL_GRAD: 1299ed9e99e6SJeremy L Thompson ierr = CeedRealloc(num_eval_mode_out + dim, &eval_mode_out); CeedChk(ierr); 1300ed9e99e6SJeremy L Thompson for (CeedInt d=0; d<dim; d++) { 1301ed9e99e6SJeremy L Thompson eval_mode_out[num_eval_mode_out+d] = eval_mode; 1302ed9e99e6SJeremy L Thompson } 1303ed9e99e6SJeremy L Thompson num_eval_mode_out += dim; 1304ed9e99e6SJeremy L Thompson break; 1305ed9e99e6SJeremy L Thompson case CEED_EVAL_WEIGHT: 1306ed9e99e6SJeremy L Thompson case CEED_EVAL_DIV: 1307ed9e99e6SJeremy L Thompson case CEED_EVAL_CURL: 1308ed9e99e6SJeremy L Thompson break; // Caught by QF Assembly 1309ed9e99e6SJeremy L Thompson } 1310ed9e99e6SJeremy L Thompson } 1311ed9e99e6SJeremy L Thompson } 1312ed9e99e6SJeremy L Thompson (*data)->num_eval_mode_out = num_eval_mode_out; 1313ed9e99e6SJeremy L Thompson (*data)->eval_mode_out = eval_mode_out; 1314ed9e99e6SJeremy L Thompson ierr = CeedBasisReferenceCopy(basis_out, &(*data)->basis_out); CeedChk(ierr); 1315ed9e99e6SJeremy L Thompson 1316ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1317ed9e99e6SJeremy L Thompson } 1318ed9e99e6SJeremy L Thompson 1319ed9e99e6SJeremy L Thompson /** 1320ed9e99e6SJeremy L Thompson @brief Get CeedOperator CeedEvalModes for assembly 1321ed9e99e6SJeremy L Thompson 1322ed9e99e6SJeremy L Thompson @param[in] data CeedOperatorAssemblyData 1323ed9e99e6SJeremy L Thompson @param[out] num_eval_mode_in Pointer to hold number of input CeedEvalModes, or NULL 1324ed9e99e6SJeremy L Thompson @param[out] eval_mode_in Pointer to hold input CeedEvalModes, or NULL 1325ed9e99e6SJeremy L Thompson @param[out] num_eval_mode_out Pointer to hold number of output CeedEvalModes, or NULL 1326ed9e99e6SJeremy L Thompson @param[out] eval_mode_out Pointer to hold output CeedEvalModes, or NULL 1327ed9e99e6SJeremy L Thompson 1328ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1329ed9e99e6SJeremy L Thompson 1330ed9e99e6SJeremy L Thompson @ref Backend 1331ed9e99e6SJeremy L Thompson **/ 1332ed9e99e6SJeremy L Thompson int CeedOperatorAssemblyDataGetEvalModes(CeedOperatorAssemblyData data, 1333ed9e99e6SJeremy L Thompson CeedInt *num_eval_mode_in, const CeedEvalMode **eval_mode_in, 1334ed9e99e6SJeremy L Thompson CeedInt *num_eval_mode_out, const CeedEvalMode **eval_mode_out) { 1335ed9e99e6SJeremy L Thompson if (num_eval_mode_in) *num_eval_mode_in = data->num_eval_mode_in; 1336ed9e99e6SJeremy L Thompson if (eval_mode_in) *eval_mode_in = data->eval_mode_in; 1337ed9e99e6SJeremy L Thompson if (num_eval_mode_out) *num_eval_mode_out = data->num_eval_mode_out; 1338ed9e99e6SJeremy L Thompson if (eval_mode_out) *eval_mode_out = data->eval_mode_out; 1339ed9e99e6SJeremy L Thompson 1340ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1341ed9e99e6SJeremy L Thompson } 1342ed9e99e6SJeremy L Thompson 1343ed9e99e6SJeremy L Thompson /** 1344ed9e99e6SJeremy L Thompson @brief Get CeedOperator CeedBasis data for assembly 1345ed9e99e6SJeremy L Thompson 1346ed9e99e6SJeremy L Thompson @param[in] data CeedOperatorAssemblyData 1347ed9e99e6SJeremy L Thompson @param[out] basis_in Pointer to hold active input CeedBasis, or NULL 1348ed9e99e6SJeremy L Thompson @param[out] B_in Pointer to hold assembled active input B, or NULL 1349ed9e99e6SJeremy L Thompson @param[out] basis_out Pointer to hold active output CeedBasis, or NULL 1350ed9e99e6SJeremy L Thompson @param[out] B_out Pointer to hold assembled active output B, or NULL 1351ed9e99e6SJeremy L Thompson 1352ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1353ed9e99e6SJeremy L Thompson 1354ed9e99e6SJeremy L Thompson @ref Backend 1355ed9e99e6SJeremy L Thompson **/ 1356ed9e99e6SJeremy L Thompson int CeedOperatorAssemblyDataGetBases(CeedOperatorAssemblyData data, 1357ed9e99e6SJeremy L Thompson CeedBasis *basis_in, const CeedScalar **B_in, CeedBasis *basis_out, 1358ed9e99e6SJeremy L Thompson const CeedScalar **B_out) { 1359ed9e99e6SJeremy L Thompson int ierr; 1360ed9e99e6SJeremy L Thompson 1361ed9e99e6SJeremy L Thompson // Assemble B_in, B_out if needed 1362ed9e99e6SJeremy L Thompson if (B_in && !data->B_in) { 1363ed9e99e6SJeremy L Thompson CeedInt num_qpts, elem_size; 1364ed9e99e6SJeremy L Thompson CeedScalar *B_in, *identity = NULL; 1365ed9e99e6SJeremy L Thompson const CeedScalar *interp_in, *grad_in; 1366ed9e99e6SJeremy L Thompson bool has_eval_none = false; 1367ed9e99e6SJeremy L Thompson 1368ed9e99e6SJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(data->basis_in, &num_qpts); 1369ed9e99e6SJeremy L Thompson CeedChk(ierr); 1370ed9e99e6SJeremy L Thompson ierr = CeedBasisGetNumNodes(data->basis_in, &elem_size); CeedChk(ierr); 1371ed9e99e6SJeremy L Thompson ierr = CeedCalloc(num_qpts * elem_size * data->num_eval_mode_in, &B_in); 1372ed9e99e6SJeremy L Thompson CeedChk(ierr); 1373ed9e99e6SJeremy L Thompson 1374ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < data->num_eval_mode_in; i++) { 1375ed9e99e6SJeremy L Thompson has_eval_none = has_eval_none || (data->eval_mode_in[i] == CEED_EVAL_NONE); 1376ed9e99e6SJeremy L Thompson } 1377ed9e99e6SJeremy L Thompson if (has_eval_none) { 1378ed9e99e6SJeremy L Thompson ierr = CeedCalloc(num_qpts * elem_size, &identity); CeedChk(ierr); 1379ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < (elem_size < num_qpts ? elem_size : num_qpts); i++) { 1380ed9e99e6SJeremy L Thompson identity[i * elem_size + i] = 1.0; 1381ed9e99e6SJeremy L Thompson } 1382ed9e99e6SJeremy L Thompson } 1383ed9e99e6SJeremy L Thompson ierr = CeedBasisGetInterp(data->basis_in, &interp_in); CeedChk(ierr); 1384ed9e99e6SJeremy L Thompson ierr = CeedBasisGetGrad(data->basis_in, &grad_in); CeedChk(ierr); 1385ed9e99e6SJeremy L Thompson 1386ed9e99e6SJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 1387ed9e99e6SJeremy L Thompson for (CeedInt n = 0; n < elem_size; n++) { 1388ed9e99e6SJeremy L Thompson CeedInt d_in = -1; 1389ed9e99e6SJeremy L Thompson for (CeedInt e_in = 0; e_in < data->num_eval_mode_in; e_in++) { 1390ed9e99e6SJeremy L Thompson const CeedInt qq = data->num_eval_mode_in * q; 1391ed9e99e6SJeremy L Thompson const CeedScalar *b = NULL; 1392ed9e99e6SJeremy L Thompson 1393ed9e99e6SJeremy L Thompson if (data->eval_mode_in[e_in] == CEED_EVAL_GRAD) d_in++; 1394ed9e99e6SJeremy L Thompson CeedOperatorGetBasisPointer(data->eval_mode_in[e_in], identity, 1395ed9e99e6SJeremy L Thompson interp_in, &grad_in[d_in * num_qpts * elem_size], &b); CeedChk(ierr); 1396ed9e99e6SJeremy L Thompson B_in[(qq + e_in)*elem_size + n] = b[q * elem_size + n]; 1397ed9e99e6SJeremy L Thompson } 1398ed9e99e6SJeremy L Thompson } 1399ed9e99e6SJeremy L Thompson } 1400ed9e99e6SJeremy L Thompson data->B_in = B_in; 1401ed9e99e6SJeremy L Thompson } 1402ed9e99e6SJeremy L Thompson 1403ed9e99e6SJeremy L Thompson if (B_out && !data->B_out) { 1404ed9e99e6SJeremy L Thompson CeedInt num_qpts, elem_size; 1405ed9e99e6SJeremy L Thompson CeedScalar *B_out, *identity = NULL; 1406ed9e99e6SJeremy L Thompson const CeedScalar *interp_out, *grad_out; 1407ed9e99e6SJeremy L Thompson bool has_eval_none = false; 1408ed9e99e6SJeremy L Thompson 1409ed9e99e6SJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(data->basis_out, &num_qpts); 1410ed9e99e6SJeremy L Thompson CeedChk(ierr); 1411ed9e99e6SJeremy L Thompson ierr = CeedBasisGetNumNodes(data->basis_out, &elem_size); CeedChk(ierr); 1412ed9e99e6SJeremy L Thompson ierr = CeedCalloc(num_qpts * elem_size * data->num_eval_mode_out, &B_out); 1413ed9e99e6SJeremy L Thompson CeedChk(ierr); 1414ed9e99e6SJeremy L Thompson 1415ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < data->num_eval_mode_out; i++) { 1416ed9e99e6SJeremy L Thompson has_eval_none = has_eval_none || (data->eval_mode_out[i] == CEED_EVAL_NONE); 1417ed9e99e6SJeremy L Thompson } 1418ed9e99e6SJeremy L Thompson if (has_eval_none) { 1419ed9e99e6SJeremy L Thompson ierr = CeedCalloc(num_qpts * elem_size, &identity); CeedChk(ierr); 1420ed9e99e6SJeremy L Thompson for (CeedInt i = 0; i < (elem_size < num_qpts ? elem_size : num_qpts); i++) { 1421ed9e99e6SJeremy L Thompson identity[i * elem_size + i] = 1.0; 1422ed9e99e6SJeremy L Thompson } 1423ed9e99e6SJeremy L Thompson } 1424ed9e99e6SJeremy L Thompson ierr = CeedBasisGetInterp(data->basis_out, &interp_out); CeedChk(ierr); 1425ed9e99e6SJeremy L Thompson ierr = CeedBasisGetGrad(data->basis_out, &grad_out); CeedChk(ierr); 1426ed9e99e6SJeremy L Thompson 1427ed9e99e6SJeremy L Thompson for (CeedInt q = 0; q < num_qpts; q++) { 1428ed9e99e6SJeremy L Thompson for (CeedInt n = 0; n < elem_size; n++) { 1429ed9e99e6SJeremy L Thompson CeedInt d_out = -1; 1430ed9e99e6SJeremy L Thompson for (CeedInt e_out = 0; e_out < data->num_eval_mode_out; e_out++) { 1431ed9e99e6SJeremy L Thompson const CeedInt qq = data->num_eval_mode_out * q; 1432ed9e99e6SJeremy L Thompson const CeedScalar *b = NULL; 1433ed9e99e6SJeremy L Thompson 1434ed9e99e6SJeremy L Thompson if (data->eval_mode_out[e_out] == CEED_EVAL_GRAD) d_out++; 1435ed9e99e6SJeremy L Thompson CeedOperatorGetBasisPointer(data->eval_mode_out[e_out], identity, 1436ed9e99e6SJeremy L Thompson interp_out, &grad_out[d_out * num_qpts * elem_size], &b); CeedChk(ierr); 1437ed9e99e6SJeremy L Thompson B_out[(qq + e_out)*elem_size + n] = b[q * elem_size + n]; 1438ed9e99e6SJeremy L Thompson } 1439ed9e99e6SJeremy L Thompson } 1440ed9e99e6SJeremy L Thompson } 1441ed9e99e6SJeremy L Thompson data->B_out = B_out; 1442ed9e99e6SJeremy L Thompson } 1443ed9e99e6SJeremy L Thompson 1444ed9e99e6SJeremy L Thompson if (basis_in) *basis_in = data->basis_in; 1445ed9e99e6SJeremy L Thompson if (B_in) *B_in = data->B_in; 1446ed9e99e6SJeremy L Thompson if (basis_out) *basis_out = data->basis_out; 1447ed9e99e6SJeremy L Thompson if (B_out) *B_out = data->B_out; 1448ed9e99e6SJeremy L Thompson 1449ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1450ed9e99e6SJeremy L Thompson } 1451ed9e99e6SJeremy L Thompson 1452ed9e99e6SJeremy L Thompson /** 1453ed9e99e6SJeremy L Thompson @brief Destroy CeedOperatorAssemblyData 1454ed9e99e6SJeremy L Thompson 1455ed9e99e6SJeremy L Thompson @param[out] data CeedOperatorAssemblyData to destroy 1456ed9e99e6SJeremy L Thompson 1457ed9e99e6SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1458ed9e99e6SJeremy L Thompson 1459ed9e99e6SJeremy L Thompson @ref Backend 1460ed9e99e6SJeremy L Thompson **/ 1461ed9e99e6SJeremy L Thompson int CeedOperatorAssemblyDataDestroy(CeedOperatorAssemblyData *data) { 1462ed9e99e6SJeremy L Thompson int ierr; 1463ed9e99e6SJeremy L Thompson 1464ed9e99e6SJeremy L Thompson if (!*data) return CEED_ERROR_SUCCESS; 1465ed9e99e6SJeremy L Thompson 1466ed9e99e6SJeremy L Thompson ierr = CeedDestroy(&(*data)->ceed); CeedChk(ierr); 1467ed9e99e6SJeremy L Thompson ierr = CeedBasisDestroy(&(*data)->basis_in); CeedChk(ierr); 1468ed9e99e6SJeremy L Thompson ierr = CeedBasisDestroy(&(*data)->basis_out); CeedChk(ierr); 1469ed9e99e6SJeremy L Thompson ierr = CeedFree(&(*data)->B_in); CeedChk(ierr); 1470ed9e99e6SJeremy L Thompson ierr = CeedFree(&(*data)->B_out); CeedChk(ierr); 1471ed9e99e6SJeremy L Thompson 1472ed9e99e6SJeremy L Thompson ierr = CeedFree(data); CeedChk(ierr); 1473ed9e99e6SJeremy L Thompson return CEED_ERROR_SUCCESS; 1474ed9e99e6SJeremy L Thompson } 1475ed9e99e6SJeremy L Thompson 1476480fae85SJeremy L Thompson /// @} 1477480fae85SJeremy L Thompson 1478480fae85SJeremy L Thompson /// ---------------------------------------------------------------------------- 1479eaf62fffSJeremy L Thompson /// CeedOperator Public API 1480eaf62fffSJeremy L Thompson /// ---------------------------------------------------------------------------- 1481eaf62fffSJeremy L Thompson /// @addtogroup CeedOperatorUser 1482eaf62fffSJeremy L Thompson /// @{ 1483eaf62fffSJeremy L Thompson 1484eaf62fffSJeremy L Thompson /** 1485eaf62fffSJeremy L Thompson @brief Assemble a linear CeedQFunction associated with a CeedOperator 1486eaf62fffSJeremy L Thompson 1487eaf62fffSJeremy L Thompson This returns a CeedVector containing a matrix at each quadrature point 1488eaf62fffSJeremy L Thompson providing the action of the CeedQFunction associated with the CeedOperator. 1489eaf62fffSJeremy L Thompson The vector 'assembled' is of shape 1490eaf62fffSJeremy L Thompson [num_elements, num_input_fields, num_output_fields, num_quad_points] 1491eaf62fffSJeremy L Thompson and contains column-major matrices representing the action of the 1492eaf62fffSJeremy L Thompson CeedQFunction for a corresponding quadrature point on an element. Inputs and 1493eaf62fffSJeremy L Thompson outputs are in the order provided by the user when adding CeedOperator fields. 1494eaf62fffSJeremy L Thompson For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and 1495eaf62fffSJeremy L Thompson 'v', provided in that order, would result in an assembled QFunction that 1496eaf62fffSJeremy L Thompson consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting 1497eaf62fffSJeremy L Thompson on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v]. 1498eaf62fffSJeremy L Thompson 1499f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1500f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1501f04ea552SJeremy L Thompson 1502eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1503eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedQFunction at 1504eaf62fffSJeremy L Thompson quadrature points 1505eaf62fffSJeremy L Thompson @param[out] rstr CeedElemRestriction for CeedVector containing assembled 1506eaf62fffSJeremy L Thompson CeedQFunction 1507eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1508eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1509eaf62fffSJeremy L Thompson 1510eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1511eaf62fffSJeremy L Thompson 1512eaf62fffSJeremy L Thompson @ref User 1513eaf62fffSJeremy L Thompson **/ 1514eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled, 1515eaf62fffSJeremy L Thompson CeedElemRestriction *rstr, 1516eaf62fffSJeremy L Thompson CeedRequest *request) { 1517eaf62fffSJeremy L Thompson int ierr; 1518eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1519eaf62fffSJeremy L Thompson 1520eaf62fffSJeremy L Thompson if (op->LinearAssembleQFunction) { 1521d04bbc78SJeremy L Thompson // Backend version 152270a7ffb3SJeremy L Thompson ierr = op->LinearAssembleQFunction(op, assembled, rstr, request); 152370a7ffb3SJeremy L Thompson CeedChk(ierr); 1524eaf62fffSJeremy L Thompson } else { 1525d04bbc78SJeremy L Thompson // Operator fallback 1526d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1527d04bbc78SJeremy L Thompson 1528d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1529d04bbc78SJeremy L Thompson if (op_fallback) { 1530d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunction(op_fallback, assembled, 1531eaf62fffSJeremy L Thompson rstr, request); CeedChk(ierr); 1532d04bbc78SJeremy L Thompson } else { 1533d04bbc78SJeremy L Thompson // LCOV_EXCL_START 1534d04bbc78SJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 1535d04bbc78SJeremy L Thompson "Backend does not support CeedOperatorLinearAssembleQFunction"); 1536d04bbc78SJeremy L Thompson // LCOV_EXCL_STOP 1537d04bbc78SJeremy L Thompson } 153870a7ffb3SJeremy L Thompson } 1539eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1540eaf62fffSJeremy L Thompson } 154170a7ffb3SJeremy L Thompson 154270a7ffb3SJeremy L Thompson /** 154370a7ffb3SJeremy L Thompson @brief Assemble CeedQFunction and store result internall. Return copied 154470a7ffb3SJeremy L Thompson references of stored data to the caller. Caller is responsible for 154570a7ffb3SJeremy L Thompson ownership and destruction of the copied references. See also 154670a7ffb3SJeremy L Thompson @ref CeedOperatorLinearAssembleQFunction 154770a7ffb3SJeremy L Thompson 154870a7ffb3SJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 154970a7ffb3SJeremy L Thompson @param assembled CeedVector to store assembled CeedQFunction at 155070a7ffb3SJeremy L Thompson quadrature points 155170a7ffb3SJeremy L Thompson @param rstr CeedElemRestriction for CeedVector containing assembled 155270a7ffb3SJeremy L Thompson CeedQFunction 155370a7ffb3SJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 155470a7ffb3SJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 155570a7ffb3SJeremy L Thompson 155670a7ffb3SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 155770a7ffb3SJeremy L Thompson 155870a7ffb3SJeremy L Thompson @ref User 155970a7ffb3SJeremy L Thompson **/ 156070a7ffb3SJeremy L Thompson int CeedOperatorLinearAssembleQFunctionBuildOrUpdate(CeedOperator op, 156170a7ffb3SJeremy L Thompson CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) { 156270a7ffb3SJeremy L Thompson int ierr; 156370a7ffb3SJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 156470a7ffb3SJeremy L Thompson 156570a7ffb3SJeremy L Thompson if (op->LinearAssembleQFunctionUpdate) { 1566d04bbc78SJeremy L Thompson // Backend version 1567480fae85SJeremy L Thompson bool qf_assembled_is_setup; 15682efa2d85SJeremy L Thompson CeedVector assembled_vec = NULL; 15692efa2d85SJeremy L Thompson CeedElemRestriction assembled_rstr = NULL; 1570480fae85SJeremy L Thompson 1571480fae85SJeremy L Thompson ierr = CeedQFunctionAssemblyDataIsSetup(op->qf_assembled, 1572480fae85SJeremy L Thompson &qf_assembled_is_setup); CeedChk(ierr); 1573480fae85SJeremy L Thompson if (qf_assembled_is_setup) { 1574d04bbc78SJeremy L Thompson bool update_needed; 1575d04bbc78SJeremy L Thompson 1576480fae85SJeremy L Thompson ierr = CeedQFunctionAssemblyDataGetObjects(op->qf_assembled, &assembled_vec, 1577480fae85SJeremy L Thompson &assembled_rstr); CeedChk(ierr); 15788b919e6bSJeremy L Thompson ierr = CeedQFunctionAssemblyDataIsUpdateNeeded(op->qf_assembled, 15798b919e6bSJeremy L Thompson &update_needed); CeedChk(ierr); 15808b919e6bSJeremy L Thompson if (update_needed) { 1581480fae85SJeremy L Thompson ierr = op->LinearAssembleQFunctionUpdate(op, assembled_vec, assembled_rstr, 1582480fae85SJeremy L Thompson request); CeedChk(ierr); 15838b919e6bSJeremy L Thompson } 158470a7ffb3SJeremy L Thompson } else { 1585480fae85SJeremy L Thompson ierr = op->LinearAssembleQFunction(op, &assembled_vec, &assembled_rstr, 1586480fae85SJeremy L Thompson request); CeedChk(ierr); 1587480fae85SJeremy L Thompson ierr = CeedQFunctionAssemblyDataSetObjects(op->qf_assembled, assembled_vec, 1588480fae85SJeremy L Thompson assembled_rstr); CeedChk(ierr); 158970a7ffb3SJeremy L Thompson } 1590beecbf24SJeremy L Thompson ierr = CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, false); 15918b919e6bSJeremy L Thompson CeedChk(ierr); 15922efa2d85SJeremy L Thompson 1593d04bbc78SJeremy L Thompson // Copy reference from internally held copy 159470a7ffb3SJeremy L Thompson *assembled = NULL; 159570a7ffb3SJeremy L Thompson *rstr = NULL; 1596480fae85SJeremy L Thompson ierr = CeedVectorReferenceCopy(assembled_vec, assembled); CeedChk(ierr); 15972efa2d85SJeremy L Thompson ierr = CeedVectorDestroy(&assembled_vec); CeedChk(ierr); 1598480fae85SJeremy L Thompson ierr = CeedElemRestrictionReferenceCopy(assembled_rstr, rstr); CeedChk(ierr); 15992efa2d85SJeremy L Thompson ierr = CeedElemRestrictionDestroy(&assembled_rstr); CeedChk(ierr); 160070a7ffb3SJeremy L Thompson } else { 1601d04bbc78SJeremy L Thompson // Operator fallback 1602d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1603d04bbc78SJeremy L Thompson 1604d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1605d04bbc78SJeremy L Thompson if (op_fallback) { 1606d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op_fallback, assembled, 1607d04bbc78SJeremy L Thompson rstr, request); CeedChk(ierr); 1608d04bbc78SJeremy L Thompson } else { 1609d04bbc78SJeremy L Thompson // LCOV_EXCL_START 1610d04bbc78SJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 1611d04bbc78SJeremy L Thompson "Backend does not support CeedOperatorLinearAssembleQFunctionUpdate"); 1612d04bbc78SJeremy L Thompson // LCOV_EXCL_STOP 161370a7ffb3SJeremy L Thompson } 161470a7ffb3SJeremy L Thompson } 161570a7ffb3SJeremy L Thompson 161670a7ffb3SJeremy L Thompson return CEED_ERROR_SUCCESS; 1617eaf62fffSJeremy L Thompson } 1618eaf62fffSJeremy L Thompson 1619eaf62fffSJeremy L Thompson /** 1620eaf62fffSJeremy L Thompson @brief Assemble the diagonal of a square linear CeedOperator 1621eaf62fffSJeremy L Thompson 1622eaf62fffSJeremy L Thompson This overwrites a CeedVector with the diagonal of a linear CeedOperator. 1623eaf62fffSJeremy L Thompson 1624eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1625eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1626eaf62fffSJeremy L Thompson 1627f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1628f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1629f04ea552SJeremy L Thompson 1630eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1631eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator diagonal 1632eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1633eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1634eaf62fffSJeremy L Thompson 1635eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1636eaf62fffSJeremy L Thompson 1637eaf62fffSJeremy L Thompson @ref User 1638eaf62fffSJeremy L Thompson **/ 1639eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled, 1640eaf62fffSJeremy L Thompson CeedRequest *request) { 1641eaf62fffSJeremy L Thompson int ierr; 1642eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1643eaf62fffSJeremy L Thompson 1644c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 1645c9366a6bSJeremy L Thompson ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size); 1646c9366a6bSJeremy L Thompson CeedChk(ierr); 1647c9366a6bSJeremy L Thompson if (input_size != output_size) 1648c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1649c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1650c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 1651c9366a6bSJeremy L Thompson 1652eaf62fffSJeremy L Thompson if (op->LinearAssembleDiagonal) { 1653d04bbc78SJeremy L Thompson // Backend version 1654eaf62fffSJeremy L Thompson ierr = op->LinearAssembleDiagonal(op, assembled, request); CeedChk(ierr); 1655eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1656eaf62fffSJeremy L Thompson } else if (op->LinearAssembleAddDiagonal) { 1657d04bbc78SJeremy L Thompson // Backend version with zeroing first 1658eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1659eaf62fffSJeremy L Thompson ierr = op->LinearAssembleAddDiagonal(op, assembled, request); CeedChk(ierr); 1660eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1661eaf62fffSJeremy L Thompson } else { 1662d04bbc78SJeremy L Thompson // Operator fallback 1663d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1664d04bbc78SJeremy L Thompson 1665d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1666d04bbc78SJeremy L Thompson if (op_fallback) { 1667d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssembleDiagonal(op_fallback, assembled, request); 1668eaf62fffSJeremy L Thompson CeedChk(ierr); 1669eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1670eaf62fffSJeremy L Thompson } 1671eaf62fffSJeremy L Thompson } 1672eaf62fffSJeremy L Thompson // Default interface implementation 1673eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1674eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssembleAddDiagonal(op, assembled, request); 1675eaf62fffSJeremy L Thompson CeedChk(ierr); 1676d04bbc78SJeremy L Thompson 1677eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1678eaf62fffSJeremy L Thompson } 1679eaf62fffSJeremy L Thompson 1680eaf62fffSJeremy L Thompson /** 1681eaf62fffSJeremy L Thompson @brief Assemble the diagonal of a square linear CeedOperator 1682eaf62fffSJeremy L Thompson 1683eaf62fffSJeremy L Thompson This sums into a CeedVector the diagonal of a linear CeedOperator. 1684eaf62fffSJeremy L Thompson 1685eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1686eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1687eaf62fffSJeremy L Thompson 1688f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1689f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1690f04ea552SJeremy L Thompson 1691eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1692eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator diagonal 1693eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1694eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 1695eaf62fffSJeremy L Thompson 1696eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1697eaf62fffSJeremy L Thompson 1698eaf62fffSJeremy L Thompson @ref User 1699eaf62fffSJeremy L Thompson **/ 1700eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled, 1701eaf62fffSJeremy L Thompson CeedRequest *request) { 1702eaf62fffSJeremy L Thompson int ierr; 1703eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1704eaf62fffSJeremy L Thompson 1705c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 1706c9366a6bSJeremy L Thompson ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size); 1707c9366a6bSJeremy L Thompson CeedChk(ierr); 1708c9366a6bSJeremy L Thompson if (input_size != output_size) 1709c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1710c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1711c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 1712c9366a6bSJeremy L Thompson 1713eaf62fffSJeremy L Thompson if (op->LinearAssembleAddDiagonal) { 1714d04bbc78SJeremy L Thompson // Backend version 1715eaf62fffSJeremy L Thompson ierr = op->LinearAssembleAddDiagonal(op, assembled, request); CeedChk(ierr); 1716eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1717eaf62fffSJeremy L Thompson } else { 1718d04bbc78SJeremy L Thompson // Operator fallback 1719d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1720d04bbc78SJeremy L Thompson 1721d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1722d04bbc78SJeremy L Thompson if (op_fallback) { 1723d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssembleAddDiagonal(op_fallback, assembled, request); 1724eaf62fffSJeremy L Thompson CeedChk(ierr); 1725eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1726eaf62fffSJeremy L Thompson } 1727eaf62fffSJeremy L Thompson } 1728eaf62fffSJeremy L Thompson // Default interface implementation 1729eaf62fffSJeremy L Thompson bool is_composite; 1730eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1731eaf62fffSJeremy L Thompson if (is_composite) { 1732eaf62fffSJeremy L Thompson ierr = CeedCompositeOperatorLinearAssembleAddDiagonal(op, request, 1733eaf62fffSJeremy L Thompson false, assembled); CeedChk(ierr); 1734eaf62fffSJeremy L Thompson } else { 1735eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssembleAddDiagonal(op, request, false, assembled); 1736eaf62fffSJeremy L Thompson CeedChk(ierr); 1737eaf62fffSJeremy L Thompson } 1738d04bbc78SJeremy L Thompson 1739d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 1740eaf62fffSJeremy L Thompson } 1741eaf62fffSJeremy L Thompson 1742eaf62fffSJeremy L Thompson /** 1743eaf62fffSJeremy L Thompson @brief Assemble the point block diagonal of a square linear CeedOperator 1744eaf62fffSJeremy L Thompson 1745eaf62fffSJeremy L Thompson This overwrites a CeedVector with the point block diagonal of a linear 1746eaf62fffSJeremy L Thompson CeedOperator. 1747eaf62fffSJeremy L Thompson 1748eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1749eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1750eaf62fffSJeremy L Thompson 1751f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1752f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1753f04ea552SJeremy L Thompson 1754eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1755eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator point block 1756eaf62fffSJeremy L Thompson diagonal, provided in row-major form with an 1757eaf62fffSJeremy L Thompson @a num_comp * @a num_comp block at each node. The dimensions 1758eaf62fffSJeremy L Thompson of this vector are derived from the active vector 1759eaf62fffSJeremy L Thompson for the CeedOperator. The array has shape 1760eaf62fffSJeremy L Thompson [nodes, component out, component in]. 1761eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1762eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 1763eaf62fffSJeremy L Thompson 1764eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1765eaf62fffSJeremy L Thompson 1766eaf62fffSJeremy L Thompson @ref User 1767eaf62fffSJeremy L Thompson **/ 1768eaf62fffSJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op, 1769eaf62fffSJeremy L Thompson CeedVector assembled, CeedRequest *request) { 1770eaf62fffSJeremy L Thompson int ierr; 1771eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1772eaf62fffSJeremy L Thompson 1773c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 1774c9366a6bSJeremy L Thompson ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size); 1775c9366a6bSJeremy L Thompson CeedChk(ierr); 1776c9366a6bSJeremy L Thompson if (input_size != output_size) 1777c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1778c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1779c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 1780c9366a6bSJeremy L Thompson 1781eaf62fffSJeremy L Thompson if (op->LinearAssemblePointBlockDiagonal) { 1782d04bbc78SJeremy L Thompson // Backend version 1783eaf62fffSJeremy L Thompson ierr = op->LinearAssemblePointBlockDiagonal(op, assembled, request); 1784eaf62fffSJeremy L Thompson CeedChk(ierr); 1785eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1786eaf62fffSJeremy L Thompson } else if (op->LinearAssembleAddPointBlockDiagonal) { 1787d04bbc78SJeremy L Thompson // Backend version with zeroing first 1788eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1789eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, 1790eaf62fffSJeremy L Thompson request); CeedChk(ierr); 1791eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1792eaf62fffSJeremy L Thompson } else { 1793d04bbc78SJeremy L Thompson // Operator fallback 1794d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1795d04bbc78SJeremy L Thompson 1796d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1797d04bbc78SJeremy L Thompson if (op_fallback) { 1798d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssemblePointBlockDiagonal(op_fallback, assembled, 1799d04bbc78SJeremy L Thompson request); CeedChk(ierr); 1800eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1801eaf62fffSJeremy L Thompson } 1802eaf62fffSJeremy L Thompson } 1803eaf62fffSJeremy L Thompson // Default interface implementation 1804eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1805eaf62fffSJeremy L Thompson ierr = CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, request); 1806eaf62fffSJeremy L Thompson CeedChk(ierr); 1807d04bbc78SJeremy L Thompson 1808eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1809eaf62fffSJeremy L Thompson } 1810eaf62fffSJeremy L Thompson 1811eaf62fffSJeremy L Thompson /** 1812eaf62fffSJeremy L Thompson @brief Assemble the point block diagonal of a square linear CeedOperator 1813eaf62fffSJeremy L Thompson 1814eaf62fffSJeremy L Thompson This sums into a CeedVector with the point block diagonal of a linear 1815eaf62fffSJeremy L Thompson CeedOperator. 1816eaf62fffSJeremy L Thompson 1817eaf62fffSJeremy L Thompson Note: Currently only non-composite CeedOperators with a single field and 1818eaf62fffSJeremy L Thompson composite CeedOperators with single field sub-operators are supported. 1819eaf62fffSJeremy L Thompson 1820f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1821f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1822f04ea552SJeremy L Thompson 1823eaf62fffSJeremy L Thompson @param op CeedOperator to assemble CeedQFunction 1824eaf62fffSJeremy L Thompson @param[out] assembled CeedVector to store assembled CeedOperator point block 1825eaf62fffSJeremy L Thompson diagonal, provided in row-major form with an 1826eaf62fffSJeremy L Thompson @a num_comp * @a num_comp block at each node. The dimensions 1827eaf62fffSJeremy L Thompson of this vector are derived from the active vector 1828eaf62fffSJeremy L Thompson for the CeedOperator. The array has shape 1829eaf62fffSJeremy L Thompson [nodes, component out, component in]. 1830eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 1831eaf62fffSJeremy L Thompson CEED_REQUEST_IMMEDIATE 1832eaf62fffSJeremy L Thompson 1833eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1834eaf62fffSJeremy L Thompson 1835eaf62fffSJeremy L Thompson @ref User 1836eaf62fffSJeremy L Thompson **/ 1837eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op, 1838eaf62fffSJeremy L Thompson CeedVector assembled, CeedRequest *request) { 1839eaf62fffSJeremy L Thompson int ierr; 1840eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1841eaf62fffSJeremy L Thompson 1842c9366a6bSJeremy L Thompson CeedSize input_size = 0, output_size = 0; 1843c9366a6bSJeremy L Thompson ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size); 1844c9366a6bSJeremy L Thompson CeedChk(ierr); 1845c9366a6bSJeremy L Thompson if (input_size != output_size) 1846c9366a6bSJeremy L Thompson // LCOV_EXCL_START 1847c9366a6bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, "Operator must be square"); 1848c9366a6bSJeremy L Thompson // LCOV_EXCL_STOP 1849c9366a6bSJeremy L Thompson 1850eaf62fffSJeremy L Thompson if (op->LinearAssembleAddPointBlockDiagonal) { 1851d04bbc78SJeremy L Thompson // Backend version 1852eaf62fffSJeremy L Thompson ierr = op->LinearAssembleAddPointBlockDiagonal(op, assembled, request); 1853eaf62fffSJeremy L Thompson CeedChk(ierr); 1854eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1855eaf62fffSJeremy L Thompson } else { 1856d04bbc78SJeremy L Thompson // Operator fallback 1857d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1858d04bbc78SJeremy L Thompson 1859d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1860d04bbc78SJeremy L Thompson if (op_fallback) { 1861d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssembleAddPointBlockDiagonal(op_fallback, assembled, 1862d04bbc78SJeremy L Thompson request); CeedChk(ierr); 1863eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1864eaf62fffSJeremy L Thompson } 1865eaf62fffSJeremy L Thompson } 1866eaf62fffSJeremy L Thompson // Default interface implemenation 1867eaf62fffSJeremy L Thompson bool is_composite; 1868eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1869eaf62fffSJeremy L Thompson if (is_composite) { 1870eaf62fffSJeremy L Thompson ierr = CeedCompositeOperatorLinearAssembleAddDiagonal(op, request, 1871eaf62fffSJeremy L Thompson true, assembled); CeedChk(ierr); 1872eaf62fffSJeremy L Thompson } else { 1873eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssembleAddDiagonal(op, request, true, assembled); 1874eaf62fffSJeremy L Thompson CeedChk(ierr); 1875eaf62fffSJeremy L Thompson } 1876d04bbc78SJeremy L Thompson 1877d04bbc78SJeremy L Thompson return CEED_ERROR_SUCCESS; 1878eaf62fffSJeremy L Thompson } 1879eaf62fffSJeremy L Thompson 1880eaf62fffSJeremy L Thompson /** 1881eaf62fffSJeremy L Thompson @brief Fully assemble the nonzero pattern of a linear operator. 1882eaf62fffSJeremy L Thompson 1883eaf62fffSJeremy L Thompson Expected to be used in conjunction with CeedOperatorLinearAssemble() 1884eaf62fffSJeremy L Thompson 1885eaf62fffSJeremy L Thompson The assembly routines use coordinate format, with num_entries tuples of the 1886eaf62fffSJeremy L Thompson form (i, j, value) which indicate that value should be added to the matrix 1887eaf62fffSJeremy L Thompson in entry (i, j). Note that the (i, j) pairs are not unique and may repeat. 1888eaf62fffSJeremy L Thompson This function returns the number of entries and their (i, j) locations, 1889eaf62fffSJeremy L Thompson while CeedOperatorLinearAssemble() provides the values in the same 1890eaf62fffSJeremy L Thompson ordering. 1891eaf62fffSJeremy L Thompson 1892eaf62fffSJeremy L Thompson This will generally be slow unless your operator is low-order. 1893eaf62fffSJeremy L Thompson 1894f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1895f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1896f04ea552SJeremy L Thompson 1897eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 1898eaf62fffSJeremy L Thompson @param[out] num_entries Number of entries in coordinate nonzero pattern 1899eaf62fffSJeremy L Thompson @param[out] rows Row number for each entry 1900eaf62fffSJeremy L Thompson @param[out] cols Column number for each entry 1901eaf62fffSJeremy L Thompson 1902eaf62fffSJeremy L Thompson @ref User 1903eaf62fffSJeremy L Thompson **/ 1904c30b7fbdSJeremy L Thompson int CeedOperatorLinearAssembleSymbolic(CeedOperator op, CeedSize *num_entries, 1905eaf62fffSJeremy L Thompson CeedInt **rows, CeedInt **cols) { 1906eaf62fffSJeremy L Thompson int ierr; 1907eaf62fffSJeremy L Thompson CeedInt num_suboperators, single_entries; 1908eaf62fffSJeremy L Thompson CeedOperator *sub_operators; 1909eaf62fffSJeremy L Thompson bool is_composite; 1910eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1911eaf62fffSJeremy L Thompson 1912eaf62fffSJeremy L Thompson if (op->LinearAssembleSymbolic) { 1913d04bbc78SJeremy L Thompson // Backend version 1914eaf62fffSJeremy L Thompson ierr = op->LinearAssembleSymbolic(op, num_entries, rows, cols); CeedChk(ierr); 1915eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1916eaf62fffSJeremy L Thompson } else { 1917d04bbc78SJeremy L Thompson // Operator fallback 1918d04bbc78SJeremy L Thompson CeedOperator op_fallback; 1919d04bbc78SJeremy L Thompson 1920d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 1921d04bbc78SJeremy L Thompson if (op_fallback) { 1922d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssembleSymbolic(op_fallback, num_entries, rows, cols); 1923eaf62fffSJeremy L Thompson CeedChk(ierr); 1924eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1925eaf62fffSJeremy L Thompson } 1926eaf62fffSJeremy L Thompson } 1927eaf62fffSJeremy L Thompson 1928eaf62fffSJeremy L Thompson // Default interface implementation 1929eaf62fffSJeremy L Thompson 1930eaf62fffSJeremy L Thompson // count entries and allocate rows, cols arrays 1931eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1932eaf62fffSJeremy L Thompson *num_entries = 0; 1933eaf62fffSJeremy L Thompson if (is_composite) { 1934eaf62fffSJeremy L Thompson ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1935eaf62fffSJeremy L Thompson ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 193692ae7e47SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; ++k) { 1937eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k], 1938eaf62fffSJeremy L Thompson &single_entries); CeedChk(ierr); 1939eaf62fffSJeremy L Thompson *num_entries += single_entries; 1940eaf62fffSJeremy L Thompson } 1941eaf62fffSJeremy L Thompson } else { 1942eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemblyCountEntries(op, 1943eaf62fffSJeremy L Thompson &single_entries); CeedChk(ierr); 1944eaf62fffSJeremy L Thompson *num_entries += single_entries; 1945eaf62fffSJeremy L Thompson } 1946eaf62fffSJeremy L Thompson ierr = CeedCalloc(*num_entries, rows); CeedChk(ierr); 1947eaf62fffSJeremy L Thompson ierr = CeedCalloc(*num_entries, cols); CeedChk(ierr); 1948eaf62fffSJeremy L Thompson 1949eaf62fffSJeremy L Thompson // assemble nonzero locations 1950eaf62fffSJeremy L Thompson CeedInt offset = 0; 1951eaf62fffSJeremy L Thompson if (is_composite) { 1952eaf62fffSJeremy L Thompson ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1953eaf62fffSJeremy L Thompson ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 195492ae7e47SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; ++k) { 1955eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssembleSymbolic(sub_operators[k], offset, *rows, 1956eaf62fffSJeremy L Thompson *cols); CeedChk(ierr); 1957eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k], 1958eaf62fffSJeremy L Thompson &single_entries); 1959eaf62fffSJeremy L Thompson CeedChk(ierr); 1960eaf62fffSJeremy L Thompson offset += single_entries; 1961eaf62fffSJeremy L Thompson } 1962eaf62fffSJeremy L Thompson } else { 1963eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssembleSymbolic(op, offset, *rows, *cols); 1964eaf62fffSJeremy L Thompson CeedChk(ierr); 1965eaf62fffSJeremy L Thompson } 1966eaf62fffSJeremy L Thompson 1967eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 1968eaf62fffSJeremy L Thompson } 1969eaf62fffSJeremy L Thompson 1970eaf62fffSJeremy L Thompson /** 1971eaf62fffSJeremy L Thompson @brief Fully assemble the nonzero entries of a linear operator. 1972eaf62fffSJeremy L Thompson 1973eaf62fffSJeremy L Thompson Expected to be used in conjunction with CeedOperatorLinearAssembleSymbolic() 1974eaf62fffSJeremy L Thompson 1975eaf62fffSJeremy L Thompson The assembly routines use coordinate format, with num_entries tuples of the 1976eaf62fffSJeremy L Thompson form (i, j, value) which indicate that value should be added to the matrix 1977eaf62fffSJeremy L Thompson in entry (i, j). Note that the (i, j) pairs are not unique and may repeat. 1978eaf62fffSJeremy L Thompson This function returns the values of the nonzero entries to be added, their 1979eaf62fffSJeremy L Thompson (i, j) locations are provided by CeedOperatorLinearAssembleSymbolic() 1980eaf62fffSJeremy L Thompson 1981eaf62fffSJeremy L Thompson This will generally be slow unless your operator is low-order. 1982eaf62fffSJeremy L Thompson 1983f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1984f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1985f04ea552SJeremy L Thompson 1986eaf62fffSJeremy L Thompson @param[in] op CeedOperator to assemble 1987eaf62fffSJeremy L Thompson @param[out] values Values to assemble into matrix 1988eaf62fffSJeremy L Thompson 1989eaf62fffSJeremy L Thompson @ref User 1990eaf62fffSJeremy L Thompson **/ 1991eaf62fffSJeremy L Thompson int CeedOperatorLinearAssemble(CeedOperator op, CeedVector values) { 1992eaf62fffSJeremy L Thompson int ierr; 1993eaf62fffSJeremy L Thompson CeedInt num_suboperators, single_entries = 0; 1994eaf62fffSJeremy L Thompson CeedOperator *sub_operators; 1995eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1996eaf62fffSJeremy L Thompson 1997eaf62fffSJeremy L Thompson if (op->LinearAssemble) { 1998d04bbc78SJeremy L Thompson // Backend version 1999eaf62fffSJeremy L Thompson ierr = op->LinearAssemble(op, values); CeedChk(ierr); 2000eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2001eaf62fffSJeremy L Thompson } else { 2002d04bbc78SJeremy L Thompson // Operator fallback 2003d04bbc78SJeremy L Thompson CeedOperator op_fallback; 2004d04bbc78SJeremy L Thompson 2005d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 2006d04bbc78SJeremy L Thompson if (op_fallback) { 2007d04bbc78SJeremy L Thompson ierr = CeedOperatorLinearAssemble(op_fallback, values); CeedChk(ierr); 2008eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2009eaf62fffSJeremy L Thompson } 2010eaf62fffSJeremy L Thompson } 2011eaf62fffSJeremy L Thompson 2012eaf62fffSJeremy L Thompson // Default interface implementation 2013eaf62fffSJeremy L Thompson bool is_composite; 2014eaf62fffSJeremy L Thompson ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 2015eaf62fffSJeremy L Thompson 2016eaf62fffSJeremy L Thompson CeedInt offset = 0; 2017eaf62fffSJeremy L Thompson if (is_composite) { 2018eaf62fffSJeremy L Thompson ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 2019eaf62fffSJeremy L Thompson ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 2020cefa2673SJeremy L Thompson for (CeedInt k = 0; k < num_suboperators; k++) { 2021eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemble(sub_operators[k], offset, values); 2022eaf62fffSJeremy L Thompson CeedChk(ierr); 2023eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k], 2024eaf62fffSJeremy L Thompson &single_entries); 2025eaf62fffSJeremy L Thompson CeedChk(ierr); 2026eaf62fffSJeremy L Thompson offset += single_entries; 2027eaf62fffSJeremy L Thompson } 2028eaf62fffSJeremy L Thompson } else { 2029eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorAssemble(op, offset, values); CeedChk(ierr); 2030eaf62fffSJeremy L Thompson } 2031eaf62fffSJeremy L Thompson 2032eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2033eaf62fffSJeremy L Thompson } 2034eaf62fffSJeremy L Thompson 2035eaf62fffSJeremy L Thompson /** 2036eaf62fffSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators 2037eaf62fffSJeremy L Thompson for a CeedOperator, creating the prolongation basis from the 2038eaf62fffSJeremy L Thompson fine and coarse grid interpolation 2039eaf62fffSJeremy L Thompson 2040f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 2041f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 2042f04ea552SJeremy L Thompson 2043eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 2044eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 2045eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 2046eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 2047eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 2048eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 2049eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 2050eaf62fffSJeremy L Thompson 2051eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2052eaf62fffSJeremy L Thompson 2053eaf62fffSJeremy L Thompson @ref User 2054eaf62fffSJeremy L Thompson **/ 2055eaf62fffSJeremy L Thompson int CeedOperatorMultigridLevelCreate(CeedOperator op_fine, 2056eaf62fffSJeremy L Thompson CeedVector p_mult_fine, 2057eaf62fffSJeremy L Thompson CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 2058eaf62fffSJeremy L Thompson CeedOperator *op_coarse, CeedOperator *op_prolong, 2059eaf62fffSJeremy L Thompson CeedOperator *op_restrict) { 2060eaf62fffSJeremy L Thompson int ierr; 2061f04ea552SJeremy L Thompson ierr = CeedOperatorCheckReady(op_fine); CeedChk(ierr); 2062eaf62fffSJeremy L Thompson Ceed ceed; 2063eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr); 2064eaf62fffSJeremy L Thompson 2065eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 2066eaf62fffSJeremy L Thompson CeedBasis basis_fine; 2067eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr); 2068eaf62fffSJeremy L Thompson CeedInt Q_f, Q_c; 2069eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr); 2070eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr); 2071eaf62fffSJeremy L Thompson if (Q_f != Q_c) 2072eaf62fffSJeremy L Thompson // LCOV_EXCL_START 2073eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, 2074eaf62fffSJeremy L Thompson "Bases must have compatible quadrature spaces"); 2075eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 2076eaf62fffSJeremy L Thompson 2077eaf62fffSJeremy L Thompson // Coarse to fine basis 2078eaf62fffSJeremy L Thompson CeedInt P_f, P_c, Q = Q_f; 2079eaf62fffSJeremy L Thompson bool is_tensor_f, is_tensor_c; 2080eaf62fffSJeremy L Thompson ierr = CeedBasisIsTensor(basis_fine, &is_tensor_f); CeedChk(ierr); 2081eaf62fffSJeremy L Thompson ierr = CeedBasisIsTensor(basis_coarse, &is_tensor_c); CeedChk(ierr); 2082eaf62fffSJeremy L Thompson CeedScalar *interp_c, *interp_f, *interp_c_to_f, *tau; 2083eaf62fffSJeremy L Thompson if (is_tensor_f && is_tensor_c) { 2084eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes1D(basis_fine, &P_f); CeedChk(ierr); 2085eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes1D(basis_coarse, &P_c); CeedChk(ierr); 2086eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints1D(basis_coarse, &Q); CeedChk(ierr); 2087eaf62fffSJeremy L Thompson } else if (!is_tensor_f && !is_tensor_c) { 2088eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis_fine, &P_f); CeedChk(ierr); 2089eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis_coarse, &P_c); CeedChk(ierr); 2090eaf62fffSJeremy L Thompson } else { 2091eaf62fffSJeremy L Thompson // LCOV_EXCL_START 2092eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_MINOR, 2093eaf62fffSJeremy L Thompson "Bases must both be tensor or non-tensor"); 2094eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 2095eaf62fffSJeremy L Thompson } 2096eaf62fffSJeremy L Thompson 2097eaf62fffSJeremy L Thompson ierr = CeedMalloc(Q*P_f, &interp_f); CeedChk(ierr); 2098eaf62fffSJeremy L Thompson ierr = CeedMalloc(Q*P_c, &interp_c); CeedChk(ierr); 2099eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_c*P_f, &interp_c_to_f); CeedChk(ierr); 2100eaf62fffSJeremy L Thompson ierr = CeedMalloc(Q, &tau); CeedChk(ierr); 21018575dcacSJeremy L Thompson const CeedScalar *interp_f_source = NULL, *interp_c_source = NULL; 2102eaf62fffSJeremy L Thompson if (is_tensor_f) { 21038575dcacSJeremy L Thompson ierr = CeedBasisGetInterp1D(basis_fine, &interp_f_source); CeedChk(ierr); 21048575dcacSJeremy L Thompson ierr = CeedBasisGetInterp1D(basis_coarse, &interp_c_source); CeedChk(ierr); 2105eaf62fffSJeremy L Thompson } else { 21068575dcacSJeremy L Thompson ierr = CeedBasisGetInterp(basis_fine, &interp_f_source); CeedChk(ierr); 21078575dcacSJeremy L Thompson ierr = CeedBasisGetInterp(basis_coarse, &interp_c_source); CeedChk(ierr); 2108eaf62fffSJeremy L Thompson } 21098575dcacSJeremy L Thompson memcpy(interp_f, interp_f_source, Q*P_f*sizeof interp_f_source[0]); 21108575dcacSJeremy L Thompson memcpy(interp_c, interp_c_source, Q*P_c*sizeof interp_c_source[0]); 2111eaf62fffSJeremy L Thompson 2112eaf62fffSJeremy L Thompson // -- QR Factorization, interp_f = Q R 2113eaf62fffSJeremy L Thompson ierr = CeedQRFactorization(ceed, interp_f, tau, Q, P_f); CeedChk(ierr); 2114eaf62fffSJeremy L Thompson 2115eaf62fffSJeremy L Thompson // -- Apply Qtranspose, interp_c = Qtranspose interp_c 2116eaf62fffSJeremy L Thompson ierr = CeedHouseholderApplyQ(interp_c, interp_f, tau, CEED_TRANSPOSE, 2117eaf62fffSJeremy L Thompson Q, P_c, P_f, P_c, 1); CeedChk(ierr); 2118eaf62fffSJeremy L Thompson 2119eaf62fffSJeremy L Thompson // -- Apply Rinv, interp_c_to_f = Rinv interp_c 2120eaf62fffSJeremy L Thompson for (CeedInt j=0; j<P_c; j++) { // Column j 2121eaf62fffSJeremy 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]; 2122eaf62fffSJeremy L Thompson for (CeedInt i=P_f-2; i>=0; i--) { // Row i 2123eaf62fffSJeremy L Thompson interp_c_to_f[j+P_c*i] = interp_c[j+P_c*i]; 2124eaf62fffSJeremy L Thompson for (CeedInt k=i+1; k<P_f; k++) 2125eaf62fffSJeremy L Thompson interp_c_to_f[j+P_c*i] -= interp_f[k+P_f*i]*interp_c_to_f[j+P_c*k]; 2126eaf62fffSJeremy L Thompson interp_c_to_f[j+P_c*i] /= interp_f[i+P_f*i]; 2127eaf62fffSJeremy L Thompson } 2128eaf62fffSJeremy L Thompson } 2129eaf62fffSJeremy L Thompson ierr = CeedFree(&tau); CeedChk(ierr); 2130eaf62fffSJeremy L Thompson ierr = CeedFree(&interp_c); CeedChk(ierr); 2131eaf62fffSJeremy L Thompson ierr = CeedFree(&interp_f); CeedChk(ierr); 2132eaf62fffSJeremy L Thompson 2133eaf62fffSJeremy L Thompson // Complete with interp_c_to_f versions of code 2134eaf62fffSJeremy L Thompson if (is_tensor_f) { 2135eaf62fffSJeremy L Thompson ierr = CeedOperatorMultigridLevelCreateTensorH1(op_fine, p_mult_fine, 2136eaf62fffSJeremy L Thompson rstr_coarse, basis_coarse, interp_c_to_f, op_coarse, op_prolong, op_restrict); 2137eaf62fffSJeremy L Thompson CeedChk(ierr); 2138eaf62fffSJeremy L Thompson } else { 2139eaf62fffSJeremy L Thompson ierr = CeedOperatorMultigridLevelCreateH1(op_fine, p_mult_fine, 2140eaf62fffSJeremy L Thompson rstr_coarse, basis_coarse, interp_c_to_f, op_coarse, op_prolong, op_restrict); 2141eaf62fffSJeremy L Thompson CeedChk(ierr); 2142eaf62fffSJeremy L Thompson } 2143eaf62fffSJeremy L Thompson 2144eaf62fffSJeremy L Thompson // Cleanup 2145eaf62fffSJeremy L Thompson ierr = CeedFree(&interp_c_to_f); CeedChk(ierr); 2146eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2147eaf62fffSJeremy L Thompson } 2148eaf62fffSJeremy L Thompson 2149eaf62fffSJeremy L Thompson /** 2150eaf62fffSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators 2151eaf62fffSJeremy L Thompson for a CeedOperator with a tensor basis for the active basis 2152eaf62fffSJeremy L Thompson 2153f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 2154f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 2155f04ea552SJeremy L Thompson 2156eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 2157eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 2158eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 2159eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 2160eaf62fffSJeremy L Thompson @param[in] interp_c_to_f Matrix for coarse to fine interpolation 2161eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 2162eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 2163eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 2164eaf62fffSJeremy L Thompson 2165eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2166eaf62fffSJeremy L Thompson 2167eaf62fffSJeremy L Thompson @ref User 2168eaf62fffSJeremy L Thompson **/ 2169eaf62fffSJeremy L Thompson int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator op_fine, 2170eaf62fffSJeremy L Thompson CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse, 2171eaf62fffSJeremy L Thompson const CeedScalar *interp_c_to_f, CeedOperator *op_coarse, 2172eaf62fffSJeremy L Thompson CeedOperator *op_prolong, CeedOperator *op_restrict) { 2173eaf62fffSJeremy L Thompson int ierr; 2174f04ea552SJeremy L Thompson ierr = CeedOperatorCheckReady(op_fine); CeedChk(ierr); 2175eaf62fffSJeremy L Thompson Ceed ceed; 2176eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr); 2177eaf62fffSJeremy L Thompson 2178eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 2179eaf62fffSJeremy L Thompson CeedBasis basis_fine; 2180eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr); 2181eaf62fffSJeremy L Thompson CeedInt Q_f, Q_c; 2182eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr); 2183eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr); 2184eaf62fffSJeremy L Thompson if (Q_f != Q_c) 2185eaf62fffSJeremy L Thompson // LCOV_EXCL_START 2186eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, 2187eaf62fffSJeremy L Thompson "Bases must have compatible quadrature spaces"); 2188eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 2189eaf62fffSJeremy L Thompson 2190eaf62fffSJeremy L Thompson // Coarse to fine basis 2191eaf62fffSJeremy L Thompson CeedInt dim, num_comp, num_nodes_c, P_1d_f, P_1d_c; 2192eaf62fffSJeremy L Thompson ierr = CeedBasisGetDimension(basis_fine, &dim); CeedChk(ierr); 2193eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis_fine, &num_comp); CeedChk(ierr); 2194eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes1D(basis_fine, &P_1d_f); CeedChk(ierr); 2195eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c); 2196eaf62fffSJeremy L Thompson CeedChk(ierr); 2197eaf62fffSJeremy L Thompson P_1d_c = dim == 1 ? num_nodes_c : 2198eaf62fffSJeremy L Thompson dim == 2 ? sqrt(num_nodes_c) : 2199eaf62fffSJeremy L Thompson cbrt(num_nodes_c); 2200eaf62fffSJeremy L Thompson CeedScalar *q_ref, *q_weight, *grad; 2201eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d_f, &q_ref); CeedChk(ierr); 2202eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d_f, &q_weight); CeedChk(ierr); 2203eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d_f*P_1d_c*dim, &grad); CeedChk(ierr); 2204eaf62fffSJeremy L Thompson CeedBasis basis_c_to_f; 2205eaf62fffSJeremy L Thompson ierr = CeedBasisCreateTensorH1(ceed, dim, num_comp, P_1d_c, P_1d_f, 2206eaf62fffSJeremy L Thompson interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f); 2207eaf62fffSJeremy L Thompson CeedChk(ierr); 2208eaf62fffSJeremy L Thompson ierr = CeedFree(&q_ref); CeedChk(ierr); 2209eaf62fffSJeremy L Thompson ierr = CeedFree(&q_weight); CeedChk(ierr); 2210eaf62fffSJeremy L Thompson ierr = CeedFree(&grad); CeedChk(ierr); 2211eaf62fffSJeremy L Thompson 2212eaf62fffSJeremy L Thompson // Core code 2213eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, 2214eaf62fffSJeremy L Thompson basis_coarse, basis_c_to_f, op_coarse, 2215eaf62fffSJeremy L Thompson op_prolong, op_restrict); 2216eaf62fffSJeremy L Thompson CeedChk(ierr); 2217eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2218eaf62fffSJeremy L Thompson } 2219eaf62fffSJeremy L Thompson 2220eaf62fffSJeremy L Thompson /** 2221eaf62fffSJeremy L Thompson @brief Create a multigrid coarse operator and level transfer operators 2222eaf62fffSJeremy L Thompson for a CeedOperator with a non-tensor basis for the active vector 2223eaf62fffSJeremy L Thompson 2224f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 2225f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 2226f04ea552SJeremy L Thompson 2227eaf62fffSJeremy L Thompson @param[in] op_fine Fine grid operator 2228eaf62fffSJeremy L Thompson @param[in] p_mult_fine L-vector multiplicity in parallel gather/scatter 2229eaf62fffSJeremy L Thompson @param[in] rstr_coarse Coarse grid restriction 2230eaf62fffSJeremy L Thompson @param[in] basis_coarse Coarse grid active vector basis 2231eaf62fffSJeremy L Thompson @param[in] interp_c_to_f Matrix for coarse to fine interpolation 2232eaf62fffSJeremy L Thompson @param[out] op_coarse Coarse grid operator 2233eaf62fffSJeremy L Thompson @param[out] op_prolong Coarse to fine operator 2234eaf62fffSJeremy L Thompson @param[out] op_restrict Fine to coarse operator 2235eaf62fffSJeremy L Thompson 2236eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2237eaf62fffSJeremy L Thompson 2238eaf62fffSJeremy L Thompson @ref User 2239eaf62fffSJeremy L Thompson **/ 2240eaf62fffSJeremy L Thompson int CeedOperatorMultigridLevelCreateH1(CeedOperator op_fine, 2241eaf62fffSJeremy L Thompson CeedVector p_mult_fine, 2242eaf62fffSJeremy L Thompson CeedElemRestriction rstr_coarse, 2243eaf62fffSJeremy L Thompson CeedBasis basis_coarse, 2244eaf62fffSJeremy L Thompson const CeedScalar *interp_c_to_f, 2245eaf62fffSJeremy L Thompson CeedOperator *op_coarse, 2246eaf62fffSJeremy L Thompson CeedOperator *op_prolong, 2247eaf62fffSJeremy L Thompson CeedOperator *op_restrict) { 2248eaf62fffSJeremy L Thompson int ierr; 2249f04ea552SJeremy L Thompson ierr = CeedOperatorCheckReady(op_fine); CeedChk(ierr); 2250eaf62fffSJeremy L Thompson Ceed ceed; 2251eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr); 2252eaf62fffSJeremy L Thompson 2253eaf62fffSJeremy L Thompson // Check for compatible quadrature spaces 2254eaf62fffSJeremy L Thompson CeedBasis basis_fine; 2255eaf62fffSJeremy L Thompson ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr); 2256eaf62fffSJeremy L Thompson CeedInt Q_f, Q_c; 2257eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr); 2258eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr); 2259eaf62fffSJeremy L Thompson if (Q_f != Q_c) 2260eaf62fffSJeremy L Thompson // LCOV_EXCL_START 2261eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, 2262eaf62fffSJeremy L Thompson "Bases must have compatible quadrature spaces"); 2263eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 2264eaf62fffSJeremy L Thompson 2265eaf62fffSJeremy L Thompson // Coarse to fine basis 2266eaf62fffSJeremy L Thompson CeedElemTopology topo; 2267eaf62fffSJeremy L Thompson ierr = CeedBasisGetTopology(basis_fine, &topo); CeedChk(ierr); 2268eaf62fffSJeremy L Thompson CeedInt dim, num_comp, num_nodes_c, num_nodes_f; 2269eaf62fffSJeremy L Thompson ierr = CeedBasisGetDimension(basis_fine, &dim); CeedChk(ierr); 2270eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis_fine, &num_comp); CeedChk(ierr); 2271eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis_fine, &num_nodes_f); CeedChk(ierr); 2272eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c); 2273eaf62fffSJeremy L Thompson CeedChk(ierr); 2274eaf62fffSJeremy L Thompson CeedScalar *q_ref, *q_weight, *grad; 2275f9e0419eSJeremy L Thompson ierr = CeedCalloc(num_nodes_f*dim, &q_ref); CeedChk(ierr); 2276eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_nodes_f, &q_weight); CeedChk(ierr); 2277eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_nodes_f*num_nodes_c*dim, &grad); CeedChk(ierr); 2278eaf62fffSJeremy L Thompson CeedBasis basis_c_to_f; 2279eaf62fffSJeremy L Thompson ierr = CeedBasisCreateH1(ceed, topo, num_comp, num_nodes_c, num_nodes_f, 2280eaf62fffSJeremy L Thompson interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f); 2281eaf62fffSJeremy L Thompson CeedChk(ierr); 2282eaf62fffSJeremy L Thompson ierr = CeedFree(&q_ref); CeedChk(ierr); 2283eaf62fffSJeremy L Thompson ierr = CeedFree(&q_weight); CeedChk(ierr); 2284eaf62fffSJeremy L Thompson ierr = CeedFree(&grad); CeedChk(ierr); 2285eaf62fffSJeremy L Thompson 2286eaf62fffSJeremy L Thompson // Core code 2287eaf62fffSJeremy L Thompson ierr = CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse, 2288eaf62fffSJeremy L Thompson basis_coarse, basis_c_to_f, op_coarse, 2289eaf62fffSJeremy L Thompson op_prolong, op_restrict); 2290eaf62fffSJeremy L Thompson CeedChk(ierr); 2291eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2292eaf62fffSJeremy L Thompson } 2293eaf62fffSJeremy L Thompson 2294eaf62fffSJeremy L Thompson /** 2295eaf62fffSJeremy L Thompson @brief Build a FDM based approximate inverse for each element for a 2296eaf62fffSJeremy L Thompson CeedOperator 2297eaf62fffSJeremy L Thompson 2298eaf62fffSJeremy L Thompson This returns a CeedOperator and CeedVector to apply a Fast Diagonalization 2299eaf62fffSJeremy L Thompson Method based approximate inverse. This function obtains the simultaneous 2300eaf62fffSJeremy L Thompson diagonalization for the 1D mass and Laplacian operators, 2301eaf62fffSJeremy L Thompson M = V^T V, K = V^T S V. 2302eaf62fffSJeremy L Thompson The assembled QFunction is used to modify the eigenvalues from simultaneous 2303eaf62fffSJeremy L Thompson diagonalization and obtain an approximate inverse of the form 2304eaf62fffSJeremy L Thompson V^T S^hat V. The CeedOperator must be linear and non-composite. The 2305eaf62fffSJeremy L Thompson associated CeedQFunction must therefore also be linear. 2306eaf62fffSJeremy L Thompson 2307f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 2308f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 2309f04ea552SJeremy L Thompson 2310eaf62fffSJeremy L Thompson @param op CeedOperator to create element inverses 2311eaf62fffSJeremy L Thompson @param[out] fdm_inv CeedOperator to apply the action of a FDM based inverse 2312eaf62fffSJeremy L Thompson for each element 2313eaf62fffSJeremy L Thompson @param request Address of CeedRequest for non-blocking completion, else 2314eaf62fffSJeremy L Thompson @ref CEED_REQUEST_IMMEDIATE 2315eaf62fffSJeremy L Thompson 2316eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2317eaf62fffSJeremy L Thompson 2318480fae85SJeremy L Thompson @ref User 2319eaf62fffSJeremy L Thompson **/ 2320eaf62fffSJeremy L Thompson int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdm_inv, 2321eaf62fffSJeremy L Thompson CeedRequest *request) { 2322eaf62fffSJeremy L Thompson int ierr; 2323eaf62fffSJeremy L Thompson ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 2324eaf62fffSJeremy L Thompson 2325eaf62fffSJeremy L Thompson if (op->CreateFDMElementInverse) { 2326d04bbc78SJeremy L Thompson // Backend version 2327eaf62fffSJeremy L Thompson ierr = op->CreateFDMElementInverse(op, fdm_inv, request); CeedChk(ierr); 2328eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2329eaf62fffSJeremy L Thompson } else { 2330d04bbc78SJeremy L Thompson // Operator fallback 2331d04bbc78SJeremy L Thompson CeedOperator op_fallback; 2332d04bbc78SJeremy L Thompson 2333d04bbc78SJeremy L Thompson ierr = CeedOperatorGetFallback(op, &op_fallback); CeedChk(ierr); 2334d04bbc78SJeremy L Thompson if (op_fallback) { 2335d04bbc78SJeremy L Thompson ierr = CeedOperatorCreateFDMElementInverse(op_fallback, fdm_inv, request); 2336eaf62fffSJeremy L Thompson CeedChk(ierr); 2337eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2338eaf62fffSJeremy L Thompson } 2339eaf62fffSJeremy L Thompson } 2340eaf62fffSJeremy L Thompson 2341d04bbc78SJeremy L Thompson // Default interface implementation 2342eaf62fffSJeremy L Thompson Ceed ceed, ceed_parent; 2343eaf62fffSJeremy L Thompson ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 2344eaf62fffSJeremy L Thompson ierr = CeedGetOperatorFallbackParentCeed(ceed, &ceed_parent); CeedChk(ierr); 2345eaf62fffSJeremy L Thompson ceed_parent = ceed_parent ? ceed_parent : ceed; 2346eaf62fffSJeremy L Thompson CeedQFunction qf; 2347eaf62fffSJeremy L Thompson ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr); 2348eaf62fffSJeremy L Thompson 2349eaf62fffSJeremy L Thompson // Determine active input basis 2350eaf62fffSJeremy L Thompson bool interp = false, grad = false; 2351eaf62fffSJeremy L Thompson CeedBasis basis = NULL; 2352eaf62fffSJeremy L Thompson CeedElemRestriction rstr = NULL; 2353eaf62fffSJeremy L Thompson CeedOperatorField *op_fields; 2354eaf62fffSJeremy L Thompson CeedQFunctionField *qf_fields; 2355eaf62fffSJeremy L Thompson CeedInt num_input_fields; 23567e7773b5SJeremy L Thompson ierr = CeedOperatorGetFields(op, &num_input_fields, &op_fields, NULL, NULL); 23577e7773b5SJeremy L Thompson CeedChk(ierr); 23587e7773b5SJeremy L Thompson ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL); CeedChk(ierr); 2359eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_input_fields; i++) { 2360eaf62fffSJeremy L Thompson CeedVector vec; 2361eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChk(ierr); 2362eaf62fffSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) { 2363eaf62fffSJeremy L Thompson CeedEvalMode eval_mode; 2364eaf62fffSJeremy L Thompson ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); CeedChk(ierr); 2365eaf62fffSJeremy L Thompson interp = interp || eval_mode == CEED_EVAL_INTERP; 2366eaf62fffSJeremy L Thompson grad = grad || eval_mode == CEED_EVAL_GRAD; 2367eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis); CeedChk(ierr); 2368eaf62fffSJeremy L Thompson ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr); CeedChk(ierr); 2369eaf62fffSJeremy L Thompson } 2370eaf62fffSJeremy L Thompson } 2371eaf62fffSJeremy L Thompson if (!basis) 2372eaf62fffSJeremy L Thompson // LCOV_EXCL_START 2373eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "No active field set"); 2374eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 2375e79b91d9SJeremy L Thompson CeedSize l_size = 1; 2376e79b91d9SJeremy L Thompson CeedInt P_1d, Q_1d, elem_size, num_qpts, dim, num_comp = 1, num_elem = 1; 2377eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes1D(basis, &P_1d); CeedChk(ierr); 2378eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumNodes(basis, &elem_size); CeedChk(ierr); 2379eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d); CeedChk(ierr); 2380eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumQuadraturePoints(basis, &num_qpts); CeedChk(ierr); 2381eaf62fffSJeremy L Thompson ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr); 2382eaf62fffSJeremy L Thompson ierr = CeedBasisGetNumComponents(basis, &num_comp); CeedChk(ierr); 2383eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr); 2384eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetLVectorSize(rstr, &l_size); CeedChk(ierr); 2385eaf62fffSJeremy L Thompson 2386eaf62fffSJeremy L Thompson // Build and diagonalize 1D Mass and Laplacian 2387eaf62fffSJeremy L Thompson bool tensor_basis; 2388eaf62fffSJeremy L Thompson ierr = CeedBasisIsTensor(basis, &tensor_basis); CeedChk(ierr); 2389eaf62fffSJeremy L Thompson if (!tensor_basis) 2390eaf62fffSJeremy L Thompson // LCOV_EXCL_START 2391eaf62fffSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, 2392eaf62fffSJeremy L Thompson "FDMElementInverse only supported for tensor " 2393eaf62fffSJeremy L Thompson "bases"); 2394eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 2395eaf62fffSJeremy L Thompson CeedScalar *mass, *laplace, *x, *fdm_interp, *lambda; 2396eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &mass); CeedChk(ierr); 2397eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &laplace); CeedChk(ierr); 2398eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &x); CeedChk(ierr); 2399eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &fdm_interp); CeedChk(ierr); 2400eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d, &lambda); CeedChk(ierr); 2401eaf62fffSJeremy L Thompson // -- Build matrices 2402eaf62fffSJeremy L Thompson const CeedScalar *interp_1d, *grad_1d, *q_weight_1d; 2403eaf62fffSJeremy L Thompson ierr = CeedBasisGetInterp1D(basis, &interp_1d); CeedChk(ierr); 2404eaf62fffSJeremy L Thompson ierr = CeedBasisGetGrad1D(basis, &grad_1d); CeedChk(ierr); 2405eaf62fffSJeremy L Thompson ierr = CeedBasisGetQWeights(basis, &q_weight_1d); CeedChk(ierr); 2406eaf62fffSJeremy L Thompson ierr = CeedBuildMassLaplace(interp_1d, grad_1d, q_weight_1d, P_1d, Q_1d, dim, 2407eaf62fffSJeremy L Thompson mass, laplace); CeedChk(ierr); 2408eaf62fffSJeremy L Thompson 2409eaf62fffSJeremy L Thompson // -- Diagonalize 2410eaf62fffSJeremy L Thompson ierr = CeedSimultaneousDiagonalization(ceed, laplace, mass, x, lambda, P_1d); 2411eaf62fffSJeremy L Thompson CeedChk(ierr); 2412eaf62fffSJeremy L Thompson ierr = CeedFree(&mass); CeedChk(ierr); 2413eaf62fffSJeremy L Thompson ierr = CeedFree(&laplace); CeedChk(ierr); 2414eaf62fffSJeremy L Thompson for (CeedInt i=0; i<P_1d; i++) 2415eaf62fffSJeremy L Thompson for (CeedInt j=0; j<P_1d; j++) 2416eaf62fffSJeremy L Thompson fdm_interp[i+j*P_1d] = x[j+i*P_1d]; 2417eaf62fffSJeremy L Thompson ierr = CeedFree(&x); CeedChk(ierr); 2418eaf62fffSJeremy L Thompson 2419eaf62fffSJeremy L Thompson // Assemble QFunction 2420eaf62fffSJeremy L Thompson CeedVector assembled; 2421eaf62fffSJeremy L Thompson CeedElemRestriction rstr_qf; 242270a7ffb3SJeremy L Thompson ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled, 242370a7ffb3SJeremy L Thompson &rstr_qf, request); CeedChk(ierr); 2424eaf62fffSJeremy L Thompson CeedInt layout[3]; 2425eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionGetELayout(rstr_qf, &layout); CeedChk(ierr); 2426eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr_qf); CeedChk(ierr); 2427eaf62fffSJeremy L Thompson CeedScalar max_norm = 0; 2428eaf62fffSJeremy L Thompson ierr = CeedVectorNorm(assembled, CEED_NORM_MAX, &max_norm); CeedChk(ierr); 2429eaf62fffSJeremy L Thompson 2430eaf62fffSJeremy L Thompson // Calculate element averages 2431eaf62fffSJeremy L Thompson CeedInt num_modes = (interp?1:0) + (grad?dim:0); 2432eaf62fffSJeremy L Thompson CeedScalar *elem_avg; 2433eaf62fffSJeremy L Thompson const CeedScalar *assembled_array, *q_weight_array; 2434eaf62fffSJeremy L Thompson CeedVector q_weight; 2435eaf62fffSJeremy L Thompson ierr = CeedVectorCreate(ceed_parent, num_qpts, &q_weight); CeedChk(ierr); 2436eaf62fffSJeremy L Thompson ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, 2437eaf62fffSJeremy L Thompson CEED_VECTOR_NONE, q_weight); CeedChk(ierr); 2438eaf62fffSJeremy L Thompson ierr = CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembled_array); 2439eaf62fffSJeremy L Thompson CeedChk(ierr); 2440eaf62fffSJeremy L Thompson ierr = CeedVectorGetArrayRead(q_weight, CEED_MEM_HOST, &q_weight_array); 2441eaf62fffSJeremy L Thompson CeedChk(ierr); 2442eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_elem, &elem_avg); CeedChk(ierr); 2443eaf62fffSJeremy L Thompson const CeedScalar qf_value_bound = max_norm*100*CEED_EPSILON; 2444eaf62fffSJeremy L Thompson for (CeedInt e=0; e<num_elem; e++) { 2445eaf62fffSJeremy L Thompson CeedInt count = 0; 2446eaf62fffSJeremy L Thompson for (CeedInt q=0; q<num_qpts; q++) 2447eaf62fffSJeremy L Thompson for (CeedInt i=0; i<num_comp*num_comp*num_modes*num_modes; i++) 2448eaf62fffSJeremy L Thompson if (fabs(assembled_array[q*layout[0] + i*layout[1] + e*layout[2]]) > 2449eaf62fffSJeremy L Thompson qf_value_bound) { 2450eaf62fffSJeremy L Thompson elem_avg[e] += assembled_array[q*layout[0] + i*layout[1] + e*layout[2]] / 2451eaf62fffSJeremy L Thompson q_weight_array[q]; 2452eaf62fffSJeremy L Thompson count++; 2453eaf62fffSJeremy L Thompson } 2454eaf62fffSJeremy L Thompson if (count) { 2455eaf62fffSJeremy L Thompson elem_avg[e] /= count; 2456eaf62fffSJeremy L Thompson } else { 2457eaf62fffSJeremy L Thompson elem_avg[e] = 1.0; 2458eaf62fffSJeremy L Thompson } 2459eaf62fffSJeremy L Thompson } 2460eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArrayRead(assembled, &assembled_array); CeedChk(ierr); 2461eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&assembled); CeedChk(ierr); 2462eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArrayRead(q_weight, &q_weight_array); CeedChk(ierr); 2463eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&q_weight); CeedChk(ierr); 2464eaf62fffSJeremy L Thompson 2465eaf62fffSJeremy L Thompson // Build FDM diagonal 2466eaf62fffSJeremy L Thompson CeedVector q_data; 2467eaf62fffSJeremy L Thompson CeedScalar *q_data_array, *fdm_diagonal; 2468eaf62fffSJeremy L Thompson ierr = CeedCalloc(num_comp*elem_size, &fdm_diagonal); CeedChk(ierr); 2469eaf62fffSJeremy L Thompson const CeedScalar fdm_diagonal_bound = elem_size*CEED_EPSILON; 2470eaf62fffSJeremy L Thompson for (CeedInt c=0; c<num_comp; c++) 2471eaf62fffSJeremy L Thompson for (CeedInt n=0; n<elem_size; n++) { 2472eaf62fffSJeremy L Thompson if (interp) 2473eaf62fffSJeremy L Thompson fdm_diagonal[c*elem_size + n] = 1.0; 2474eaf62fffSJeremy L Thompson if (grad) 2475eaf62fffSJeremy L Thompson for (CeedInt d=0; d<dim; d++) { 2476eaf62fffSJeremy L Thompson CeedInt i = (n / CeedIntPow(P_1d, d)) % P_1d; 2477eaf62fffSJeremy L Thompson fdm_diagonal[c*elem_size + n] += lambda[i]; 2478eaf62fffSJeremy L Thompson } 2479eaf62fffSJeremy L Thompson if (fabs(fdm_diagonal[c*elem_size + n]) < fdm_diagonal_bound) 2480eaf62fffSJeremy L Thompson fdm_diagonal[c*elem_size + n] = fdm_diagonal_bound; 2481eaf62fffSJeremy L Thompson } 2482eaf62fffSJeremy L Thompson ierr = CeedVectorCreate(ceed_parent, num_elem*num_comp*elem_size, &q_data); 2483eaf62fffSJeremy L Thompson CeedChk(ierr); 2484eaf62fffSJeremy L Thompson ierr = CeedVectorSetValue(q_data, 0.0); CeedChk(ierr); 24859c774eddSJeremy L Thompson ierr = CeedVectorGetArrayWrite(q_data, CEED_MEM_HOST, &q_data_array); 24869c774eddSJeremy L Thompson CeedChk(ierr); 2487eaf62fffSJeremy L Thompson for (CeedInt e=0; e<num_elem; e++) 2488eaf62fffSJeremy L Thompson for (CeedInt c=0; c<num_comp; c++) 2489eaf62fffSJeremy L Thompson for (CeedInt n=0; n<elem_size; n++) 2490eaf62fffSJeremy L Thompson q_data_array[(e*num_comp+c)*elem_size+n] = 1. / (elem_avg[e] * 2491eaf62fffSJeremy L Thompson fdm_diagonal[c*elem_size + n]); 2492eaf62fffSJeremy L Thompson ierr = CeedFree(&elem_avg); CeedChk(ierr); 2493eaf62fffSJeremy L Thompson ierr = CeedFree(&fdm_diagonal); CeedChk(ierr); 2494eaf62fffSJeremy L Thompson ierr = CeedVectorRestoreArray(q_data, &q_data_array); CeedChk(ierr); 2495eaf62fffSJeremy L Thompson 2496eaf62fffSJeremy L Thompson // Setup FDM operator 2497eaf62fffSJeremy L Thompson // -- Basis 2498eaf62fffSJeremy L Thompson CeedBasis fdm_basis; 2499eaf62fffSJeremy L Thompson CeedScalar *grad_dummy, *q_ref_dummy, *q_weight_dummy; 2500eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d*P_1d, &grad_dummy); CeedChk(ierr); 2501eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d, &q_ref_dummy); CeedChk(ierr); 2502eaf62fffSJeremy L Thompson ierr = CeedCalloc(P_1d, &q_weight_dummy); CeedChk(ierr); 2503eaf62fffSJeremy L Thompson ierr = CeedBasisCreateTensorH1(ceed_parent, dim, num_comp, P_1d, P_1d, 2504eaf62fffSJeremy L Thompson fdm_interp, grad_dummy, q_ref_dummy, 2505eaf62fffSJeremy L Thompson q_weight_dummy, &fdm_basis); CeedChk(ierr); 2506eaf62fffSJeremy L Thompson ierr = CeedFree(&fdm_interp); CeedChk(ierr); 2507eaf62fffSJeremy L Thompson ierr = CeedFree(&grad_dummy); CeedChk(ierr); 2508eaf62fffSJeremy L Thompson ierr = CeedFree(&q_ref_dummy); CeedChk(ierr); 2509eaf62fffSJeremy L Thompson ierr = CeedFree(&q_weight_dummy); CeedChk(ierr); 2510eaf62fffSJeremy L Thompson ierr = CeedFree(&lambda); CeedChk(ierr); 2511eaf62fffSJeremy L Thompson 2512eaf62fffSJeremy L Thompson // -- Restriction 2513eaf62fffSJeremy L Thompson CeedElemRestriction rstr_qd_i; 2514eaf62fffSJeremy L Thompson CeedInt strides[3] = {1, elem_size, elem_size*num_comp}; 2515eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionCreateStrided(ceed_parent, num_elem, elem_size, 2516eaf62fffSJeremy L Thompson num_comp, num_elem*num_comp*elem_size, 2517eaf62fffSJeremy L Thompson strides, &rstr_qd_i); CeedChk(ierr); 2518eaf62fffSJeremy L Thompson // -- QFunction 2519eaf62fffSJeremy L Thompson CeedQFunction qf_fdm; 2520eaf62fffSJeremy L Thompson ierr = CeedQFunctionCreateInteriorByName(ceed_parent, "Scale", &qf_fdm); 2521eaf62fffSJeremy L Thompson CeedChk(ierr); 2522eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_fdm, "input", num_comp, CEED_EVAL_INTERP); 2523eaf62fffSJeremy L Thompson CeedChk(ierr); 2524eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddInput(qf_fdm, "scale", num_comp, CEED_EVAL_NONE); 2525eaf62fffSJeremy L Thompson CeedChk(ierr); 2526eaf62fffSJeremy L Thompson ierr = CeedQFunctionAddOutput(qf_fdm, "output", num_comp, CEED_EVAL_INTERP); 2527eaf62fffSJeremy L Thompson CeedChk(ierr); 25286e15d496SJeremy L Thompson ierr = CeedQFunctionSetUserFlopsEstimate(qf_fdm, num_comp); CeedChk(ierr); 2529eaf62fffSJeremy L Thompson // -- QFunction context 2530eaf62fffSJeremy L Thompson CeedInt *num_comp_data; 2531eaf62fffSJeremy L Thompson ierr = CeedCalloc(1, &num_comp_data); CeedChk(ierr); 2532eaf62fffSJeremy L Thompson num_comp_data[0] = num_comp; 2533eaf62fffSJeremy L Thompson CeedQFunctionContext ctx_fdm; 2534eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextCreate(ceed, &ctx_fdm); CeedChk(ierr); 2535eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextSetData(ctx_fdm, CEED_MEM_HOST, CEED_OWN_POINTER, 2536eaf62fffSJeremy L Thompson sizeof(*num_comp_data), num_comp_data); 2537eaf62fffSJeremy L Thompson CeedChk(ierr); 2538eaf62fffSJeremy L Thompson ierr = CeedQFunctionSetContext(qf_fdm, ctx_fdm); CeedChk(ierr); 2539eaf62fffSJeremy L Thompson ierr = CeedQFunctionContextDestroy(&ctx_fdm); CeedChk(ierr); 2540eaf62fffSJeremy L Thompson // -- Operator 2541eaf62fffSJeremy L Thompson ierr = CeedOperatorCreate(ceed_parent, qf_fdm, NULL, NULL, fdm_inv); 2542eaf62fffSJeremy L Thompson CeedChk(ierr); 2543eaf62fffSJeremy L Thompson CeedOperatorSetField(*fdm_inv, "input", rstr, fdm_basis, CEED_VECTOR_ACTIVE); 2544eaf62fffSJeremy L Thompson CeedChk(ierr); 2545eaf62fffSJeremy L Thompson CeedOperatorSetField(*fdm_inv, "scale", rstr_qd_i, CEED_BASIS_COLLOCATED, 2546eaf62fffSJeremy L Thompson q_data); CeedChk(ierr); 2547eaf62fffSJeremy L Thompson CeedOperatorSetField(*fdm_inv, "output", rstr, fdm_basis, CEED_VECTOR_ACTIVE); 2548eaf62fffSJeremy L Thompson CeedChk(ierr); 2549eaf62fffSJeremy L Thompson 2550eaf62fffSJeremy L Thompson // Cleanup 2551eaf62fffSJeremy L Thompson ierr = CeedVectorDestroy(&q_data); CeedChk(ierr); 2552eaf62fffSJeremy L Thompson ierr = CeedBasisDestroy(&fdm_basis); CeedChk(ierr); 2553eaf62fffSJeremy L Thompson ierr = CeedElemRestrictionDestroy(&rstr_qd_i); CeedChk(ierr); 2554eaf62fffSJeremy L Thompson ierr = CeedQFunctionDestroy(&qf_fdm); CeedChk(ierr); 2555eaf62fffSJeremy L Thompson 2556eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 2557eaf62fffSJeremy L Thompson } 2558eaf62fffSJeremy L Thompson 2559eaf62fffSJeremy L Thompson /// @} 2560