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. 3d7b241e6Sjeremylt // 43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause 5d7b241e6Sjeremylt // 63d8e8822SJeremy L Thompson // This file is part of CEED: http://github.com/ceed 7d7b241e6Sjeremylt 83d576824SJeremy L Thompson #include <ceed-impl.h> 9*2b730f8bSJeremy L Thompson #include <ceed/backend.h> 10*2b730f8bSJeremy L Thompson #include <ceed/ceed.h> 113d576824SJeremy L Thompson #include <stdbool.h> 123d576824SJeremy L Thompson #include <stdio.h> 133d576824SJeremy L Thompson #include <string.h> 14d7b241e6Sjeremylt 15dfdf5a53Sjeremylt /// @file 167a982d89SJeremy L. Thompson /// Implementation of CeedOperator interfaces 177a982d89SJeremy L. Thompson 187a982d89SJeremy L. Thompson /// ---------------------------------------------------------------------------- 197a982d89SJeremy L. Thompson /// CeedOperator Library Internal Functions 207a982d89SJeremy L. Thompson /// ---------------------------------------------------------------------------- 217a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorDeveloper 227a982d89SJeremy L. Thompson /// @{ 237a982d89SJeremy L. Thompson 247a982d89SJeremy L. Thompson /** 25e15f9bd0SJeremy L Thompson @brief Check if a CeedOperator Field matches the QFunction Field 26e15f9bd0SJeremy L Thompson 27e15f9bd0SJeremy L Thompson @param[in] ceed Ceed object for error handling 28d1d35e2fSjeremylt @param[in] qf_field QFunction Field matching Operator Field 29e15f9bd0SJeremy L Thompson @param[in] r Operator Field ElemRestriction 30e15f9bd0SJeremy L Thompson @param[in] b Operator Field Basis 31e15f9bd0SJeremy L Thompson 32e15f9bd0SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 33e15f9bd0SJeremy L Thompson 34e15f9bd0SJeremy L Thompson @ref Developer 35e15f9bd0SJeremy L Thompson **/ 36*2b730f8bSJeremy L Thompson static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field, CeedElemRestriction r, CeedBasis b) { 37d1d35e2fSjeremylt CeedEvalMode eval_mode = qf_field->eval_mode; 38*2b730f8bSJeremy L Thompson CeedInt dim = 1, num_comp = 1, Q_comp = 1, restr_num_comp = 1, size = qf_field->size; 39*2b730f8bSJeremy L Thompson 40e15f9bd0SJeremy L Thompson // Restriction 41e15f9bd0SJeremy L Thompson if (r != CEED_ELEMRESTRICTION_NONE) { 42d1d35e2fSjeremylt if (eval_mode == CEED_EVAL_WEIGHT) { 43e15f9bd0SJeremy L Thompson // LCOV_EXCL_START 44*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, "CEED_ELEMRESTRICTION_NONE should be used for a field with eval mode CEED_EVAL_WEIGHT"); 45e15f9bd0SJeremy L Thompson // LCOV_EXCL_STOP 46e15f9bd0SJeremy L Thompson } 47*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumComponents(r, &restr_num_comp)); 48e1e9e29dSJed Brown } 49d1d35e2fSjeremylt if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == CEED_EVAL_WEIGHT)) { 50e1e9e29dSJed Brown // LCOV_EXCL_START 51*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT must be used together."); 52e1e9e29dSJed Brown // LCOV_EXCL_STOP 53e1e9e29dSJed Brown } 54e15f9bd0SJeremy L Thompson // Basis 55e15f9bd0SJeremy L Thompson if (b != CEED_BASIS_COLLOCATED) { 56*2b730f8bSJeremy L Thompson if (eval_mode == CEED_EVAL_NONE) { 578229195eSjeremylt // LCOV_EXCL_START 58*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, "Field '%s' configured with CEED_EVAL_NONE must be used with CEED_BASIS_COLLOCATED", 59d1d35e2fSjeremylt qf_field->field_name); 6041bdf1c9SJeremy L Thompson // LCOV_EXCL_STOP 61*2b730f8bSJeremy L Thompson } 62*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetDimension(b, &dim)); 63*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumComponents(b, &num_comp)); 64*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadratureComponents(b, &Q_comp)); 65d1d35e2fSjeremylt if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) { 66e15f9bd0SJeremy L Thompson // LCOV_EXCL_START 67e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, 68*2b730f8bSJeremy L Thompson "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: ElemRestriction has %" CeedInt_FMT 69*2b730f8bSJeremy L Thompson " components, but Basis has %" CeedInt_FMT " components", 70*2b730f8bSJeremy L Thompson qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], restr_num_comp, num_comp); 71e15f9bd0SJeremy L Thompson // LCOV_EXCL_STOP 72e15f9bd0SJeremy L Thompson } 7341bdf1c9SJeremy L Thompson } else if (eval_mode != CEED_EVAL_NONE) { 7441bdf1c9SJeremy L Thompson // LCOV_EXCL_START 75*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, "Field '%s' configured with %s cannot be used with CEED_BASIS_COLLOCATED", qf_field->field_name, 76*2b730f8bSJeremy L Thompson CeedEvalModes[eval_mode]); 7741bdf1c9SJeremy L Thompson // LCOV_EXCL_STOP 78e15f9bd0SJeremy L Thompson } 79e15f9bd0SJeremy L Thompson // Field size 80d1d35e2fSjeremylt switch (eval_mode) { 81e15f9bd0SJeremy L Thompson case CEED_EVAL_NONE: 82*2b730f8bSJeremy L Thompson if (size != restr_num_comp) { 83e15f9bd0SJeremy L Thompson // LCOV_EXCL_START 84e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, 85*2b730f8bSJeremy L Thompson "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: ElemRestriction has " CeedInt_FMT " components", qf_field->field_name, 86*2b730f8bSJeremy L Thompson qf_field->size, CeedEvalModes[qf_field->eval_mode], restr_num_comp); 87e15f9bd0SJeremy L Thompson // LCOV_EXCL_STOP 88*2b730f8bSJeremy L Thompson } 89e15f9bd0SJeremy L Thompson break; 90e15f9bd0SJeremy L Thompson case CEED_EVAL_INTERP: 91*2b730f8bSJeremy L Thompson if (size != num_comp * Q_comp) { 92e15f9bd0SJeremy L Thompson // LCOV_EXCL_START 93e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, 94*2b730f8bSJeremy L Thompson "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: ElemRestriction/Basis has " CeedInt_FMT " components", 95*2b730f8bSJeremy L Thompson qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], num_comp * Q_comp); 96e15f9bd0SJeremy L Thompson // LCOV_EXCL_STOP 97*2b730f8bSJeremy L Thompson } 98e15f9bd0SJeremy L Thompson break; 99e15f9bd0SJeremy L Thompson case CEED_EVAL_GRAD: 100*2b730f8bSJeremy L Thompson if (size != num_comp * dim) { 101e15f9bd0SJeremy L Thompson // LCOV_EXCL_START 102e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_DIMENSION, 103*2b730f8bSJeremy L Thompson "Field '%s' of size %" CeedInt_FMT " and EvalMode %s in %" CeedInt_FMT " dimensions: ElemRestriction/Basis has %" CeedInt_FMT 104*2b730f8bSJeremy L Thompson " components", 105*2b730f8bSJeremy L Thompson qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim, num_comp); 106e15f9bd0SJeremy L Thompson // LCOV_EXCL_STOP 107*2b730f8bSJeremy L Thompson } 108e15f9bd0SJeremy L Thompson break; 109e15f9bd0SJeremy L Thompson case CEED_EVAL_WEIGHT: 110d1d35e2fSjeremylt // No additional checks required 111e15f9bd0SJeremy L Thompson break; 112e15f9bd0SJeremy L Thompson case CEED_EVAL_DIV: 113*2b730f8bSJeremy L Thompson if (size != num_comp) { 114a0c16c2cSrezgarshakeri // LCOV_EXCL_START 115a0c16c2cSrezgarshakeri return CeedError(ceed, CEED_ERROR_DIMENSION, 116*2b730f8bSJeremy L Thompson "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: ElemRestriction/Basis has " CeedInt_FMT " components", 117*2b730f8bSJeremy L Thompson qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], num_comp); 118a0c16c2cSrezgarshakeri // LCOV_EXCL_STOP 119*2b730f8bSJeremy L Thompson } 120e15f9bd0SJeremy L Thompson break; 121e15f9bd0SJeremy L Thompson case CEED_EVAL_CURL: 122e15f9bd0SJeremy L Thompson // Not implemented 123e15f9bd0SJeremy L Thompson break; 124e15f9bd0SJeremy L Thompson } 125e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 1267a982d89SJeremy L. Thompson } 1277a982d89SJeremy L. Thompson 1287a982d89SJeremy L. Thompson /** 1297a982d89SJeremy L. Thompson @brief View a field of a CeedOperator 1307a982d89SJeremy L. Thompson 1317a982d89SJeremy L. Thompson @param[in] field Operator field to view 132d1d35e2fSjeremylt @param[in] qf_field QFunction field (carries field name) 133d1d35e2fSjeremylt @param[in] field_number Number of field being viewed 1344c4400c7SValeria Barra @param[in] sub true indicates sub-operator, which increases indentation; false for top-level operator 135d1d35e2fSjeremylt @param[in] input true for an input field; false for output field 1367a982d89SJeremy L. Thompson @param[in] stream Stream to view to, e.g., stdout 1377a982d89SJeremy L. Thompson 1387a982d89SJeremy L. Thompson @return An error code: 0 - success, otherwise - failure 1397a982d89SJeremy L. Thompson 1407a982d89SJeremy L. Thompson @ref Utility 1417a982d89SJeremy L. Thompson **/ 142*2b730f8bSJeremy L Thompson static int CeedOperatorFieldView(CeedOperatorField field, CeedQFunctionField qf_field, CeedInt field_number, bool sub, bool input, FILE *stream) { 1437a982d89SJeremy L. Thompson const char *pre = sub ? " " : ""; 144d1d35e2fSjeremylt const char *in_out = input ? "Input" : "Output"; 1457a982d89SJeremy L. Thompson 146*2b730f8bSJeremy L Thompson fprintf(stream, 147*2b730f8bSJeremy L Thompson "%s %s field %" CeedInt_FMT 148*2b730f8bSJeremy L Thompson ":\n" 1497a982d89SJeremy L. Thompson "%s Name: \"%s\"\n", 150d1d35e2fSjeremylt pre, in_out, field_number, pre, qf_field->field_name); 1517a982d89SJeremy L. Thompson 152990fdeb6SJeremy L Thompson fprintf(stream, "%s Size: %" CeedInt_FMT "\n", pre, qf_field->size); 153f5ebfb90SJeremy L Thompson 154*2b730f8bSJeremy L Thompson fprintf(stream, "%s EvalMode: %s\n", pre, CeedEvalModes[qf_field->eval_mode]); 155f5ebfb90SJeremy L Thompson 156*2b730f8bSJeremy L Thompson if (field->basis == CEED_BASIS_COLLOCATED) fprintf(stream, "%s Collocated basis\n", pre); 1577a982d89SJeremy L. Thompson 158*2b730f8bSJeremy L Thompson if (field->vec == CEED_VECTOR_ACTIVE) fprintf(stream, "%s Active vector\n", pre); 159*2b730f8bSJeremy L Thompson else if (field->vec == CEED_VECTOR_NONE) fprintf(stream, "%s No vector\n", pre); 160f5ebfb90SJeremy L Thompson 161e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 1627a982d89SJeremy L. Thompson } 1637a982d89SJeremy L. Thompson 1647a982d89SJeremy L. Thompson /** 1657a982d89SJeremy L. Thompson @brief View a single CeedOperator 1667a982d89SJeremy L. Thompson 1677a982d89SJeremy L. Thompson @param[in] op CeedOperator to view 1687a982d89SJeremy L. Thompson @param[in] sub Boolean flag for sub-operator 1697a982d89SJeremy L. Thompson @param[in] stream Stream to write; typically stdout/stderr or a file 1707a982d89SJeremy L. Thompson 1717a982d89SJeremy L. Thompson @return Error code: 0 - success, otherwise - failure 1727a982d89SJeremy L. Thompson 1737a982d89SJeremy L. Thompson @ref Utility 1747a982d89SJeremy L. Thompson **/ 1757a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) { 1767a982d89SJeremy L. Thompson const char *pre = sub ? " " : ""; 1777a982d89SJeremy L. Thompson 178381e6593SJeremy L Thompson CeedInt num_elem, num_qpts; 179*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 180*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts)); 181381e6593SJeremy L Thompson 18278464608Sjeremylt CeedInt total_fields = 0; 183*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetNumArgs(op, &total_fields)); 184*2b730f8bSJeremy L Thompson fprintf(stream, "%s %" CeedInt_FMT " elements with %" CeedInt_FMT " quadrature points each\n", pre, num_elem, num_qpts); 1857a982d89SJeremy L. Thompson 186*2b730f8bSJeremy L Thompson fprintf(stream, "%s %" CeedInt_FMT " field%s\n", pre, total_fields, total_fields > 1 ? "s" : ""); 1877a982d89SJeremy L. Thompson 188*2b730f8bSJeremy L Thompson fprintf(stream, "%s %" CeedInt_FMT " input field%s:\n", pre, op->qf->num_input_fields, op->qf->num_input_fields > 1 ? "s" : ""); 189d1d35e2fSjeremylt for (CeedInt i = 0; i < op->qf->num_input_fields; i++) { 190*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i], i, sub, 1, stream)); 1917a982d89SJeremy L. Thompson } 1927a982d89SJeremy L. Thompson 193*2b730f8bSJeremy L Thompson fprintf(stream, "%s %" CeedInt_FMT " output field%s:\n", pre, op->qf->num_output_fields, op->qf->num_output_fields > 1 ? "s" : ""); 194d1d35e2fSjeremylt for (CeedInt i = 0; i < op->qf->num_output_fields; i++) { 195*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i], i, sub, 0, stream)); 1967a982d89SJeremy L. Thompson } 197e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 1987a982d89SJeremy L. Thompson } 1997a982d89SJeremy L. Thompson 200d99fa3c5SJeremy L Thompson /** 2010f60e0a8SJeremy L Thompson @brief Find the active vector basis for a non-composite CeedOperator 202eaf62fffSJeremy L Thompson 203eaf62fffSJeremy L Thompson @param[in] op CeedOperator to find active basis for 2040f60e0a8SJeremy L Thompson @param[out] active_basis Basis for active input vector or NULL for composite operator 205eaf62fffSJeremy L Thompson 206eaf62fffSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 207eaf62fffSJeremy L Thompson 208eaf62fffSJeremy L Thompson @ ref Developer 209eaf62fffSJeremy L Thompson **/ 210eaf62fffSJeremy L Thompson int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) { 211eaf62fffSJeremy L Thompson *active_basis = NULL; 2120f60e0a8SJeremy L Thompson if (op->is_composite) return CEED_ERROR_SUCCESS; 213*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < op->qf->num_input_fields; i++) { 214eaf62fffSJeremy L Thompson if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 215eaf62fffSJeremy L Thompson *active_basis = op->input_fields[i]->basis; 216eaf62fffSJeremy L Thompson break; 217eaf62fffSJeremy L Thompson } 218*2b730f8bSJeremy L Thompson } 219eaf62fffSJeremy L Thompson 220eaf62fffSJeremy L Thompson if (!*active_basis) { 221eaf62fffSJeremy L Thompson // LCOV_EXCL_START 222eaf62fffSJeremy L Thompson Ceed ceed; 223*2b730f8bSJeremy L Thompson 224*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 225*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_MINOR, "No active CeedBasis found"); 226eaf62fffSJeremy L Thompson // LCOV_EXCL_STOP 227eaf62fffSJeremy L Thompson } 228eaf62fffSJeremy L Thompson return CEED_ERROR_SUCCESS; 229eaf62fffSJeremy L Thompson } 230eaf62fffSJeremy L Thompson 231eaf62fffSJeremy L Thompson /** 2320f60e0a8SJeremy L Thompson @brief Find the active vector ElemRestriction for a non-composite CeedOperator 233e2f04181SAndrew T. Barker 234e2f04181SAndrew T. Barker @param[in] op CeedOperator to find active basis for 2350f60e0a8SJeremy L Thompson @param[out] active_rstr ElemRestriction for active input vector or NULL for composite operator 236e2f04181SAndrew T. Barker 237e2f04181SAndrew T. Barker @return An error code: 0 - success, otherwise - failure 238e2f04181SAndrew T. Barker 239e2f04181SAndrew T. Barker @ref Utility 240e2f04181SAndrew T. Barker **/ 241*2b730f8bSJeremy L Thompson int CeedOperatorGetActiveElemRestriction(CeedOperator op, CeedElemRestriction *active_rstr) { 242d1d35e2fSjeremylt *active_rstr = NULL; 2430f60e0a8SJeremy L Thompson if (op->is_composite) return CEED_ERROR_SUCCESS; 244*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < op->qf->num_input_fields; i++) { 245d1d35e2fSjeremylt if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 246d1d35e2fSjeremylt *active_rstr = op->input_fields[i]->elem_restr; 247e2f04181SAndrew T. Barker break; 248e2f04181SAndrew T. Barker } 249*2b730f8bSJeremy L Thompson } 250e2f04181SAndrew T. Barker 251d1d35e2fSjeremylt if (!*active_rstr) { 252e2f04181SAndrew T. Barker // LCOV_EXCL_START 253e2f04181SAndrew T. Barker Ceed ceed; 254*2b730f8bSJeremy L Thompson 255*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 256*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No active CeedElemRestriction found"); 257e2f04181SAndrew T. Barker // LCOV_EXCL_STOP 258e2f04181SAndrew T. Barker } 259e2f04181SAndrew T. Barker return CEED_ERROR_SUCCESS; 260e2f04181SAndrew T. Barker } 261e2f04181SAndrew T. Barker 262d8dd9a91SJeremy L Thompson /** 263d8dd9a91SJeremy L Thompson @brief Set QFunctionContext field value of the specified type. 264d8dd9a91SJeremy L Thompson For composite operators, the value is set in all 265d8dd9a91SJeremy L Thompson sub-operator QFunctionContexts that have a matching `field_name`. 266d8dd9a91SJeremy L Thompson A non-zero error code is returned for single operators 267d8dd9a91SJeremy L Thompson that do not have a matching field of the same type or composite 268d8dd9a91SJeremy L Thompson operators that do not have any field of a matching type. 269d8dd9a91SJeremy L Thompson 270d8dd9a91SJeremy L Thompson @param op CeedOperator 2713668ca4bSJeremy L Thompson @param field_label Label of field to set 272d8dd9a91SJeremy L Thompson @param field_type Type of field to set 273d8dd9a91SJeremy L Thompson @param value Value to set 274d8dd9a91SJeremy L Thompson 275d8dd9a91SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 276d8dd9a91SJeremy L Thompson 277d8dd9a91SJeremy L Thompson @ref User 278d8dd9a91SJeremy L Thompson **/ 279*2b730f8bSJeremy L Thompson static int CeedOperatorContextSetGeneric(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, void *value) { 280*2b730f8bSJeremy L Thompson if (!field_label) { 2813668ca4bSJeremy L Thompson // LCOV_EXCL_START 282*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label"); 2833668ca4bSJeremy L Thompson // LCOV_EXCL_STOP 284*2b730f8bSJeremy L Thompson } 2853668ca4bSJeremy L Thompson 2863668ca4bSJeremy L Thompson bool is_composite = false; 287*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 288d8dd9a91SJeremy L Thompson if (is_composite) { 289d8dd9a91SJeremy L Thompson CeedInt num_sub; 290d8dd9a91SJeremy L Thompson CeedOperator *sub_operators; 291d8dd9a91SJeremy L Thompson 292*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetNumSub(op, &num_sub)); 293*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetSubList(op, &sub_operators)); 294*2b730f8bSJeremy L Thompson if (num_sub != field_label->num_sub_labels) { 2953668ca4bSJeremy L Thompson // LCOV_EXCL_START 2963668ca4bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 297*2b730f8bSJeremy L Thompson "ContextLabel does not correspond to composite operator. Use CeedOperatorGetContextFieldLabel()."); 2983668ca4bSJeremy L Thompson // LCOV_EXCL_STOP 299*2b730f8bSJeremy L Thompson } 300d8dd9a91SJeremy L Thompson 301d8dd9a91SJeremy L Thompson for (CeedInt i = 0; i < num_sub; i++) { 302d8dd9a91SJeremy L Thompson // Try every sub-operator, ok if some sub-operators do not have field 3033668ca4bSJeremy L Thompson if (field_label->sub_labels[i] && sub_operators[i]->qf->ctx) { 304*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextSetGeneric(sub_operators[i]->qf->ctx, field_label->sub_labels[i], field_type, value)); 305d8dd9a91SJeremy L Thompson } 306d8dd9a91SJeremy L Thompson } 307d8dd9a91SJeremy L Thompson } else { 308*2b730f8bSJeremy L Thompson if (!op->qf->ctx) { 309d8dd9a91SJeremy L Thompson // LCOV_EXCL_START 310*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, "QFunction does not have context data"); 311d8dd9a91SJeremy L Thompson // LCOV_EXCL_STOP 312*2b730f8bSJeremy L Thompson } 313d8dd9a91SJeremy L Thompson 314*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextSetGeneric(op->qf->ctx, field_label, field_type, value)); 315d8dd9a91SJeremy L Thompson } 316d8dd9a91SJeremy L Thompson 317d8dd9a91SJeremy L Thompson return CEED_ERROR_SUCCESS; 318d8dd9a91SJeremy L Thompson } 319d8dd9a91SJeremy L Thompson 3207a982d89SJeremy L. Thompson /// @} 3217a982d89SJeremy L. Thompson 3227a982d89SJeremy L. Thompson /// ---------------------------------------------------------------------------- 3237a982d89SJeremy L. Thompson /// CeedOperator Backend API 3247a982d89SJeremy L. Thompson /// ---------------------------------------------------------------------------- 3257a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend 3267a982d89SJeremy L. Thompson /// @{ 3277a982d89SJeremy L. Thompson 3287a982d89SJeremy L. Thompson /** 3297a982d89SJeremy L. Thompson @brief Get the number of arguments associated with a CeedOperator 3307a982d89SJeremy L. Thompson 3317a982d89SJeremy L. Thompson @param op CeedOperator 332d1d35e2fSjeremylt @param[out] num_args Variable to store vector number of arguments 3337a982d89SJeremy L. Thompson 3347a982d89SJeremy L. Thompson @return An error code: 0 - success, otherwise - failure 3357a982d89SJeremy L. Thompson 3367a982d89SJeremy L. Thompson @ref Backend 3377a982d89SJeremy L. Thompson **/ 3387a982d89SJeremy L. Thompson 339d1d35e2fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) { 340*2b730f8bSJeremy L Thompson if (op->is_composite) { 3417a982d89SJeremy L. Thompson // LCOV_EXCL_START 342*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operators"); 3437a982d89SJeremy L. Thompson // LCOV_EXCL_STOP 344*2b730f8bSJeremy L Thompson } 345d1d35e2fSjeremylt *num_args = op->num_fields; 346e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 3477a982d89SJeremy L. Thompson } 3487a982d89SJeremy L. Thompson 3497a982d89SJeremy L. Thompson /** 3507a982d89SJeremy L. Thompson @brief Get the setup status of a CeedOperator 3517a982d89SJeremy L. Thompson 3527a982d89SJeremy L. Thompson @param op CeedOperator 353d1d35e2fSjeremylt @param[out] is_setup_done Variable to store setup status 3547a982d89SJeremy L. Thompson 3557a982d89SJeremy L. Thompson @return An error code: 0 - success, otherwise - failure 3567a982d89SJeremy L. Thompson 3577a982d89SJeremy L. Thompson @ref Backend 3587a982d89SJeremy L. Thompson **/ 3597a982d89SJeremy L. Thompson 360d1d35e2fSjeremylt int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) { 361f04ea552SJeremy L Thompson *is_setup_done = op->is_backend_setup; 362e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 3637a982d89SJeremy L. Thompson } 3647a982d89SJeremy L. Thompson 3657a982d89SJeremy L. Thompson /** 3667a982d89SJeremy L. Thompson @brief Get the QFunction associated with a CeedOperator 3677a982d89SJeremy L. Thompson 3687a982d89SJeremy L. Thompson @param op CeedOperator 3697a982d89SJeremy L. Thompson @param[out] qf Variable to store QFunction 3707a982d89SJeremy L. Thompson 3717a982d89SJeremy L. Thompson @return An error code: 0 - success, otherwise - failure 3727a982d89SJeremy L. Thompson 3737a982d89SJeremy L. Thompson @ref Backend 3747a982d89SJeremy L. Thompson **/ 3757a982d89SJeremy L. Thompson 3767a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 377*2b730f8bSJeremy L Thompson if (op->is_composite) { 3787a982d89SJeremy L. Thompson // LCOV_EXCL_START 379*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 3807a982d89SJeremy L. Thompson // LCOV_EXCL_STOP 381*2b730f8bSJeremy L Thompson } 3827a982d89SJeremy L. Thompson *qf = op->qf; 383e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 3847a982d89SJeremy L. Thompson } 3857a982d89SJeremy L. Thompson 3867a982d89SJeremy L. Thompson /** 387c04a41a7SJeremy L Thompson @brief Get a boolean value indicating if the CeedOperator is composite 388c04a41a7SJeremy L Thompson 389c04a41a7SJeremy L Thompson @param op CeedOperator 390d1d35e2fSjeremylt @param[out] is_composite Variable to store composite status 391c04a41a7SJeremy L Thompson 392c04a41a7SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 393c04a41a7SJeremy L Thompson 394c04a41a7SJeremy L Thompson @ref Backend 395c04a41a7SJeremy L Thompson **/ 396c04a41a7SJeremy L Thompson 397d1d35e2fSjeremylt int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) { 398f04ea552SJeremy L Thompson *is_composite = op->is_composite; 399e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 400c04a41a7SJeremy L Thompson } 401c04a41a7SJeremy L Thompson 402c04a41a7SJeremy L Thompson /** 403d1d35e2fSjeremylt @brief Get the number of sub_operators associated with a CeedOperator 4047a982d89SJeremy L. Thompson 4057a982d89SJeremy L. Thompson @param op CeedOperator 406d1d35e2fSjeremylt @param[out] num_suboperators Variable to store number of sub_operators 4077a982d89SJeremy L. Thompson 4087a982d89SJeremy L. Thompson @return An error code: 0 - success, otherwise - failure 4097a982d89SJeremy L. Thompson 4107a982d89SJeremy L. Thompson @ref Backend 4117a982d89SJeremy L. Thompson **/ 4127a982d89SJeremy L. Thompson 413d1d35e2fSjeremylt int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) { 414*2b730f8bSJeremy L Thompson if (!op->is_composite) { 4157a982d89SJeremy L. Thompson // LCOV_EXCL_START 416e15f9bd0SJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 4177a982d89SJeremy L. Thompson // LCOV_EXCL_STOP 418*2b730f8bSJeremy L Thompson } 419d1d35e2fSjeremylt *num_suboperators = op->num_suboperators; 420e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 4217a982d89SJeremy L. Thompson } 4227a982d89SJeremy L. Thompson 4237a982d89SJeremy L. Thompson /** 424d1d35e2fSjeremylt @brief Get the list of sub_operators associated with a CeedOperator 4257a982d89SJeremy L. Thompson 4267a982d89SJeremy L. Thompson @param op CeedOperator 427d1d35e2fSjeremylt @param[out] sub_operators Variable to store list of sub_operators 4287a982d89SJeremy L. Thompson 4297a982d89SJeremy L. Thompson @return An error code: 0 - success, otherwise - failure 4307a982d89SJeremy L. Thompson 4317a982d89SJeremy L. Thompson @ref Backend 4327a982d89SJeremy L. Thompson **/ 4337a982d89SJeremy L. Thompson 434d1d35e2fSjeremylt int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) { 435*2b730f8bSJeremy L Thompson if (!op->is_composite) { 4367a982d89SJeremy L. Thompson // LCOV_EXCL_START 437e15f9bd0SJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 4387a982d89SJeremy L. Thompson // LCOV_EXCL_STOP 439*2b730f8bSJeremy L Thompson } 440d1d35e2fSjeremylt *sub_operators = op->sub_operators; 441e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 4427a982d89SJeremy L. Thompson } 4437a982d89SJeremy L. Thompson 4447a982d89SJeremy L. Thompson /** 4457a982d89SJeremy L. Thompson @brief Get the backend data of a CeedOperator 4467a982d89SJeremy L. Thompson 4477a982d89SJeremy L. Thompson @param op CeedOperator 4487a982d89SJeremy L. Thompson @param[out] data Variable to store data 4497a982d89SJeremy L. Thompson 4507a982d89SJeremy L. Thompson @return An error code: 0 - success, otherwise - failure 4517a982d89SJeremy L. Thompson 4527a982d89SJeremy L. Thompson @ref Backend 4537a982d89SJeremy L. Thompson **/ 4547a982d89SJeremy L. Thompson 455777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) { 456777ff853SJeremy L Thompson *(void **)data = op->data; 457e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 4587a982d89SJeremy L. Thompson } 4597a982d89SJeremy L. Thompson 4607a982d89SJeremy L. Thompson /** 4617a982d89SJeremy L. Thompson @brief Set the backend data of a CeedOperator 4627a982d89SJeremy L. Thompson 4637a982d89SJeremy L. Thompson @param[out] op CeedOperator 4647a982d89SJeremy L. Thompson @param data Data to set 4657a982d89SJeremy L. Thompson 4667a982d89SJeremy L. Thompson @return An error code: 0 - success, otherwise - failure 4677a982d89SJeremy L. Thompson 4687a982d89SJeremy L. Thompson @ref Backend 4697a982d89SJeremy L. Thompson **/ 4707a982d89SJeremy L. Thompson 471777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) { 472777ff853SJeremy L Thompson op->data = data; 473e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 4747a982d89SJeremy L. Thompson } 4757a982d89SJeremy L. Thompson 4767a982d89SJeremy L. Thompson /** 47734359f16Sjeremylt @brief Increment the reference counter for a CeedOperator 47834359f16Sjeremylt 47934359f16Sjeremylt @param op CeedOperator to increment the reference counter 48034359f16Sjeremylt 48134359f16Sjeremylt @return An error code: 0 - success, otherwise - failure 48234359f16Sjeremylt 48334359f16Sjeremylt @ref Backend 48434359f16Sjeremylt **/ 4859560d06aSjeremylt int CeedOperatorReference(CeedOperator op) { 48634359f16Sjeremylt op->ref_count++; 48734359f16Sjeremylt return CEED_ERROR_SUCCESS; 48834359f16Sjeremylt } 48934359f16Sjeremylt 49034359f16Sjeremylt /** 4917a982d89SJeremy L. Thompson @brief Set the setup flag of a CeedOperator to True 4927a982d89SJeremy L. Thompson 4937a982d89SJeremy L. Thompson @param op CeedOperator 4947a982d89SJeremy L. Thompson 4957a982d89SJeremy L. Thompson @return An error code: 0 - success, otherwise - failure 4967a982d89SJeremy L. Thompson 4977a982d89SJeremy L. Thompson @ref Backend 4987a982d89SJeremy L. Thompson **/ 4997a982d89SJeremy L. Thompson 5007a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) { 501f04ea552SJeremy L Thompson op->is_backend_setup = true; 502e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 5037a982d89SJeremy L. Thompson } 5047a982d89SJeremy L. Thompson 5057a982d89SJeremy L. Thompson /// @} 5067a982d89SJeremy L. Thompson 5077a982d89SJeremy L. Thompson /// ---------------------------------------------------------------------------- 5087a982d89SJeremy L. Thompson /// CeedOperator Public API 5097a982d89SJeremy L. Thompson /// ---------------------------------------------------------------------------- 5107a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser 511dfdf5a53Sjeremylt /// @{ 512d7b241e6Sjeremylt 513d7b241e6Sjeremylt /** 5140219ea01SJeremy L Thompson @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 5150219ea01SJeremy L Thompson CeedElemRestriction can be associated with CeedQFunction fields with 5160219ea01SJeremy L Thompson \ref CeedOperatorSetField. 517d7b241e6Sjeremylt 518b11c1e72Sjeremylt @param ceed A Ceed object where the CeedOperator will be created 519d7b241e6Sjeremylt @param qf QFunction defining the action of the operator at quadrature points 52034138859Sjeremylt @param dqf QFunction defining the action of the Jacobian of @a qf (or 5214cc79fe7SJed Brown @ref CEED_QFUNCTION_NONE) 522d7b241e6Sjeremylt @param dqfT QFunction defining the action of the transpose of the Jacobian 5234cc79fe7SJed Brown of @a qf (or @ref CEED_QFUNCTION_NONE) 524b11c1e72Sjeremylt @param[out] op Address of the variable where the newly created 525b11c1e72Sjeremylt CeedOperator will be stored 526b11c1e72Sjeremylt 527b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 528dfdf5a53Sjeremylt 5297a982d89SJeremy L. Thompson @ref User 530d7b241e6Sjeremylt */ 531*2b730f8bSJeremy L Thompson int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, CeedQFunction dqfT, CeedOperator *op) { 5325fe0d4faSjeremylt if (!ceed->OperatorCreate) { 5335fe0d4faSjeremylt Ceed delegate; 534*2b730f8bSJeremy L Thompson CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator")); 5355fe0d4faSjeremylt 536*2b730f8bSJeremy L Thompson if (!delegate) { 537c042f62fSJeremy L Thompson // LCOV_EXCL_START 538*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support OperatorCreate"); 539c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 540*2b730f8bSJeremy L Thompson } 5415fe0d4faSjeremylt 542*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCreate(delegate, qf, dqf, dqfT, op)); 543e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 5445fe0d4faSjeremylt } 5455fe0d4faSjeremylt 546*2b730f8bSJeremy L Thompson if (!qf || qf == CEED_QFUNCTION_NONE) { 547b3b7035fSJeremy L Thompson // LCOV_EXCL_START 548*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_MINOR, "Operator must have a valid QFunction."); 549b3b7035fSJeremy L Thompson // LCOV_EXCL_STOP 550*2b730f8bSJeremy L Thompson } 551*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, op)); 552d7b241e6Sjeremylt (*op)->ceed = ceed; 553*2b730f8bSJeremy L Thompson CeedCall(CeedReference(ceed)); 554d1d35e2fSjeremylt (*op)->ref_count = 1; 555d7b241e6Sjeremylt (*op)->qf = qf; 5562b104005SJeremy L Thompson (*op)->input_size = -1; 5572b104005SJeremy L Thompson (*op)->output_size = -1; 558*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionReference(qf)); 559442e7f0bSjeremylt if (dqf && dqf != CEED_QFUNCTION_NONE) { 560d7b241e6Sjeremylt (*op)->dqf = dqf; 561*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionReference(dqf)); 562442e7f0bSjeremylt } 563442e7f0bSjeremylt if (dqfT && dqfT != CEED_QFUNCTION_NONE) { 564d7b241e6Sjeremylt (*op)->dqfT = dqfT; 565*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionReference(dqfT)); 566442e7f0bSjeremylt } 567*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled)); 568*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields)); 569*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields)); 570*2b730f8bSJeremy L Thompson CeedCall(ceed->OperatorCreate(*op)); 571e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 572d7b241e6Sjeremylt } 573d7b241e6Sjeremylt 574d7b241e6Sjeremylt /** 57552d6035fSJeremy L Thompson @brief Create an operator that composes the action of several operators 57652d6035fSJeremy L Thompson 57752d6035fSJeremy L Thompson @param ceed A Ceed object where the CeedOperator will be created 57852d6035fSJeremy L Thompson @param[out] op Address of the variable where the newly created 57952d6035fSJeremy L Thompson Composite CeedOperator will be stored 58052d6035fSJeremy L Thompson 58152d6035fSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 58252d6035fSJeremy L Thompson 5837a982d89SJeremy L. Thompson @ref User 58452d6035fSJeremy L Thompson */ 58552d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 58652d6035fSJeremy L Thompson if (!ceed->CompositeOperatorCreate) { 58752d6035fSJeremy L Thompson Ceed delegate; 588*2b730f8bSJeremy L Thompson CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator")); 58952d6035fSJeremy L Thompson 590250756a7Sjeremylt if (delegate) { 591*2b730f8bSJeremy L Thompson CeedCall(CeedCompositeOperatorCreate(delegate, op)); 592e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 59352d6035fSJeremy L Thompson } 594250756a7Sjeremylt } 59552d6035fSJeremy L Thompson 596*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, op)); 59752d6035fSJeremy L Thompson (*op)->ceed = ceed; 598*2b730f8bSJeremy L Thompson CeedCall(CeedReference(ceed)); 599996d9ab5SJed Brown (*op)->ref_count = 1; 600f04ea552SJeremy L Thompson (*op)->is_composite = true; 601*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators)); 6022b104005SJeremy L Thompson (*op)->input_size = -1; 6032b104005SJeremy L Thompson (*op)->output_size = -1; 604250756a7Sjeremylt 605250756a7Sjeremylt if (ceed->CompositeOperatorCreate) { 606*2b730f8bSJeremy L Thompson CeedCall(ceed->CompositeOperatorCreate(*op)); 607250756a7Sjeremylt } 608e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 60952d6035fSJeremy L Thompson } 61052d6035fSJeremy L Thompson 61152d6035fSJeremy L Thompson /** 6129560d06aSjeremylt @brief Copy the pointer to a CeedOperator. Both pointers should 6139560d06aSjeremylt be destroyed with `CeedOperatorDestroy()`; 6149560d06aSjeremylt Note: If `*op_copy` is non-NULL, then it is assumed that 6159560d06aSjeremylt `*op_copy` is a pointer to a CeedOperator. This 6169560d06aSjeremylt CeedOperator will be destroyed if `*op_copy` is the only 6179560d06aSjeremylt reference to this CeedOperator. 6189560d06aSjeremylt 6199560d06aSjeremylt @param op CeedOperator to copy reference to 6209560d06aSjeremylt @param[out] op_copy Variable to store copied reference 6219560d06aSjeremylt 6229560d06aSjeremylt @return An error code: 0 - success, otherwise - failure 6239560d06aSjeremylt 6249560d06aSjeremylt @ref User 6259560d06aSjeremylt **/ 6269560d06aSjeremylt int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) { 627*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorReference(op)); 628*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorDestroy(op_copy)); 6299560d06aSjeremylt *op_copy = op; 6309560d06aSjeremylt return CEED_ERROR_SUCCESS; 6319560d06aSjeremylt } 6329560d06aSjeremylt 6339560d06aSjeremylt /** 634b11c1e72Sjeremylt @brief Provide a field to a CeedOperator for use by its CeedQFunction 635d7b241e6Sjeremylt 636d7b241e6Sjeremylt This function is used to specify both active and passive fields to a 637d7b241e6Sjeremylt CeedOperator. For passive fields, a vector @arg v must be provided. Passive 638d7b241e6Sjeremylt fields can inputs or outputs (updated in-place when operator is applied). 639d7b241e6Sjeremylt 640d7b241e6Sjeremylt Active fields must be specified using this function, but their data (in a 641d7b241e6Sjeremylt CeedVector) is passed in CeedOperatorApply(). There can be at most one active 642979e564eSJames Wright input CeedVector and at most one active output CeedVector passed to 643979e564eSJames Wright CeedOperatorApply(). 644d7b241e6Sjeremylt 6458c91a0c9SJeremy L Thompson @param op CeedOperator on which to provide the field 646d1d35e2fSjeremylt @param field_name Name of the field (to be matched with the name used by 6478795c945Sjeremylt CeedQFunction) 648b11c1e72Sjeremylt @param r CeedElemRestriction 6494cc79fe7SJed Brown @param b CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED 650b11c1e72Sjeremylt if collocated with quadrature points 6514cc79fe7SJed Brown @param v CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE 6524cc79fe7SJed Brown if field is active or @ref CEED_VECTOR_NONE if using 6534cc79fe7SJed Brown @ref CEED_EVAL_WEIGHT in the QFunction 654b11c1e72Sjeremylt 655b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 656dfdf5a53Sjeremylt 6577a982d89SJeremy L. Thompson @ref User 658b11c1e72Sjeremylt **/ 659*2b730f8bSJeremy L Thompson int CeedOperatorSetField(CeedOperator op, const char *field_name, CeedElemRestriction r, CeedBasis b, CeedVector v) { 660*2b730f8bSJeremy L Thompson if (op->is_composite) { 661c042f62fSJeremy L Thompson // LCOV_EXCL_START 662*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Cannot add field to composite operator."); 663c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 664*2b730f8bSJeremy L Thompson } 665*2b730f8bSJeremy L Thompson if (op->is_immutable) { 666f04ea552SJeremy L Thompson // LCOV_EXCL_START 667*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 668f04ea552SJeremy L Thompson // LCOV_EXCL_STOP 669*2b730f8bSJeremy L Thompson } 670*2b730f8bSJeremy L Thompson if (!r) { 671c042f62fSJeremy L Thompson // LCOV_EXCL_START 672*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "ElemRestriction r for field \"%s\" must be non-NULL.", field_name); 673c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 674*2b730f8bSJeremy L Thompson } 675*2b730f8bSJeremy L Thompson if (!b) { 676c042f62fSJeremy L Thompson // LCOV_EXCL_START 677*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Basis b for field \"%s\" must be non-NULL.", field_name); 678c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 679*2b730f8bSJeremy L Thompson } 680*2b730f8bSJeremy L Thompson if (!v) { 681c042f62fSJeremy L Thompson // LCOV_EXCL_START 682*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Vector v for field \"%s\" must be non-NULL.", field_name); 683c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 684*2b730f8bSJeremy L Thompson } 68552d6035fSJeremy L Thompson 686d1d35e2fSjeremylt CeedInt num_elem; 687*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetNumElements(r, &num_elem)); 688*2b730f8bSJeremy L Thompson if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction && op->num_elem != num_elem) { 689c042f62fSJeremy L Thompson // LCOV_EXCL_START 690e15f9bd0SJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, 691*2b730f8bSJeremy L Thompson "ElemRestriction with %" CeedInt_FMT " elements incompatible with prior %" CeedInt_FMT " elements", num_elem, op->num_elem); 692c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 693*2b730f8bSJeremy L Thompson } 694d7b241e6Sjeremylt 69578464608Sjeremylt CeedInt num_qpts = 0; 696e15f9bd0SJeremy L Thompson if (b != CEED_BASIS_COLLOCATED) { 697*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetNumQuadraturePoints(b, &num_qpts)); 698*2b730f8bSJeremy L Thompson if (op->num_qpts && op->num_qpts != num_qpts) { 699c042f62fSJeremy L Thompson // LCOV_EXCL_START 700e15f9bd0SJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_DIMENSION, 701*2b730f8bSJeremy L Thompson "Basis with %" CeedInt_FMT " quadrature points incompatible with prior %" CeedInt_FMT " points", num_qpts, op->num_qpts); 702c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 703d7b241e6Sjeremylt } 704*2b730f8bSJeremy L Thompson } 705d1d35e2fSjeremylt CeedQFunctionField qf_field; 706d1d35e2fSjeremylt CeedOperatorField *op_field; 7072b104005SJeremy L Thompson bool is_input = true; 708d1d35e2fSjeremylt for (CeedInt i = 0; i < op->qf->num_input_fields; i++) { 709d1d35e2fSjeremylt if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) { 710d1d35e2fSjeremylt qf_field = op->qf->input_fields[i]; 711d1d35e2fSjeremylt op_field = &op->input_fields[i]; 712d7b241e6Sjeremylt goto found; 713d7b241e6Sjeremylt } 714d7b241e6Sjeremylt } 7152b104005SJeremy L Thompson is_input = false; 716d1d35e2fSjeremylt for (CeedInt i = 0; i < op->qf->num_output_fields; i++) { 717d1d35e2fSjeremylt if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) { 718d1d35e2fSjeremylt qf_field = op->qf->output_fields[i]; 719d1d35e2fSjeremylt op_field = &op->output_fields[i]; 720d7b241e6Sjeremylt goto found; 721d7b241e6Sjeremylt } 722d7b241e6Sjeremylt } 723c042f62fSJeremy L Thompson // LCOV_EXCL_START 724*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, "QFunction has no knowledge of field '%s'", field_name); 725c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 726d7b241e6Sjeremylt found: 727*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckField(op->ceed, qf_field, r, b)); 728*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, op_field)); 729e15f9bd0SJeremy L Thompson 7302b104005SJeremy L Thompson if (v == CEED_VECTOR_ACTIVE) { 7312b104005SJeremy L Thompson CeedSize l_size; 732*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetLVectorSize(r, &l_size)); 7332b104005SJeremy L Thompson if (is_input) { 7342b104005SJeremy L Thompson if (op->input_size == -1) op->input_size = l_size; 735*2b730f8bSJeremy L Thompson if (l_size != op->input_size) { 7362b104005SJeremy L Thompson // LCOV_EXCL_START 737*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "LVector size %td does not match previous size %td", l_size, op->input_size); 7382b104005SJeremy L Thompson // LCOV_EXCL_STOP 739*2b730f8bSJeremy L Thompson } 7402b104005SJeremy L Thompson } else { 7412b104005SJeremy L Thompson if (op->output_size == -1) op->output_size = l_size; 742*2b730f8bSJeremy L Thompson if (l_size != op->output_size) { 7432b104005SJeremy L Thompson // LCOV_EXCL_START 744*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "LVector size %td does not match previous size %td", l_size, op->output_size); 7452b104005SJeremy L Thompson // LCOV_EXCL_STOP 7462b104005SJeremy L Thompson } 7472b104005SJeremy L Thompson } 748*2b730f8bSJeremy L Thompson } 7492b104005SJeremy L Thompson 750d1d35e2fSjeremylt (*op_field)->vec = v; 751e15f9bd0SJeremy L Thompson if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) { 752*2b730f8bSJeremy L Thompson CeedCall(CeedVectorReference(v)); 753e15f9bd0SJeremy L Thompson } 754e15f9bd0SJeremy L Thompson 755d1d35e2fSjeremylt (*op_field)->elem_restr = r; 756*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionReference(r)); 757e15f9bd0SJeremy L Thompson if (r != CEED_ELEMRESTRICTION_NONE) { 758d1d35e2fSjeremylt op->num_elem = num_elem; 759d1d35e2fSjeremylt op->has_restriction = true; // Restriction set, but num_elem may be 0 760e15f9bd0SJeremy L Thompson } 761d99fa3c5SJeremy L Thompson 762d1d35e2fSjeremylt (*op_field)->basis = b; 763e15f9bd0SJeremy L Thompson if (b != CEED_BASIS_COLLOCATED) { 764cd4dfc48Sjeremylt if (!op->num_qpts) { 765*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetNumQuadraturePoints(op, num_qpts)); 766cd4dfc48Sjeremylt } 767*2b730f8bSJeremy L Thompson CeedCall(CeedBasisReference(b)); 768e15f9bd0SJeremy L Thompson } 769e15f9bd0SJeremy L Thompson 770d1d35e2fSjeremylt op->num_fields += 1; 771*2b730f8bSJeremy L Thompson CeedCall(CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name)); 772e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 773d7b241e6Sjeremylt } 774d7b241e6Sjeremylt 775d7b241e6Sjeremylt /** 77643bbe138SJeremy L Thompson @brief Get the CeedOperatorFields of a CeedOperator 77743bbe138SJeremy L Thompson 778f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 779f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 780f04ea552SJeremy L Thompson 78143bbe138SJeremy L Thompson @param op CeedOperator 782f74ec584SJeremy L Thompson @param[out] num_input_fields Variable to store number of input fields 78343bbe138SJeremy L Thompson @param[out] input_fields Variable to store input_fields 784f74ec584SJeremy L Thompson @param[out] num_output_fields Variable to store number of output fields 78543bbe138SJeremy L Thompson @param[out] output_fields Variable to store output_fields 78643bbe138SJeremy L Thompson 78743bbe138SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 78843bbe138SJeremy L Thompson 789e9b533fbSJeremy L Thompson @ref Advanced 79043bbe138SJeremy L Thompson **/ 791*2b730f8bSJeremy L Thompson int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, CeedOperatorField **input_fields, CeedInt *num_output_fields, 79243bbe138SJeremy L Thompson CeedOperatorField **output_fields) { 793*2b730f8bSJeremy L Thompson if (op->is_composite) { 79443bbe138SJeremy L Thompson // LCOV_EXCL_START 795*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 79643bbe138SJeremy L Thompson // LCOV_EXCL_STOP 797*2b730f8bSJeremy L Thompson } 798*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 79943bbe138SJeremy L Thompson 80043bbe138SJeremy L Thompson if (num_input_fields) *num_input_fields = op->qf->num_input_fields; 80143bbe138SJeremy L Thompson if (input_fields) *input_fields = op->input_fields; 80243bbe138SJeremy L Thompson if (num_output_fields) *num_output_fields = op->qf->num_output_fields; 80343bbe138SJeremy L Thompson if (output_fields) *output_fields = op->output_fields; 80443bbe138SJeremy L Thompson return CEED_ERROR_SUCCESS; 80543bbe138SJeremy L Thompson } 80643bbe138SJeremy L Thompson 80743bbe138SJeremy L Thompson /** 80828567f8fSJeremy L Thompson @brief Get the name of a CeedOperatorField 80928567f8fSJeremy L Thompson 81028567f8fSJeremy L Thompson @param op_field CeedOperatorField 81128567f8fSJeremy L Thompson @param[out] field_name Variable to store the field name 81228567f8fSJeremy L Thompson 81328567f8fSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 81428567f8fSJeremy L Thompson 815e9b533fbSJeremy L Thompson @ref Advanced 81628567f8fSJeremy L Thompson **/ 81728567f8fSJeremy L Thompson int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) { 81828567f8fSJeremy L Thompson *field_name = (char *)op_field->field_name; 81928567f8fSJeremy L Thompson return CEED_ERROR_SUCCESS; 82028567f8fSJeremy L Thompson } 82128567f8fSJeremy L Thompson 82228567f8fSJeremy L Thompson /** 82343bbe138SJeremy L Thompson @brief Get the CeedElemRestriction of a CeedOperatorField 82443bbe138SJeremy L Thompson 82543bbe138SJeremy L Thompson @param op_field CeedOperatorField 82643bbe138SJeremy L Thompson @param[out] rstr Variable to store CeedElemRestriction 82743bbe138SJeremy L Thompson 82843bbe138SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 82943bbe138SJeremy L Thompson 830e9b533fbSJeremy L Thompson @ref Advanced 83143bbe138SJeremy L Thompson **/ 832*2b730f8bSJeremy L Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, CeedElemRestriction *rstr) { 83343bbe138SJeremy L Thompson *rstr = op_field->elem_restr; 83443bbe138SJeremy L Thompson return CEED_ERROR_SUCCESS; 83543bbe138SJeremy L Thompson } 83643bbe138SJeremy L Thompson 83743bbe138SJeremy L Thompson /** 83843bbe138SJeremy L Thompson @brief Get the CeedBasis of a CeedOperatorField 83943bbe138SJeremy L Thompson 84043bbe138SJeremy L Thompson @param op_field CeedOperatorField 84143bbe138SJeremy L Thompson @param[out] basis Variable to store CeedBasis 84243bbe138SJeremy L Thompson 84343bbe138SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 84443bbe138SJeremy L Thompson 845e9b533fbSJeremy L Thompson @ref Advanced 84643bbe138SJeremy L Thompson **/ 84743bbe138SJeremy L Thompson int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 84843bbe138SJeremy L Thompson *basis = op_field->basis; 84943bbe138SJeremy L Thompson return CEED_ERROR_SUCCESS; 85043bbe138SJeremy L Thompson } 85143bbe138SJeremy L Thompson 85243bbe138SJeremy L Thompson /** 85343bbe138SJeremy L Thompson @brief Get the CeedVector of a CeedOperatorField 85443bbe138SJeremy L Thompson 85543bbe138SJeremy L Thompson @param op_field CeedOperatorField 85643bbe138SJeremy L Thompson @param[out] vec Variable to store CeedVector 85743bbe138SJeremy L Thompson 85843bbe138SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 85943bbe138SJeremy L Thompson 860e9b533fbSJeremy L Thompson @ref Advanced 86143bbe138SJeremy L Thompson **/ 86243bbe138SJeremy L Thompson int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 86343bbe138SJeremy L Thompson *vec = op_field->vec; 86443bbe138SJeremy L Thompson return CEED_ERROR_SUCCESS; 86543bbe138SJeremy L Thompson } 86643bbe138SJeremy L Thompson 86743bbe138SJeremy L Thompson /** 86852d6035fSJeremy L Thompson @brief Add a sub-operator to a composite CeedOperator 869288c0443SJeremy L Thompson 870d1d35e2fSjeremylt @param[out] composite_op Composite CeedOperator 871d1d35e2fSjeremylt @param sub_op Sub-operator CeedOperator 87252d6035fSJeremy L Thompson 87352d6035fSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 87452d6035fSJeremy L Thompson 8757a982d89SJeremy L. Thompson @ref User 87652d6035fSJeremy L Thompson */ 877*2b730f8bSJeremy L Thompson int CeedCompositeOperatorAddSub(CeedOperator composite_op, CeedOperator sub_op) { 878*2b730f8bSJeremy L Thompson if (!composite_op->is_composite) { 879c042f62fSJeremy L Thompson // LCOV_EXCL_START 880*2b730f8bSJeremy L Thompson return CeedError(composite_op->ceed, CEED_ERROR_MINOR, "CeedOperator is not a composite operator"); 8812b104005SJeremy L Thompson // LCOV_EXCL_STOP 8822b104005SJeremy L Thompson } 8832b104005SJeremy L Thompson 884*2b730f8bSJeremy L Thompson if (composite_op->num_suboperators == CEED_COMPOSITE_MAX) { 885*2b730f8bSJeremy L Thompson // LCOV_EXCL_START 886*2b730f8bSJeremy L Thompson return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED, "Cannot add additional sub-operators"); 887*2b730f8bSJeremy L Thompson // LCOV_EXCL_STOP 888*2b730f8bSJeremy L Thompson } 889*2b730f8bSJeremy L Thompson if (composite_op->is_immutable) { 890*2b730f8bSJeremy L Thompson // LCOV_EXCL_START 891*2b730f8bSJeremy L Thompson return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 892*2b730f8bSJeremy L Thompson // LCOV_EXCL_STOP 893*2b730f8bSJeremy L Thompson } 894*2b730f8bSJeremy L Thompson 895*2b730f8bSJeremy L Thompson { 896*2b730f8bSJeremy L Thompson CeedSize input_size, output_size; 897*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size)); 898*2b730f8bSJeremy L Thompson if (composite_op->input_size == -1) composite_op->input_size = input_size; 899*2b730f8bSJeremy L Thompson if (composite_op->output_size == -1) composite_op->output_size = output_size; 900*2b730f8bSJeremy L Thompson // Note, a size of -1 means no active vector restriction set, so no incompatibility 901*2b730f8bSJeremy L Thompson if ((input_size != -1 && input_size != composite_op->input_size) || (output_size != -1 && output_size != composite_op->output_size)) { 902*2b730f8bSJeremy L Thompson // LCOV_EXCL_START 903*2b730f8bSJeremy L Thompson return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, 904*2b730f8bSJeremy L Thompson "Sub-operators must have compatible dimensions; composite operator of shape (%td, %td) not compatible with sub-operator of " 905*2b730f8bSJeremy L Thompson "shape (%td, %td)", 906*2b730f8bSJeremy L Thompson composite_op->input_size, composite_op->output_size, input_size, output_size); 907*2b730f8bSJeremy L Thompson // LCOV_EXCL_STOP 908*2b730f8bSJeremy L Thompson } 909*2b730f8bSJeremy L Thompson } 910*2b730f8bSJeremy L Thompson 911d1d35e2fSjeremylt composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 912*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorReference(sub_op)); 913d1d35e2fSjeremylt composite_op->num_suboperators++; 914e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 91552d6035fSJeremy L Thompson } 91652d6035fSJeremy L Thompson 91752d6035fSJeremy L Thompson /** 9184db537f9SJeremy L Thompson @brief Check if a CeedOperator is ready to be used. 9194db537f9SJeremy L Thompson 9204db537f9SJeremy L Thompson @param[in] op CeedOperator to check 9214db537f9SJeremy L Thompson 9224db537f9SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 9234db537f9SJeremy L Thompson 9244db537f9SJeremy L Thompson @ref User 9254db537f9SJeremy L Thompson **/ 9264db537f9SJeremy L Thompson int CeedOperatorCheckReady(CeedOperator op) { 9274db537f9SJeremy L Thompson Ceed ceed; 928*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetCeed(op, &ceed)); 9294db537f9SJeremy L Thompson 930*2b730f8bSJeremy L Thompson if (op->is_interface_setup) return CEED_ERROR_SUCCESS; 9314db537f9SJeremy L Thompson 9324db537f9SJeremy L Thompson CeedQFunction qf = op->qf; 9334db537f9SJeremy L Thompson if (op->is_composite) { 93443622462SJeremy L Thompson if (!op->num_suboperators) { 93543622462SJeremy L Thompson // Empty operator setup 93643622462SJeremy L Thompson op->input_size = 0; 93743622462SJeremy L Thompson op->output_size = 0; 93843622462SJeremy L Thompson } else { 9394db537f9SJeremy L Thompson for (CeedInt i = 0; i < op->num_suboperators; i++) { 940*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op->sub_operators[i])); 9414db537f9SJeremy L Thompson } 9422b104005SJeremy L Thompson // Sub-operators could be modified after adding to composite operator 9432b104005SJeremy L Thompson // Need to verify no lvec incompatibility from any changes 9442b104005SJeremy L Thompson CeedSize input_size, output_size; 945*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 94643622462SJeremy L Thompson } 9474db537f9SJeremy L Thompson } else { 948*2b730f8bSJeremy L Thompson if (op->num_fields == 0) { 9494db537f9SJeremy L Thompson // LCOV_EXCL_START 9504db537f9SJeremy L Thompson return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 9514db537f9SJeremy L Thompson // LCOV_EXCL_STOP 952*2b730f8bSJeremy L Thompson } 953*2b730f8bSJeremy L Thompson if (op->num_fields < qf->num_input_fields + qf->num_output_fields) { 9544db537f9SJeremy L Thompson // LCOV_EXCL_START 9554db537f9SJeremy L Thompson return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 9564db537f9SJeremy L Thompson // LCOV_EXCL_STOP 957*2b730f8bSJeremy L Thompson } 958*2b730f8bSJeremy L Thompson if (!op->has_restriction) { 9594db537f9SJeremy L Thompson // LCOV_EXCL_START 960*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_INCOMPLETE, "At least one restriction required"); 9614db537f9SJeremy L Thompson // LCOV_EXCL_STOP 962*2b730f8bSJeremy L Thompson } 963*2b730f8bSJeremy L Thompson if (op->num_qpts == 0) { 9644db537f9SJeremy L Thompson // LCOV_EXCL_START 965*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_INCOMPLETE, "At least one non-collocated basis is required or the number of quadrature points must be set"); 9664db537f9SJeremy L Thompson // LCOV_EXCL_STOP 9674db537f9SJeremy L Thompson } 968*2b730f8bSJeremy L Thompson } 9694db537f9SJeremy L Thompson 9704db537f9SJeremy L Thompson // Flag as immutable and ready 9714db537f9SJeremy L Thompson op->is_interface_setup = true; 972*2b730f8bSJeremy L Thompson if (op->qf && op->qf != CEED_QFUNCTION_NONE) op->qf->is_immutable = true; 973*2b730f8bSJeremy L Thompson if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) op->dqf->is_immutable = true; 974*2b730f8bSJeremy L Thompson if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) op->dqfT->is_immutable = true; 9754db537f9SJeremy L Thompson return CEED_ERROR_SUCCESS; 9764db537f9SJeremy L Thompson } 9774db537f9SJeremy L Thompson 9784db537f9SJeremy L Thompson /** 979c9366a6bSJeremy L Thompson @brief Get vector lengths for the active input and/or output vectors of a CeedOperator. 980c9366a6bSJeremy L Thompson Note: Lengths of -1 indicate that the CeedOperator does not have an 981c9366a6bSJeremy L Thompson active input and/or output. 982c9366a6bSJeremy L Thompson 983c9366a6bSJeremy L Thompson @param[in] op CeedOperator 984c9366a6bSJeremy L Thompson @param[out] input_size Variable to store active input vector length, or NULL 985c9366a6bSJeremy L Thompson @param[out] output_size Variable to store active output vector length, or NULL 986c9366a6bSJeremy L Thompson 987c9366a6bSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 988c9366a6bSJeremy L Thompson 989c9366a6bSJeremy L Thompson @ref User 990c9366a6bSJeremy L Thompson **/ 991*2b730f8bSJeremy L Thompson int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size, CeedSize *output_size) { 992c9366a6bSJeremy L Thompson bool is_composite; 993c9366a6bSJeremy L Thompson 9942b104005SJeremy L Thompson if (input_size) *input_size = op->input_size; 9952b104005SJeremy L Thompson if (output_size) *output_size = op->output_size; 996c9366a6bSJeremy L Thompson 997*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 9982b104005SJeremy L Thompson if (is_composite && (op->input_size == -1 || op->output_size == -1)) { 999c9366a6bSJeremy L Thompson for (CeedInt i = 0; i < op->num_suboperators; i++) { 1000c9366a6bSJeremy L Thompson CeedSize sub_input_size, sub_output_size; 1001*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetActiveVectorLengths(op->sub_operators[i], &sub_input_size, &sub_output_size)); 10022b104005SJeremy L Thompson if (op->input_size == -1) op->input_size = sub_input_size; 10032b104005SJeremy L Thompson if (op->output_size == -1) op->output_size = sub_output_size; 10042b104005SJeremy L Thompson // Note, a size of -1 means no active vector restriction set, so no incompatibility 1005*2b730f8bSJeremy L Thompson if ((sub_input_size != -1 && sub_input_size != op->input_size) || (sub_output_size != -1 && sub_output_size != op->output_size)) { 10062b104005SJeremy L Thompson // LCOV_EXCL_START 10072b104005SJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_MAJOR, 1008*2b730f8bSJeremy L Thompson "Sub-operators must have compatible dimensions; composite operator of shape (%td, %td) not compatible with sub-operator of " 1009*2b730f8bSJeremy L Thompson "shape (%td, %td)", 10102b104005SJeremy L Thompson op->input_size, op->output_size, input_size, output_size); 10112b104005SJeremy L Thompson // LCOV_EXCL_STOP 1012c9366a6bSJeremy L Thompson } 1013c9366a6bSJeremy L Thompson } 1014*2b730f8bSJeremy L Thompson } 1015c9366a6bSJeremy L Thompson 1016c9366a6bSJeremy L Thompson return CEED_ERROR_SUCCESS; 1017c9366a6bSJeremy L Thompson } 1018c9366a6bSJeremy L Thompson 1019c9366a6bSJeremy L Thompson /** 1020beecbf24SJeremy L Thompson @brief Set reuse of CeedQFunction data in CeedOperatorLinearAssemble* functions. 1021beecbf24SJeremy L Thompson When `reuse_assembly_data = false` (default), the CeedQFunction associated 1022beecbf24SJeremy L Thompson with this CeedOperator is re-assembled every time a `CeedOperatorLinearAssemble*` 1023beecbf24SJeremy L Thompson function is called. 1024beecbf24SJeremy L Thompson When `reuse_assembly_data = true`, the CeedQFunction associated with 1025beecbf24SJeremy L Thompson this CeedOperator is reused between calls to 1026beecbf24SJeremy L Thompson `CeedOperatorSetQFunctionAssemblyDataUpdated`. 10278b919e6bSJeremy L Thompson 1028beecbf24SJeremy L Thompson @param[in] op CeedOperator 1029beecbf24SJeremy L Thompson @param[in] reuse_assembly_data Boolean flag setting assembly data reuse 10308b919e6bSJeremy L Thompson 10318b919e6bSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 10328b919e6bSJeremy L Thompson 10338b919e6bSJeremy L Thompson @ref Advanced 10348b919e6bSJeremy L Thompson **/ 1035*2b730f8bSJeremy L Thompson int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op, bool reuse_assembly_data) { 10368b919e6bSJeremy L Thompson bool is_composite; 10378b919e6bSJeremy L Thompson 1038*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 10398b919e6bSJeremy L Thompson if (is_composite) { 10408b919e6bSJeremy L Thompson for (CeedInt i = 0; i < op->num_suboperators; i++) { 1041*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i], reuse_assembly_data)); 10428b919e6bSJeremy L Thompson } 10438b919e6bSJeremy L Thompson } else { 1044*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data)); 1045beecbf24SJeremy L Thompson } 1046beecbf24SJeremy L Thompson 1047beecbf24SJeremy L Thompson return CEED_ERROR_SUCCESS; 1048beecbf24SJeremy L Thompson } 1049beecbf24SJeremy L Thompson 1050beecbf24SJeremy L Thompson /** 1051beecbf24SJeremy L Thompson @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly. 1052beecbf24SJeremy L Thompson 1053beecbf24SJeremy L Thompson @param[in] op CeedOperator 10546e15d496SJeremy L Thompson @param[in] needs_data_update Boolean flag setting assembly data reuse 1055beecbf24SJeremy L Thompson 1056beecbf24SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1057beecbf24SJeremy L Thompson 1058beecbf24SJeremy L Thompson @ref Advanced 1059beecbf24SJeremy L Thompson **/ 1060*2b730f8bSJeremy L Thompson int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op, bool needs_data_update) { 1061beecbf24SJeremy L Thompson bool is_composite; 1062beecbf24SJeremy L Thompson 1063*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1064beecbf24SJeremy L Thompson if (is_composite) { 1065beecbf24SJeremy L Thompson for (CeedInt i = 0; i < op->num_suboperators; i++) { 1066*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op->sub_operators[i], needs_data_update)); 1067beecbf24SJeremy L Thompson } 1068beecbf24SJeremy L Thompson } else { 1069*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, needs_data_update)); 10708b919e6bSJeremy L Thompson } 10718b919e6bSJeremy L Thompson 10728b919e6bSJeremy L Thompson return CEED_ERROR_SUCCESS; 10738b919e6bSJeremy L Thompson } 10748b919e6bSJeremy L Thompson 10758b919e6bSJeremy L Thompson /** 1076cd4dfc48Sjeremylt @brief Set the number of quadrature points associated with a CeedOperator. 1077cd4dfc48Sjeremylt This should be used when creating a CeedOperator where every 1078cd4dfc48Sjeremylt field has a collocated basis. This function cannot be used for 1079cd4dfc48Sjeremylt composite CeedOperators. 1080cd4dfc48Sjeremylt 1081cd4dfc48Sjeremylt @param op CeedOperator 1082cd4dfc48Sjeremylt @param num_qpts Number of quadrature points to set 1083cd4dfc48Sjeremylt 1084cd4dfc48Sjeremylt @return An error code: 0 - success, otherwise - failure 1085cd4dfc48Sjeremylt 1086e9b533fbSJeremy L Thompson @ref Advanced 1087cd4dfc48Sjeremylt **/ 1088cd4dfc48Sjeremylt int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) { 1089*2b730f8bSJeremy L Thompson if (op->is_composite) { 1090cd4dfc48Sjeremylt // LCOV_EXCL_START 1091*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 1092cd4dfc48Sjeremylt // LCOV_EXCL_STOP 1093*2b730f8bSJeremy L Thompson } 1094*2b730f8bSJeremy L Thompson if (op->num_qpts) { 1095cd4dfc48Sjeremylt // LCOV_EXCL_START 1096*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_MINOR, "Number of quadrature points already defined"); 1097cd4dfc48Sjeremylt // LCOV_EXCL_STOP 1098*2b730f8bSJeremy L Thompson } 1099*2b730f8bSJeremy L Thompson if (op->is_immutable) { 1100f04ea552SJeremy L Thompson // LCOV_EXCL_START 1101*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 1102f04ea552SJeremy L Thompson // LCOV_EXCL_STOP 1103*2b730f8bSJeremy L Thompson } 1104cd4dfc48Sjeremylt op->num_qpts = num_qpts; 1105cd4dfc48Sjeremylt return CEED_ERROR_SUCCESS; 1106cd4dfc48Sjeremylt } 1107cd4dfc48Sjeremylt 1108cd4dfc48Sjeremylt /** 1109ea6b5821SJeremy L Thompson @brief Set name of CeedOperator for CeedOperatorView output 1110ea6b5821SJeremy L Thompson 1111ea6b5821SJeremy L Thompson @param op CeedOperator 1112ea6b5821SJeremy L Thompson @param name Name to set, or NULL to remove previously set name 1113ea6b5821SJeremy L Thompson 1114ea6b5821SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1115ea6b5821SJeremy L Thompson 1116ea6b5821SJeremy L Thompson @ref User 1117ea6b5821SJeremy L Thompson **/ 1118ea6b5821SJeremy L Thompson int CeedOperatorSetName(CeedOperator op, const char *name) { 1119ea6b5821SJeremy L Thompson char *name_copy; 1120ea6b5821SJeremy L Thompson size_t name_len = name ? strlen(name) : 0; 1121ea6b5821SJeremy L Thompson 1122*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&op->name)); 1123ea6b5821SJeremy L Thompson if (name_len > 0) { 1124*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(name_len + 1, &name_copy)); 1125ea6b5821SJeremy L Thompson memcpy(name_copy, name, name_len); 1126ea6b5821SJeremy L Thompson op->name = name_copy; 1127ea6b5821SJeremy L Thompson } 1128ea6b5821SJeremy L Thompson 1129ea6b5821SJeremy L Thompson return CEED_ERROR_SUCCESS; 1130ea6b5821SJeremy L Thompson } 1131ea6b5821SJeremy L Thompson 1132ea6b5821SJeremy L Thompson /** 11337a982d89SJeremy L. Thompson @brief View a CeedOperator 11347a982d89SJeremy L. Thompson 11357a982d89SJeremy L. Thompson @param[in] op CeedOperator to view 11367a982d89SJeremy L. Thompson @param[in] stream Stream to write; typically stdout/stderr or a file 11377a982d89SJeremy L. Thompson 11387a982d89SJeremy L. Thompson @return Error code: 0 - success, otherwise - failure 11397a982d89SJeremy L. Thompson 11407a982d89SJeremy L. Thompson @ref User 11417a982d89SJeremy L. Thompson **/ 11427a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) { 1143ea6b5821SJeremy L Thompson bool has_name = op->name; 11447a982d89SJeremy L. Thompson 1145f04ea552SJeremy L Thompson if (op->is_composite) { 1146*2b730f8bSJeremy L Thompson fprintf(stream, "Composite CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : ""); 11477a982d89SJeremy L. Thompson 1148d1d35e2fSjeremylt for (CeedInt i = 0; i < op->num_suboperators; i++) { 1149ea6b5821SJeremy L Thompson has_name = op->sub_operators[i]->name; 1150*2b730f8bSJeremy L Thompson fprintf(stream, " SubOperator %" CeedInt_FMT "%s%s:\n", i, has_name ? " - " : "", has_name ? op->sub_operators[i]->name : ""); 1151*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSingleView(op->sub_operators[i], 1, stream)); 11527a982d89SJeremy L. Thompson } 11537a982d89SJeremy L. Thompson } else { 1154*2b730f8bSJeremy L Thompson fprintf(stream, "CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : ""); 1155*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorSingleView(op, 0, stream)); 11567a982d89SJeremy L. Thompson } 1157e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 11587a982d89SJeremy L. Thompson } 11593bd813ffSjeremylt 11603bd813ffSjeremylt /** 1161b7c9bbdaSJeremy L Thompson @brief Get the Ceed associated with a CeedOperator 1162b7c9bbdaSJeremy L Thompson 1163b7c9bbdaSJeremy L Thompson @param op CeedOperator 1164b7c9bbdaSJeremy L Thompson @param[out] ceed Variable to store Ceed 1165b7c9bbdaSJeremy L Thompson 1166b7c9bbdaSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1167b7c9bbdaSJeremy L Thompson 1168b7c9bbdaSJeremy L Thompson @ref Advanced 1169b7c9bbdaSJeremy L Thompson **/ 1170b7c9bbdaSJeremy L Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1171b7c9bbdaSJeremy L Thompson *ceed = op->ceed; 1172b7c9bbdaSJeremy L Thompson return CEED_ERROR_SUCCESS; 1173b7c9bbdaSJeremy L Thompson } 1174b7c9bbdaSJeremy L Thompson 1175b7c9bbdaSJeremy L Thompson /** 1176b7c9bbdaSJeremy L Thompson @brief Get the number of elements associated with a CeedOperator 1177b7c9bbdaSJeremy L Thompson 1178b7c9bbdaSJeremy L Thompson @param op CeedOperator 1179b7c9bbdaSJeremy L Thompson @param[out] num_elem Variable to store number of elements 1180b7c9bbdaSJeremy L Thompson 1181b7c9bbdaSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1182b7c9bbdaSJeremy L Thompson 1183b7c9bbdaSJeremy L Thompson @ref Advanced 1184b7c9bbdaSJeremy L Thompson **/ 1185b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1186*2b730f8bSJeremy L Thompson if (op->is_composite) { 1187b7c9bbdaSJeremy L Thompson // LCOV_EXCL_START 1188*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 1189b7c9bbdaSJeremy L Thompson // LCOV_EXCL_STOP 1190*2b730f8bSJeremy L Thompson } 1191b7c9bbdaSJeremy L Thompson *num_elem = op->num_elem; 1192b7c9bbdaSJeremy L Thompson return CEED_ERROR_SUCCESS; 1193b7c9bbdaSJeremy L Thompson } 1194b7c9bbdaSJeremy L Thompson 1195b7c9bbdaSJeremy L Thompson /** 1196b7c9bbdaSJeremy L Thompson @brief Get the number of quadrature points associated with a CeedOperator 1197b7c9bbdaSJeremy L Thompson 1198b7c9bbdaSJeremy L Thompson @param op CeedOperator 1199b7c9bbdaSJeremy L Thompson @param[out] num_qpts Variable to store vector number of quadrature points 1200b7c9bbdaSJeremy L Thompson 1201b7c9bbdaSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1202b7c9bbdaSJeremy L Thompson 1203b7c9bbdaSJeremy L Thompson @ref Advanced 1204b7c9bbdaSJeremy L Thompson **/ 1205b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1206*2b730f8bSJeremy L Thompson if (op->is_composite) { 1207b7c9bbdaSJeremy L Thompson // LCOV_EXCL_START 1208*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 1209b7c9bbdaSJeremy L Thompson // LCOV_EXCL_STOP 1210*2b730f8bSJeremy L Thompson } 1211b7c9bbdaSJeremy L Thompson *num_qpts = op->num_qpts; 1212b7c9bbdaSJeremy L Thompson return CEED_ERROR_SUCCESS; 1213b7c9bbdaSJeremy L Thompson } 1214b7c9bbdaSJeremy L Thompson 1215b7c9bbdaSJeremy L Thompson /** 12166e15d496SJeremy L Thompson @brief Estimate number of FLOPs required to apply CeedOperator on the active vector 12176e15d496SJeremy L Thompson 12186e15d496SJeremy L Thompson @param op Operator to estimate FLOPs for 12196e15d496SJeremy L Thompson @param flops Address of variable to hold FLOPs estimate 12206e15d496SJeremy L Thompson 12216e15d496SJeremy L Thompson @ref Backend 12226e15d496SJeremy L Thompson **/ 12239d36ca50SJeremy L Thompson int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) { 12246e15d496SJeremy L Thompson bool is_composite; 1225*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 12266e15d496SJeremy L Thompson 12276e15d496SJeremy L Thompson *flops = 0; 1228*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 12296e15d496SJeremy L Thompson if (is_composite) { 12306e15d496SJeremy L Thompson CeedInt num_suboperators; 1231*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetNumSub(op, &num_suboperators)); 12326e15d496SJeremy L Thompson CeedOperator *sub_operators; 1233*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetSubList(op, &sub_operators)); 12346e15d496SJeremy L Thompson 12356e15d496SJeremy L Thompson // FLOPs for each suboperator 12366e15d496SJeremy L Thompson for (CeedInt i = 0; i < num_suboperators; i++) { 12379d36ca50SJeremy L Thompson CeedSize suboperator_flops; 1238*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops)); 12396e15d496SJeremy L Thompson *flops += suboperator_flops; 12406e15d496SJeremy L Thompson } 12416e15d496SJeremy L Thompson } else { 12426e15d496SJeremy L Thompson CeedInt num_input_fields, num_output_fields; 12436e15d496SJeremy L Thompson CeedOperatorField *input_fields, *output_fields; 12446e15d496SJeremy L Thompson 1245*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields)); 12466e15d496SJeremy L Thompson 12476e15d496SJeremy L Thompson CeedInt num_elem = 0; 1248*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 12496e15d496SJeremy L Thompson // Input FLOPs 12506e15d496SJeremy L Thompson for (CeedInt i = 0; i < num_input_fields; i++) { 12516e15d496SJeremy L Thompson if (input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 12529d36ca50SJeremy L Thompson CeedSize restr_flops, basis_flops; 12536e15d496SJeremy L Thompson 1254*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetFlopsEstimate(input_fields[i]->elem_restr, CEED_NOTRANSPOSE, &restr_flops)); 12556e15d496SJeremy L Thompson *flops += restr_flops; 1256*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetFlopsEstimate(input_fields[i]->basis, CEED_NOTRANSPOSE, op->qf->input_fields[i]->eval_mode, &basis_flops)); 12576e15d496SJeremy L Thompson *flops += basis_flops * num_elem; 12586e15d496SJeremy L Thompson } 12596e15d496SJeremy L Thompson } 12606e15d496SJeremy L Thompson // QF FLOPs 12619d36ca50SJeremy L Thompson CeedInt num_qpts; 12629d36ca50SJeremy L Thompson CeedSize qf_flops; 1263*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts)); 1264*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionGetFlopsEstimate(op->qf, &qf_flops)); 12656e15d496SJeremy L Thompson *flops += num_elem * num_qpts * qf_flops; 12666e15d496SJeremy L Thompson // Output FLOPs 12676e15d496SJeremy L Thompson for (CeedInt i = 0; i < num_output_fields; i++) { 12686e15d496SJeremy L Thompson if (output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 12699d36ca50SJeremy L Thompson CeedSize restr_flops, basis_flops; 12706e15d496SJeremy L Thompson 1271*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionGetFlopsEstimate(output_fields[i]->elem_restr, CEED_TRANSPOSE, &restr_flops)); 12726e15d496SJeremy L Thompson *flops += restr_flops; 1273*2b730f8bSJeremy L Thompson CeedCall(CeedBasisGetFlopsEstimate(output_fields[i]->basis, CEED_TRANSPOSE, op->qf->output_fields[i]->eval_mode, &basis_flops)); 12746e15d496SJeremy L Thompson *flops += basis_flops * num_elem; 12756e15d496SJeremy L Thompson } 12766e15d496SJeremy L Thompson } 12776e15d496SJeremy L Thompson } 12786e15d496SJeremy L Thompson 12796e15d496SJeremy L Thompson return CEED_ERROR_SUCCESS; 12806e15d496SJeremy L Thompson } 12816e15d496SJeremy L Thompson 12826e15d496SJeremy L Thompson /** 12833668ca4bSJeremy L Thompson @brief Get label for a registered QFunctionContext field, or `NULL` if no 12843668ca4bSJeremy L Thompson field has been registered with this `field_name`. 12853668ca4bSJeremy L Thompson 12863668ca4bSJeremy L Thompson @param[in] op CeedOperator 12873668ca4bSJeremy L Thompson @param[in] field_name Name of field to retrieve label 12883668ca4bSJeremy L Thompson @param[out] field_label Variable to field label 12893668ca4bSJeremy L Thompson 12903668ca4bSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 12913668ca4bSJeremy L Thompson 12923668ca4bSJeremy L Thompson @ref User 12933668ca4bSJeremy L Thompson **/ 1294*2b730f8bSJeremy L Thompson int CeedOperatorContextGetFieldLabel(CeedOperator op, const char *field_name, CeedContextFieldLabel *field_label) { 12953668ca4bSJeremy L Thompson bool is_composite; 1296*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1297*2b730f8bSJeremy L Thompson 12983668ca4bSJeremy L Thompson if (is_composite) { 12993668ca4bSJeremy L Thompson // Check if composite label already created 13003668ca4bSJeremy L Thompson for (CeedInt i = 0; i < op->num_context_labels; i++) { 13013668ca4bSJeremy L Thompson if (!strcmp(op->context_labels[i]->name, field_name)) { 13023668ca4bSJeremy L Thompson *field_label = op->context_labels[i]; 13033668ca4bSJeremy L Thompson return CEED_ERROR_SUCCESS; 13043668ca4bSJeremy L Thompson } 13053668ca4bSJeremy L Thompson } 13063668ca4bSJeremy L Thompson 13073668ca4bSJeremy L Thompson // Create composite label if needed 13083668ca4bSJeremy L Thompson CeedInt num_sub; 13093668ca4bSJeremy L Thompson CeedOperator *sub_operators; 13103668ca4bSJeremy L Thompson CeedContextFieldLabel new_field_label; 13113668ca4bSJeremy L Thompson 1312*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, &new_field_label)); 1313*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetNumSub(op, &num_sub)); 1314*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetSubList(op, &sub_operators)); 1315*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(num_sub, &new_field_label->sub_labels)); 13163668ca4bSJeremy L Thompson new_field_label->num_sub_labels = num_sub; 13173668ca4bSJeremy L Thompson 13183668ca4bSJeremy L Thompson bool label_found = false; 13193668ca4bSJeremy L Thompson for (CeedInt i = 0; i < num_sub; i++) { 13203668ca4bSJeremy L Thompson if (sub_operators[i]->qf->ctx) { 13213668ca4bSJeremy L Thompson CeedContextFieldLabel new_field_label_i; 1322*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, &new_field_label_i)); 13233668ca4bSJeremy L Thompson if (new_field_label_i) { 13243668ca4bSJeremy L Thompson label_found = true; 13253668ca4bSJeremy L Thompson new_field_label->sub_labels[i] = new_field_label_i; 13263668ca4bSJeremy L Thompson new_field_label->name = new_field_label_i->name; 13273668ca4bSJeremy L Thompson new_field_label->description = new_field_label_i->description; 1328*2b730f8bSJeremy L Thompson if (new_field_label->type && new_field_label->type != new_field_label_i->type) { 13297bfe0f0eSJeremy L Thompson // LCOV_EXCL_START 1330*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&new_field_label)); 1331*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field types on sub-operator contexts. %s != %s", 1332*2b730f8bSJeremy L Thompson CeedContextFieldTypes[new_field_label->type], CeedContextFieldTypes[new_field_label_i->type]); 13337bfe0f0eSJeremy L Thompson // LCOV_EXCL_STOP 13347bfe0f0eSJeremy L Thompson } else { 13357bfe0f0eSJeremy L Thompson new_field_label->type = new_field_label_i->type; 13367bfe0f0eSJeremy L Thompson } 1337*2b730f8bSJeremy L Thompson if (new_field_label->num_values != 0 && new_field_label->num_values != new_field_label_i->num_values) { 13387bfe0f0eSJeremy L Thompson // LCOV_EXCL_START 1339*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&new_field_label)); 1340*2b730f8bSJeremy L Thompson return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field number of values on sub-operator contexts. %ld != %ld", 13417bfe0f0eSJeremy L Thompson new_field_label->num_values, new_field_label_i->num_values); 13427bfe0f0eSJeremy L Thompson // LCOV_EXCL_STOP 13437bfe0f0eSJeremy L Thompson } else { 13447bfe0f0eSJeremy L Thompson new_field_label->num_values = new_field_label_i->num_values; 13457bfe0f0eSJeremy L Thompson } 13463668ca4bSJeremy L Thompson } 13473668ca4bSJeremy L Thompson } 13483668ca4bSJeremy L Thompson } 13493668ca4bSJeremy L Thompson if (!label_found) { 13503668ca4bSJeremy L Thompson // LCOV_EXCL_START 1351*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&new_field_label->sub_labels)); 1352*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&new_field_label)); 13533668ca4bSJeremy L Thompson *field_label = NULL; 13543668ca4bSJeremy L Thompson // LCOV_EXCL_STOP 13553668ca4bSJeremy L Thompson } else { 13563668ca4bSJeremy L Thompson // Move new composite label to operator 13573668ca4bSJeremy L Thompson if (op->num_context_labels == 0) { 1358*2b730f8bSJeremy L Thompson CeedCall(CeedCalloc(1, &op->context_labels)); 13593668ca4bSJeremy L Thompson op->max_context_labels = 1; 13603668ca4bSJeremy L Thompson } else if (op->num_context_labels == op->max_context_labels) { 1361*2b730f8bSJeremy L Thompson CeedCall(CeedRealloc(2 * op->num_context_labels, &op->context_labels)); 13623668ca4bSJeremy L Thompson op->max_context_labels *= 2; 13633668ca4bSJeremy L Thompson } 13643668ca4bSJeremy L Thompson op->context_labels[op->num_context_labels] = new_field_label; 13653668ca4bSJeremy L Thompson *field_label = new_field_label; 13663668ca4bSJeremy L Thompson op->num_context_labels++; 13673668ca4bSJeremy L Thompson } 13683668ca4bSJeremy L Thompson 13693668ca4bSJeremy L Thompson return CEED_ERROR_SUCCESS; 13703668ca4bSJeremy L Thompson } else { 13713668ca4bSJeremy L Thompson return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label); 13723668ca4bSJeremy L Thompson } 13733668ca4bSJeremy L Thompson } 13743668ca4bSJeremy L Thompson 13753668ca4bSJeremy L Thompson /** 1376d8dd9a91SJeremy L Thompson @brief Set QFunctionContext field holding a double precision value. 1377d8dd9a91SJeremy L Thompson For composite operators, the value is set in all 1378d8dd9a91SJeremy L Thompson sub-operator QFunctionContexts that have a matching `field_name`. 1379d8dd9a91SJeremy L Thompson 1380d8dd9a91SJeremy L Thompson @param op CeedOperator 13813668ca4bSJeremy L Thompson @param field_label Label of field to register 13827bfe0f0eSJeremy L Thompson @param values Values to set 1383d8dd9a91SJeremy L Thompson 1384d8dd9a91SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1385d8dd9a91SJeremy L Thompson 1386d8dd9a91SJeremy L Thompson @ref User 1387d8dd9a91SJeremy L Thompson **/ 1388*2b730f8bSJeremy L Thompson int CeedOperatorContextSetDouble(CeedOperator op, CeedContextFieldLabel field_label, double *values) { 1389*2b730f8bSJeremy L Thompson return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values); 1390d8dd9a91SJeremy L Thompson } 1391d8dd9a91SJeremy L Thompson 1392d8dd9a91SJeremy L Thompson /** 1393d8dd9a91SJeremy L Thompson @brief Set QFunctionContext field holding an int32 value. 1394d8dd9a91SJeremy L Thompson For composite operators, the value is set in all 1395d8dd9a91SJeremy L Thompson sub-operator QFunctionContexts that have a matching `field_name`. 1396d8dd9a91SJeremy L Thompson 1397d8dd9a91SJeremy L Thompson @param op CeedOperator 13983668ca4bSJeremy L Thompson @param field_label Label of field to set 13997bfe0f0eSJeremy L Thompson @param values Values to set 1400d8dd9a91SJeremy L Thompson 1401d8dd9a91SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1402d8dd9a91SJeremy L Thompson 1403d8dd9a91SJeremy L Thompson @ref User 1404d8dd9a91SJeremy L Thompson **/ 1405*2b730f8bSJeremy L Thompson int CeedOperatorContextSetInt32(CeedOperator op, CeedContextFieldLabel field_label, int *values) { 1406*2b730f8bSJeremy L Thompson return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, values); 1407d8dd9a91SJeremy L Thompson } 1408d8dd9a91SJeremy L Thompson 1409d8dd9a91SJeremy L Thompson /** 14103bd813ffSjeremylt @brief Apply CeedOperator to a vector 1411d7b241e6Sjeremylt 1412d7b241e6Sjeremylt This computes the action of the operator on the specified (active) input, 1413d7b241e6Sjeremylt yielding its (active) output. All inputs and outputs must be specified using 1414d7b241e6Sjeremylt CeedOperatorSetField(). 1415d7b241e6Sjeremylt 1416f04ea552SJeremy L Thompson Note: Calling this function asserts that setup is complete 1417f04ea552SJeremy L Thompson and sets the CeedOperator as immutable. 1418f04ea552SJeremy L Thompson 1419d7b241e6Sjeremylt @param op CeedOperator to apply 14204cc79fe7SJed Brown @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if 142134138859Sjeremylt there are no active inputs 1422b11c1e72Sjeremylt @param[out] out CeedVector to store result of applying operator (must be 14234cc79fe7SJed Brown distinct from @a in) or @ref CEED_VECTOR_NONE if there are no 142434138859Sjeremylt active outputs 1425d7b241e6Sjeremylt @param request Address of CeedRequest for non-blocking completion, else 14264cc79fe7SJed Brown @ref CEED_REQUEST_IMMEDIATE 1427b11c1e72Sjeremylt 1428b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 1429dfdf5a53Sjeremylt 14307a982d89SJeremy L. Thompson @ref User 1431b11c1e72Sjeremylt **/ 1432*2b730f8bSJeremy L Thompson int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 1433*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1434d7b241e6Sjeremylt 1435d1d35e2fSjeremylt if (op->num_elem) { 1436250756a7Sjeremylt // Standard Operator 1437cae8b89aSjeremylt if (op->Apply) { 1438*2b730f8bSJeremy L Thompson CeedCall(op->Apply(op, in, out, request)); 1439cae8b89aSjeremylt } else { 1440cae8b89aSjeremylt // Zero all output vectors 1441250756a7Sjeremylt CeedQFunction qf = op->qf; 1442d1d35e2fSjeremylt for (CeedInt i = 0; i < qf->num_output_fields; i++) { 1443d1d35e2fSjeremylt CeedVector vec = op->output_fields[i]->vec; 1444*2b730f8bSJeremy L Thompson if (vec == CEED_VECTOR_ACTIVE) vec = out; 1445cae8b89aSjeremylt if (vec != CEED_VECTOR_NONE) { 1446*2b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(vec, 0.0)); 1447cae8b89aSjeremylt } 1448cae8b89aSjeremylt } 1449250756a7Sjeremylt // Apply 1450*2b730f8bSJeremy L Thompson CeedCall(op->ApplyAdd(op, in, out, request)); 1451250756a7Sjeremylt } 1452f04ea552SJeremy L Thompson } else if (op->is_composite) { 1453250756a7Sjeremylt // Composite Operator 1454250756a7Sjeremylt if (op->ApplyComposite) { 1455*2b730f8bSJeremy L Thompson CeedCall(op->ApplyComposite(op, in, out, request)); 1456250756a7Sjeremylt } else { 1457d1d35e2fSjeremylt CeedInt num_suboperators; 1458*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetNumSub(op, &num_suboperators)); 1459d1d35e2fSjeremylt CeedOperator *sub_operators; 1460*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetSubList(op, &sub_operators)); 1461250756a7Sjeremylt 1462250756a7Sjeremylt // Zero all output vectors 1463250756a7Sjeremylt if (out != CEED_VECTOR_NONE) { 1464*2b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(out, 0.0)); 1465cae8b89aSjeremylt } 1466d1d35e2fSjeremylt for (CeedInt i = 0; i < num_suboperators; i++) { 1467d1d35e2fSjeremylt for (CeedInt j = 0; j < sub_operators[i]->qf->num_output_fields; j++) { 1468d1d35e2fSjeremylt CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1469250756a7Sjeremylt if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1470*2b730f8bSJeremy L Thompson CeedCall(CeedVectorSetValue(vec, 0.0)); 1471250756a7Sjeremylt } 1472250756a7Sjeremylt } 1473250756a7Sjeremylt } 1474250756a7Sjeremylt // Apply 1475d1d35e2fSjeremylt for (CeedInt i = 0; i < op->num_suboperators; i++) { 1476*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorApplyAdd(op->sub_operators[i], in, out, request)); 1477cae8b89aSjeremylt } 1478cae8b89aSjeremylt } 1479250756a7Sjeremylt } 1480e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 1481cae8b89aSjeremylt } 1482cae8b89aSjeremylt 1483cae8b89aSjeremylt /** 1484cae8b89aSjeremylt @brief Apply CeedOperator to a vector and add result to output vector 1485cae8b89aSjeremylt 1486cae8b89aSjeremylt This computes the action of the operator on the specified (active) input, 1487cae8b89aSjeremylt yielding its (active) output. All inputs and outputs must be specified using 1488cae8b89aSjeremylt CeedOperatorSetField(). 1489cae8b89aSjeremylt 1490cae8b89aSjeremylt @param op CeedOperator to apply 1491cae8b89aSjeremylt @param[in] in CeedVector containing input state or NULL if there are no 1492cae8b89aSjeremylt active inputs 1493cae8b89aSjeremylt @param[out] out CeedVector to sum in result of applying operator (must be 1494cae8b89aSjeremylt distinct from @a in) or NULL if there are no active outputs 1495cae8b89aSjeremylt @param request Address of CeedRequest for non-blocking completion, else 14964cc79fe7SJed Brown @ref CEED_REQUEST_IMMEDIATE 1497cae8b89aSjeremylt 1498cae8b89aSjeremylt @return An error code: 0 - success, otherwise - failure 1499cae8b89aSjeremylt 15007a982d89SJeremy L. Thompson @ref User 1501cae8b89aSjeremylt **/ 1502*2b730f8bSJeremy L Thompson int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 1503*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorCheckReady(op)); 1504cae8b89aSjeremylt 1505d1d35e2fSjeremylt if (op->num_elem) { 1506250756a7Sjeremylt // Standard Operator 1507*2b730f8bSJeremy L Thompson CeedCall(op->ApplyAdd(op, in, out, request)); 1508f04ea552SJeremy L Thompson } else if (op->is_composite) { 1509250756a7Sjeremylt // Composite Operator 1510250756a7Sjeremylt if (op->ApplyAddComposite) { 1511*2b730f8bSJeremy L Thompson CeedCall(op->ApplyAddComposite(op, in, out, request)); 1512cae8b89aSjeremylt } else { 1513d1d35e2fSjeremylt CeedInt num_suboperators; 1514*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetNumSub(op, &num_suboperators)); 1515d1d35e2fSjeremylt CeedOperator *sub_operators; 1516*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorGetSubList(op, &sub_operators)); 1517250756a7Sjeremylt 1518d1d35e2fSjeremylt for (CeedInt i = 0; i < num_suboperators; i++) { 1519*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request)); 15201d7d2407SJeremy L Thompson } 1521250756a7Sjeremylt } 1522250756a7Sjeremylt } 1523e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 1524d7b241e6Sjeremylt } 1525d7b241e6Sjeremylt 1526d7b241e6Sjeremylt /** 1527b11c1e72Sjeremylt @brief Destroy a CeedOperator 1528d7b241e6Sjeremylt 1529d7b241e6Sjeremylt @param op CeedOperator to destroy 1530b11c1e72Sjeremylt 1531b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 1532dfdf5a53Sjeremylt 15337a982d89SJeremy L. Thompson @ref User 1534b11c1e72Sjeremylt **/ 1535d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) { 1536d1d35e2fSjeremylt if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS; 1537*2b730f8bSJeremy L Thompson if ((*op)->Destroy) CeedCall((*op)->Destroy(*op)); 1538*2b730f8bSJeremy L Thompson CeedCall(CeedDestroy(&(*op)->ceed)); 1539fe2413ffSjeremylt // Free fields 1540*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < (*op)->num_fields; i++) { 1541d1d35e2fSjeremylt if ((*op)->input_fields[i]) { 1542d1d35e2fSjeremylt if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) { 1543*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr)); 154415910d16Sjeremylt } 1545d1d35e2fSjeremylt if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1546*2b730f8bSJeremy L Thompson CeedCall(CeedBasisDestroy(&(*op)->input_fields[i]->basis)); 154771352a93Sjeremylt } 1548*2b730f8bSJeremy L Thompson if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->input_fields[i]->vec != CEED_VECTOR_NONE) { 1549*2b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&(*op)->input_fields[i]->vec)); 155071352a93Sjeremylt } 1551*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*op)->input_fields[i]->field_name)); 1552*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*op)->input_fields[i])); 1553fe2413ffSjeremylt } 1554*2b730f8bSJeremy L Thompson } 1555*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < (*op)->num_fields; i++) { 1556d1d35e2fSjeremylt if ((*op)->output_fields[i]) { 1557*2b730f8bSJeremy L Thompson CeedCall(CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr)); 1558d1d35e2fSjeremylt if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1559*2b730f8bSJeremy L Thompson CeedCall(CeedBasisDestroy(&(*op)->output_fields[i]->basis)); 156071352a93Sjeremylt } 1561*2b730f8bSJeremy L Thompson if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->output_fields[i]->vec != CEED_VECTOR_NONE) { 1562*2b730f8bSJeremy L Thompson CeedCall(CeedVectorDestroy(&(*op)->output_fields[i]->vec)); 156371352a93Sjeremylt } 1564*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*op)->output_fields[i]->field_name)); 1565*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*op)->output_fields[i])); 1566*2b730f8bSJeremy L Thompson } 1567fe2413ffSjeremylt } 1568d1d35e2fSjeremylt // Destroy sub_operators 1569*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < (*op)->num_suboperators; i++) { 1570d1d35e2fSjeremylt if ((*op)->sub_operators[i]) { 1571*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorDestroy(&(*op)->sub_operators[i])); 157252d6035fSJeremy L Thompson } 1573*2b730f8bSJeremy L Thompson } 1574*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&(*op)->qf)); 1575*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&(*op)->dqf)); 1576*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionDestroy(&(*op)->dqfT)); 15773668ca4bSJeremy L Thompson // Destroy any composite labels 15783668ca4bSJeremy L Thompson for (CeedInt i = 0; i < (*op)->num_context_labels; i++) { 1579*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*op)->context_labels[i]->sub_labels)); 1580*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*op)->context_labels[i])); 15813668ca4bSJeremy L Thompson } 1582*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*op)->context_labels)); 1583fe2413ffSjeremylt 15845107b09fSJeremy L Thompson // Destroy fallback 1585*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorDestroy(&(*op)->op_fallback)); 15865107b09fSJeremy L Thompson 1587ed9e99e6SJeremy L Thompson // Destroy assembly data 1588*2b730f8bSJeremy L Thompson CeedCall(CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled)); 1589*2b730f8bSJeremy L Thompson CeedCall(CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled)); 159070a7ffb3SJeremy L Thompson 1591*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*op)->input_fields)); 1592*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*op)->output_fields)); 1593*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*op)->sub_operators)); 1594*2b730f8bSJeremy L Thompson CeedCall(CeedFree(&(*op)->name)); 1595*2b730f8bSJeremy L Thompson CeedCall(CeedFree(op)); 1596e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 1597d7b241e6Sjeremylt } 1598d7b241e6Sjeremylt 1599d7b241e6Sjeremylt /// @} 1600