1d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details. 4d7b241e6Sjeremylt // 5d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software 6d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral 7d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and 8d7b241e6Sjeremylt // source code availability see http://github.com/ceed. 9d7b241e6Sjeremylt // 10d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office 12d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for 13d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including 14d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early 15d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative. 16d7b241e6Sjeremylt 17d7b241e6Sjeremylt #include <ceed-impl.h> 18d863ab9bSjeremylt #include <ceed-backend.h> 19d7b241e6Sjeremylt #include <string.h> 20d7b241e6Sjeremylt 21dfdf5a53Sjeremylt /// @file 22dfdf5a53Sjeremylt /// Implementation of public CeedOperator interfaces 23dfdf5a53Sjeremylt /// 24dfdf5a53Sjeremylt /// @addtogroup CeedOperator 25dfdf5a53Sjeremylt /// @{ 26d7b241e6Sjeremylt 27d7b241e6Sjeremylt /** 28b11c1e72Sjeremylt @brief Create an operator from element restriction, basis, and QFunction 29d7b241e6Sjeremylt 30b11c1e72Sjeremylt @param ceed A Ceed object where the CeedOperator will be created 31d7b241e6Sjeremylt @param qf QFunction defining the action of the operator at quadrature points 32d7b241e6Sjeremylt @param dqf QFunction defining the action of the Jacobian of @a qf (or NULL) 33d7b241e6Sjeremylt @param dqfT QFunction defining the action of the transpose of the Jacobian 34d7b241e6Sjeremylt of @a qf (or NULL) 35b11c1e72Sjeremylt @param[out] op Address of the variable where the newly created 36b11c1e72Sjeremylt CeedOperator will be stored 37b11c1e72Sjeremylt 38b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 39dfdf5a53Sjeremylt 40dfdf5a53Sjeremylt @ref Basic 41d7b241e6Sjeremylt */ 42d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 43d7b241e6Sjeremylt CeedQFunction dqfT, CeedOperator *op) { 44d7b241e6Sjeremylt int ierr; 45d7b241e6Sjeremylt 465fe0d4faSjeremylt if (!ceed->OperatorCreate) { 475fe0d4faSjeremylt Ceed delegate; 485fe0d4faSjeremylt ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr); 495fe0d4faSjeremylt 505fe0d4faSjeremylt if (!delegate) 515fe0d4faSjeremylt return CeedError(ceed, 1, "Backend does not support OperatorCreate"); 525fe0d4faSjeremylt 535fe0d4faSjeremylt ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 545fe0d4faSjeremylt return 0; 555fe0d4faSjeremylt } 565fe0d4faSjeremylt 57d7b241e6Sjeremylt ierr = CeedCalloc(1,op); CeedChk(ierr); 58d7b241e6Sjeremylt (*op)->ceed = ceed; 59d7b241e6Sjeremylt ceed->refcount++; 60d7b241e6Sjeremylt (*op)->refcount = 1; 61d7b241e6Sjeremylt (*op)->qf = qf; 62d7b241e6Sjeremylt qf->refcount++; 63d7b241e6Sjeremylt (*op)->dqf = dqf; 64d7b241e6Sjeremylt if (dqf) dqf->refcount++; 65d7b241e6Sjeremylt (*op)->dqfT = dqfT; 66d7b241e6Sjeremylt if (dqfT) dqfT->refcount++; 67d7b241e6Sjeremylt ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 68d7b241e6Sjeremylt return 0; 69d7b241e6Sjeremylt } 70d7b241e6Sjeremylt 71d7b241e6Sjeremylt /** 72b11c1e72Sjeremylt @brief Provide a field to a CeedOperator for use by its CeedQFunction 73d7b241e6Sjeremylt 74d7b241e6Sjeremylt This function is used to specify both active and passive fields to a 75d7b241e6Sjeremylt CeedOperator. For passive fields, a vector @arg v must be provided. Passive 76d7b241e6Sjeremylt fields can inputs or outputs (updated in-place when operator is applied). 77d7b241e6Sjeremylt 78d7b241e6Sjeremylt Active fields must be specified using this function, but their data (in a 79d7b241e6Sjeremylt CeedVector) is passed in CeedOperatorApply(). There can be at most one active 80d7b241e6Sjeremylt input and at most one active output. 81d7b241e6Sjeremylt 82b11c1e72Sjeremylt @param op Ceedoperator on which to provide the field 83b11c1e72Sjeremylt @param fieldname Name of the field (to be matched with the name used by CeedQFunction) 84b11c1e72Sjeremylt @param r CeedElemRestriction 85783c99b3SValeria Barra @param b CeedBasis in which the field resides or CEED_BASIS_COLLOCATED 86b11c1e72Sjeremylt if collocated with quadrature points 87b11c1e72Sjeremylt @param v CeedVector to be used by CeedOperator or CEED_VECTOR_ACTIVE 88b11c1e72Sjeremylt if field is active or CEED_VECTOR_NONE if using 89b11c1e72Sjeremylt CEED_EVAL_WEIGHT in the qfunction 90b11c1e72Sjeremylt 91b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 92dfdf5a53Sjeremylt 93dfdf5a53Sjeremylt @ref Basic 94b11c1e72Sjeremylt **/ 95d7b241e6Sjeremylt int CeedOperatorSetField(CeedOperator op, const char *fieldname, 96d7b241e6Sjeremylt CeedElemRestriction r, CeedBasis b, 97d7b241e6Sjeremylt CeedVector v) { 98d7b241e6Sjeremylt int ierr; 99d7b241e6Sjeremylt CeedInt numelements; 100d7b241e6Sjeremylt ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr); 101d7b241e6Sjeremylt if (op->numelements && op->numelements != numelements) 102d7b241e6Sjeremylt return CeedError(op->ceed, 1, 103d7b241e6Sjeremylt "ElemRestriction with %d elements incompatible with prior %d elements", 104d7b241e6Sjeremylt numelements, op->numelements); 105d7b241e6Sjeremylt op->numelements = numelements; 106d7b241e6Sjeremylt 107783c99b3SValeria Barra if (b != CEED_BASIS_COLLOCATED) { 108d7b241e6Sjeremylt CeedInt numqpoints; 109d7b241e6Sjeremylt ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr); 110d7b241e6Sjeremylt if (op->numqpoints && op->numqpoints != numqpoints) 111d7b241e6Sjeremylt return CeedError(op->ceed, 1, 112d7b241e6Sjeremylt "Basis with %d quadrature points incompatible with prior %d points", 113d7b241e6Sjeremylt numqpoints, op->numqpoints); 114d7b241e6Sjeremylt op->numqpoints = numqpoints; 115d7b241e6Sjeremylt } 116*d1bcdac9Sjeremylt CeedOperatorField *ofield; 117d7b241e6Sjeremylt for (CeedInt i=0; i<op->qf->numinputfields; i++) { 118d7b241e6Sjeremylt if (!strcmp(fieldname, op->qf->inputfields[i].fieldname)) { 119d7b241e6Sjeremylt ofield = &op->inputfields[i]; 120d7b241e6Sjeremylt goto found; 121d7b241e6Sjeremylt } 122d7b241e6Sjeremylt } 123d7b241e6Sjeremylt for (CeedInt i=0; i<op->qf->numoutputfields; i++) { 124d7b241e6Sjeremylt if (!strcmp(fieldname, op->qf->outputfields[i].fieldname)) { 125d7b241e6Sjeremylt ofield = &op->outputfields[i]; 126d7b241e6Sjeremylt goto found; 127d7b241e6Sjeremylt } 128d7b241e6Sjeremylt } 129d7b241e6Sjeremylt return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'", 130d7b241e6Sjeremylt fieldname); 131d7b241e6Sjeremylt found: 132d7b241e6Sjeremylt ofield->Erestrict = r; 133d7b241e6Sjeremylt ofield->basis = b; 134d7b241e6Sjeremylt ofield->vec = v; 135d7b241e6Sjeremylt op->nfields += 1; 136d7b241e6Sjeremylt return 0; 137d7b241e6Sjeremylt } 138d7b241e6Sjeremylt 139d7b241e6Sjeremylt /** 140b11c1e72Sjeremylt @brief Apply CeedOperator to a vector 141d7b241e6Sjeremylt 142d7b241e6Sjeremylt This computes the action of the operator on the specified (active) input, 143d7b241e6Sjeremylt yielding its (active) output. All inputs and outputs must be specified using 144d7b241e6Sjeremylt CeedOperatorSetField(). 145d7b241e6Sjeremylt 146d7b241e6Sjeremylt @param op CeedOperator to apply 147b11c1e72Sjeremylt @param[in] in CeedVector containing input state or NULL if there are no 148b11c1e72Sjeremylt active inputs 149b11c1e72Sjeremylt @param[out] out CeedVector to store result of applying operator (must be 150d7b241e6Sjeremylt distinct from @a in) or NULL if there are no active outputs 151d7b241e6Sjeremylt @param request Address of CeedRequest for non-blocking completion, else 152d7b241e6Sjeremylt CEED_REQUEST_IMMEDIATE 153b11c1e72Sjeremylt 154b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 155dfdf5a53Sjeremylt 156dfdf5a53Sjeremylt @ref Basic 157b11c1e72Sjeremylt **/ 158d7b241e6Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, 159d7b241e6Sjeremylt CeedVector out, CeedRequest *request) { 160d7b241e6Sjeremylt int ierr; 161d7b241e6Sjeremylt Ceed ceed = op->ceed; 162d7b241e6Sjeremylt CeedQFunction qf = op->qf; 163d7b241e6Sjeremylt 164d7b241e6Sjeremylt if (op->nfields == 0) return CeedError(ceed, 1, "No operator fields set"); 165d7b241e6Sjeremylt if (op->nfields < qf->numinputfields + qf->numoutputfields) return CeedError( 166d7b241e6Sjeremylt ceed, 1, "Not all operator fields set"); 167d7b241e6Sjeremylt if (op->numelements == 0) return CeedError(ceed, 1, 168d7b241e6Sjeremylt "At least one restriction required"); 169d7b241e6Sjeremylt if (op->numqpoints == 0) return CeedError(ceed, 1, 170783c99b3SValeria Barra "At least one non-collocated basis required"); 171d7b241e6Sjeremylt ierr = op->Apply(op, in, out, request); CeedChk(ierr); 172d7b241e6Sjeremylt return 0; 173d7b241e6Sjeremylt } 174d7b241e6Sjeremylt 175d7b241e6Sjeremylt /** 1764ce2993fSjeremylt @brief Get the Ceed associated with a CeedOperator 1774ce2993fSjeremylt 1784ce2993fSjeremylt @param op CeedOperator 1794ce2993fSjeremylt @param[out] ceed Variable to store Ceed 1804ce2993fSjeremylt 1814ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 1824ce2993fSjeremylt 18323617272Sjeremylt @ref Advanced 1844ce2993fSjeremylt **/ 1854ce2993fSjeremylt 1864ce2993fSjeremylt int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1874ce2993fSjeremylt *ceed = op->ceed; 1884ce2993fSjeremylt return 0; 1894ce2993fSjeremylt } 1904ce2993fSjeremylt 1914ce2993fSjeremylt /** 1924ce2993fSjeremylt @brief Get the number of elements associated with a CeedOperator 1934ce2993fSjeremylt 1944ce2993fSjeremylt @param op CeedOperator 1954ce2993fSjeremylt @param[out] numelem Variable to store number of elements 1964ce2993fSjeremylt 1974ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 1984ce2993fSjeremylt 19923617272Sjeremylt @ref Advanced 2004ce2993fSjeremylt **/ 2014ce2993fSjeremylt 2024ce2993fSjeremylt int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) { 2034ce2993fSjeremylt *numelem = op->numelements; 2044ce2993fSjeremylt return 0; 2054ce2993fSjeremylt } 2064ce2993fSjeremylt 2074ce2993fSjeremylt /** 2084ce2993fSjeremylt @brief Get the number of quadrature points associated with a CeedOperator 2094ce2993fSjeremylt 2104ce2993fSjeremylt @param op CeedOperator 2114ce2993fSjeremylt @param[out] numqpts Variable to store vector number of quadrature points 2124ce2993fSjeremylt 2134ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 2144ce2993fSjeremylt 21523617272Sjeremylt @ref Advanced 2164ce2993fSjeremylt **/ 2174ce2993fSjeremylt 2184ce2993fSjeremylt int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) { 2194ce2993fSjeremylt *numqpts = op->numqpoints; 2204ce2993fSjeremylt return 0; 2214ce2993fSjeremylt } 2224ce2993fSjeremylt 2234ce2993fSjeremylt /** 2244ce2993fSjeremylt @brief Get the number of arguments associated with a CeedOperator 2254ce2993fSjeremylt 2264ce2993fSjeremylt @param op CeedOperator 2274ce2993fSjeremylt @param[out] numargs Variable to store vector number of arguments 2284ce2993fSjeremylt 2294ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 2304ce2993fSjeremylt 23123617272Sjeremylt @ref Advanced 2324ce2993fSjeremylt **/ 2334ce2993fSjeremylt 2344ce2993fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) { 2354ce2993fSjeremylt *numargs = op->nfields; 2364ce2993fSjeremylt return 0; 2374ce2993fSjeremylt } 2384ce2993fSjeremylt 2394ce2993fSjeremylt /** 2404ce2993fSjeremylt @brief Get the setup status of a CeedOperator 2414ce2993fSjeremylt 2424ce2993fSjeremylt @param op CeedOperator 2434ce2993fSjeremylt @param[out] numelem Variable to store setup status 2444ce2993fSjeremylt 2454ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 2464ce2993fSjeremylt 24723617272Sjeremylt @ref Advanced 2484ce2993fSjeremylt **/ 2494ce2993fSjeremylt 2504ce2993fSjeremylt int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) { 2514ce2993fSjeremylt *setupdone = op->setupdone; 2524ce2993fSjeremylt return 0; 2534ce2993fSjeremylt } 2544ce2993fSjeremylt 2554ce2993fSjeremylt /** 2564ce2993fSjeremylt @brief Get the QFunction associated with a CeedOperator 2574ce2993fSjeremylt 2584ce2993fSjeremylt @param op CeedOperator 2594ce2993fSjeremylt @param[out] qf Variable to store qfunction 2604ce2993fSjeremylt 2614ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 2624ce2993fSjeremylt 26323617272Sjeremylt @ref Advanced 2644ce2993fSjeremylt **/ 2654ce2993fSjeremylt 2664ce2993fSjeremylt int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 2674ce2993fSjeremylt *qf = op->qf; 2684ce2993fSjeremylt return 0; 2694ce2993fSjeremylt } 2704ce2993fSjeremylt 2714ce2993fSjeremylt /** 2724ce2993fSjeremylt @brief Get the backend data of a CeedOperator 2734ce2993fSjeremylt 2744ce2993fSjeremylt @param op CeedOperator 2754ce2993fSjeremylt @param[out] data Variable to store data 2764ce2993fSjeremylt 2774ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 2784ce2993fSjeremylt 27923617272Sjeremylt @ref Advanced 2804ce2993fSjeremylt **/ 2814ce2993fSjeremylt 2824ce2993fSjeremylt int CeedOperatorGetData(CeedOperator op, void* *data) { 2834ce2993fSjeremylt *data = op->data; 2844ce2993fSjeremylt return 0; 2854ce2993fSjeremylt } 2864ce2993fSjeremylt 2874ce2993fSjeremylt /** 2884ce2993fSjeremylt @brief Set the setup flag of a CeedOperator to True 2894ce2993fSjeremylt 2904ce2993fSjeremylt @param op CeedOperator 2914ce2993fSjeremylt 2924ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 2934ce2993fSjeremylt 29423617272Sjeremylt @ref Advanced 2954ce2993fSjeremylt **/ 2964ce2993fSjeremylt 2974ce2993fSjeremylt int CeedOperatorSetSetupDone(CeedOperator op) { 2984ce2993fSjeremylt op->setupdone = 1; 2994ce2993fSjeremylt return 0; 3004ce2993fSjeremylt } 3014ce2993fSjeremylt 3024ce2993fSjeremylt /** 303*d1bcdac9Sjeremylt @brief Get the CeedOperatorFields of a CeedOperator 304*d1bcdac9Sjeremylt 305*d1bcdac9Sjeremylt @param op CeedOperator 306*d1bcdac9Sjeremylt @param[out] inputfields Variable to store inputfields 307*d1bcdac9Sjeremylt @param[out] outputfields Variable to store outputfields 308*d1bcdac9Sjeremylt 309*d1bcdac9Sjeremylt @return An error code: 0 - success, otherwise - failure 310*d1bcdac9Sjeremylt 311*d1bcdac9Sjeremylt @ref Advanced 312*d1bcdac9Sjeremylt **/ 313*d1bcdac9Sjeremylt 314*d1bcdac9Sjeremylt int CeedOperatorGetFields(CeedOperator op, 315*d1bcdac9Sjeremylt CeedOperatorField* *inputfields, 316*d1bcdac9Sjeremylt CeedOperatorField* *outputfields) { 317*d1bcdac9Sjeremylt if (inputfields) *inputfields = op->inputfields; 318*d1bcdac9Sjeremylt if (outputfields) *outputfields = op->outputfields; 319*d1bcdac9Sjeremylt return 0; 320*d1bcdac9Sjeremylt } 321*d1bcdac9Sjeremylt 322*d1bcdac9Sjeremylt /** 323*d1bcdac9Sjeremylt @brief Get the CeedElemRestriction of a CeedOperatorField 324*d1bcdac9Sjeremylt 325*d1bcdac9Sjeremylt @param opfield CeedOperatorField 326*d1bcdac9Sjeremylt @param[out] rstr Variable to store CeedElemRestriction 327*d1bcdac9Sjeremylt 328*d1bcdac9Sjeremylt @return An error code: 0 - success, otherwise - failure 329*d1bcdac9Sjeremylt 330*d1bcdac9Sjeremylt @ref Advanced 331*d1bcdac9Sjeremylt **/ 332*d1bcdac9Sjeremylt 333*d1bcdac9Sjeremylt int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield, 334*d1bcdac9Sjeremylt CeedElemRestriction *rstr) { 335*d1bcdac9Sjeremylt *rstr = (&opfield)->Erestrict; 336*d1bcdac9Sjeremylt return 0; 337*d1bcdac9Sjeremylt } 338*d1bcdac9Sjeremylt 339*d1bcdac9Sjeremylt /** 340*d1bcdac9Sjeremylt @brief Get the CeedBasis of a CeedOperatorField 341*d1bcdac9Sjeremylt 342*d1bcdac9Sjeremylt @param opfield CeedOperatorField 343*d1bcdac9Sjeremylt @param[out] basis Variable to store CeedBasis 344*d1bcdac9Sjeremylt 345*d1bcdac9Sjeremylt @return An error code: 0 - success, otherwise - failure 346*d1bcdac9Sjeremylt 347*d1bcdac9Sjeremylt @ref Advanced 348*d1bcdac9Sjeremylt **/ 349*d1bcdac9Sjeremylt 350*d1bcdac9Sjeremylt int CeedOperatorFieldGetBasis(CeedOperatorField opfield, 351*d1bcdac9Sjeremylt CeedBasis *basis) { 352*d1bcdac9Sjeremylt *basis = (&opfield)->basis; 353*d1bcdac9Sjeremylt return 0; 354*d1bcdac9Sjeremylt } 355*d1bcdac9Sjeremylt 356*d1bcdac9Sjeremylt /** 357*d1bcdac9Sjeremylt @brief Get the CeedVector of a CeedOperatorField 358*d1bcdac9Sjeremylt 359*d1bcdac9Sjeremylt @param opfield CeedOperatorField 360*d1bcdac9Sjeremylt @param[out] vec Variable to store CeedVector 361*d1bcdac9Sjeremylt 362*d1bcdac9Sjeremylt @return An error code: 0 - success, otherwise - failure 363*d1bcdac9Sjeremylt 364*d1bcdac9Sjeremylt @ref Advanced 365*d1bcdac9Sjeremylt **/ 366*d1bcdac9Sjeremylt 367*d1bcdac9Sjeremylt int CeedOperatorFieldGetVector(CeedOperatorField opfield, 368*d1bcdac9Sjeremylt CeedVector *vec) { 369*d1bcdac9Sjeremylt *vec = (&opfield)->vec; 370*d1bcdac9Sjeremylt return 0; 371*d1bcdac9Sjeremylt } 372*d1bcdac9Sjeremylt 373*d1bcdac9Sjeremylt /** 374b11c1e72Sjeremylt @brief Destroy a CeedOperator 375d7b241e6Sjeremylt 376d7b241e6Sjeremylt @param op CeedOperator to destroy 377b11c1e72Sjeremylt 378b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 379dfdf5a53Sjeremylt 380dfdf5a53Sjeremylt @ref Basic 381b11c1e72Sjeremylt **/ 382d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) { 383d7b241e6Sjeremylt int ierr; 384d7b241e6Sjeremylt 385d7b241e6Sjeremylt if (!*op || --(*op)->refcount > 0) return 0; 386d7b241e6Sjeremylt if ((*op)->Destroy) { 387d7b241e6Sjeremylt ierr = (*op)->Destroy(*op); CeedChk(ierr); 388d7b241e6Sjeremylt } 389d7b241e6Sjeremylt ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 390d7b241e6Sjeremylt ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 391d7b241e6Sjeremylt ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 392d7b241e6Sjeremylt ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 393d7b241e6Sjeremylt ierr = CeedFree(op); CeedChk(ierr); 394d7b241e6Sjeremylt return 0; 395d7b241e6Sjeremylt } 396d7b241e6Sjeremylt 397d7b241e6Sjeremylt /// @} 398