1777ff853SJeremy L Thompson // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2777ff853SJeremy L Thompson // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3777ff853SJeremy L Thompson // reserved. See files LICENSE and NOTICE for details. 4777ff853SJeremy L Thompson // 5777ff853SJeremy L Thompson // This file is part of CEED, a collection of benchmarks, miniapps, software 6777ff853SJeremy L Thompson // libraries and APIs for efficient high-order finite element and spectral 7777ff853SJeremy L Thompson // element discretizations for exascale applications. For more information and 8777ff853SJeremy L Thompson // source code availability see http://github.com/ceed. 9777ff853SJeremy L Thompson // 10777ff853SJeremy L Thompson // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11777ff853SJeremy L Thompson // a collaborative effort of two U.S. Department of Energy organizations (Office 12777ff853SJeremy L Thompson // of Science and the National Nuclear Security Administration) responsible for 13777ff853SJeremy L Thompson // the planning and preparation of a capable exascale ecosystem, including 14777ff853SJeremy L Thompson // software, applications, hardware, advanced system engineering and early 15777ff853SJeremy L Thompson // testbed platforms, in support of the nation's exascale computing imperative. 16777ff853SJeremy L Thompson 17ec3da8bcSJed Brown #include <ceed/ceed.h> 18ec3da8bcSJed Brown #include <ceed/backend.h> 193d576824SJeremy L Thompson #include <ceed-impl.h> 203d576824SJeremy L Thompson #include <stdint.h> 213d576824SJeremy L Thompson #include <stdio.h> 22*cdf32b93SJeremy L Thompson #include <string.h> 23777ff853SJeremy L Thompson 24777ff853SJeremy L Thompson /// @file 25777ff853SJeremy L Thompson /// Implementation of public CeedQFunctionContext interfaces 26777ff853SJeremy L Thompson 27777ff853SJeremy L Thompson /// ---------------------------------------------------------------------------- 28*cdf32b93SJeremy L Thompson /// CeedQFunctionContext Library Internal Functions 29*cdf32b93SJeremy L Thompson /// ---------------------------------------------------------------------------- 30*cdf32b93SJeremy L Thompson /// @addtogroup CeedQFunctionDeveloper 31*cdf32b93SJeremy L Thompson /// @{ 32*cdf32b93SJeremy L Thompson 33*cdf32b93SJeremy L Thompson /** 34*cdf32b93SJeremy L Thompson @brief Get index for QFunctionContext field 35*cdf32b93SJeremy L Thompson 36*cdf32b93SJeremy L Thompson @param ctx CeedQFunctionContext 37*cdf32b93SJeremy L Thompson @param field_name Name of field 38*cdf32b93SJeremy L Thompson @param field_index Index of field, or -1 if field is not registered 39*cdf32b93SJeremy L Thompson 40*cdf32b93SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 41*cdf32b93SJeremy L Thompson 42*cdf32b93SJeremy L Thompson @ref Developer 43*cdf32b93SJeremy L Thompson **/ 44*cdf32b93SJeremy L Thompson int CeedQFunctionContextGetFieldIndex(CeedQFunctionContext ctx, 45*cdf32b93SJeremy L Thompson const char *field_name, CeedInt *field_index) { 46*cdf32b93SJeremy L Thompson *field_index = -1; 47*cdf32b93SJeremy L Thompson for (CeedInt i=0; i<ctx->num_fields; i++) 48*cdf32b93SJeremy L Thompson if (!strcmp(ctx->field_descriptions[i].name, field_name)) 49*cdf32b93SJeremy L Thompson *field_index = i; 50*cdf32b93SJeremy L Thompson return CEED_ERROR_SUCCESS; 51*cdf32b93SJeremy L Thompson } 52*cdf32b93SJeremy L Thompson 53*cdf32b93SJeremy L Thompson /** 54*cdf32b93SJeremy L Thompson @brief Common function for registering QFunctionContext fields 55*cdf32b93SJeremy L Thompson 56*cdf32b93SJeremy L Thompson @param ctx CeedQFunctionContext 57*cdf32b93SJeremy L Thompson @param field_name Name of field to register 58*cdf32b93SJeremy L Thompson @param field_offset Offset of field to register 59*cdf32b93SJeremy L Thompson @param field_description Description of field, or NULL for none 60*cdf32b93SJeremy L Thompson @param field_type Field data type, such as double or int32 61*cdf32b93SJeremy L Thompson @param field_size Size of field, in bytes 62*cdf32b93SJeremy L Thompson 63*cdf32b93SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 64*cdf32b93SJeremy L Thompson 65*cdf32b93SJeremy L Thompson @ref Developer 66*cdf32b93SJeremy L Thompson **/ 67*cdf32b93SJeremy L Thompson int CeedQFunctionContextRegisterGeneric(CeedQFunctionContext ctx, 68*cdf32b93SJeremy L Thompson const char *field_name, size_t field_offset, 69*cdf32b93SJeremy L Thompson const char *field_description, 70*cdf32b93SJeremy L Thompson CeedContextFieldType field_type, 71*cdf32b93SJeremy L Thompson size_t field_size) { 72*cdf32b93SJeremy L Thompson int ierr; 73*cdf32b93SJeremy L Thompson 74*cdf32b93SJeremy L Thompson // Check for duplicate 75*cdf32b93SJeremy L Thompson CeedInt field_index = -1; 76*cdf32b93SJeremy L Thompson ierr = CeedQFunctionContextGetFieldIndex(ctx, field_name, &field_index); 77*cdf32b93SJeremy L Thompson CeedChk(ierr); 78*cdf32b93SJeremy L Thompson if (field_index != -1) 79*cdf32b93SJeremy L Thompson // LCOV_EXCL_START 80*cdf32b93SJeremy L Thompson return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 81*cdf32b93SJeremy L Thompson "QFunctionContext field with name \"%s\" already registered", 82*cdf32b93SJeremy L Thompson field_name); 83*cdf32b93SJeremy L Thompson // LCOV_EXCL_STOP 84*cdf32b93SJeremy L Thompson 85*cdf32b93SJeremy L Thompson // Allocate space for field data 86*cdf32b93SJeremy L Thompson if (ctx->num_fields == 0) { 87*cdf32b93SJeremy L Thompson ierr = CeedCalloc(1, &ctx->field_descriptions); CeedChk(ierr); 88*cdf32b93SJeremy L Thompson ctx->max_fields = 1; 89*cdf32b93SJeremy L Thompson } else if (ctx->num_fields == ctx->max_fields) { 90*cdf32b93SJeremy L Thompson ierr = CeedRealloc(2*ctx->max_fields, &ctx->field_descriptions); 91*cdf32b93SJeremy L Thompson CeedChk(ierr); 92*cdf32b93SJeremy L Thompson ctx->max_fields *= 2; 93*cdf32b93SJeremy L Thompson } 94*cdf32b93SJeremy L Thompson 95*cdf32b93SJeremy L Thompson // Copy field data 96*cdf32b93SJeremy L Thompson { 97*cdf32b93SJeremy L Thompson size_t len = strlen(field_name); 98*cdf32b93SJeremy L Thompson char *tmp; 99*cdf32b93SJeremy L Thompson ierr = CeedCalloc(len + 1, &tmp); CeedChk(ierr); 100*cdf32b93SJeremy L Thompson memcpy(tmp, field_name, len+1); 101*cdf32b93SJeremy L Thompson ctx->field_descriptions[ctx->num_fields].name = tmp; 102*cdf32b93SJeremy L Thompson } 103*cdf32b93SJeremy L Thompson { 104*cdf32b93SJeremy L Thompson size_t len = strlen(field_description); 105*cdf32b93SJeremy L Thompson char *tmp; 106*cdf32b93SJeremy L Thompson ierr = CeedCalloc(len + 1, &tmp); CeedChk(ierr); 107*cdf32b93SJeremy L Thompson memcpy(tmp, field_description, len+1); 108*cdf32b93SJeremy L Thompson ctx->field_descriptions[ctx->num_fields].description = tmp; 109*cdf32b93SJeremy L Thompson } 110*cdf32b93SJeremy L Thompson ctx->field_descriptions[ctx->num_fields].type = field_type; 111*cdf32b93SJeremy L Thompson ctx->field_descriptions[ctx->num_fields].offset = field_offset; 112*cdf32b93SJeremy L Thompson ctx->field_descriptions[ctx->num_fields].size = field_size; 113*cdf32b93SJeremy L Thompson ctx->num_fields++; 114*cdf32b93SJeremy L Thompson 115*cdf32b93SJeremy L Thompson return CEED_ERROR_SUCCESS; 116*cdf32b93SJeremy L Thompson } 117*cdf32b93SJeremy L Thompson 118*cdf32b93SJeremy L Thompson /** 119*cdf32b93SJeremy L Thompson @brief Set QFunctionContext field holding a double precision value 120*cdf32b93SJeremy L Thompson 121*cdf32b93SJeremy L Thompson @param ctx CeedQFunctionContext 122*cdf32b93SJeremy L Thompson @param field_name Name of field to set 123*cdf32b93SJeremy L Thompson @param field_type Type of field to set 124*cdf32b93SJeremy L Thompson @param value Value to set 125*cdf32b93SJeremy L Thompson 126*cdf32b93SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 127*cdf32b93SJeremy L Thompson 128*cdf32b93SJeremy L Thompson @ref User 129*cdf32b93SJeremy L Thompson **/ 130*cdf32b93SJeremy L Thompson int CeedQFunctionContextSetGeneric(CeedQFunctionContext ctx, 131*cdf32b93SJeremy L Thompson const char *field_name, 132*cdf32b93SJeremy L Thompson CeedContextFieldType field_type, void *value) { 133*cdf32b93SJeremy L Thompson int ierr; 134*cdf32b93SJeremy L Thompson 135*cdf32b93SJeremy L Thompson // Check field index 136*cdf32b93SJeremy L Thompson CeedInt field_index = -1; 137*cdf32b93SJeremy L Thompson ierr = CeedQFunctionContextGetFieldIndex(ctx, field_name, &field_index); 138*cdf32b93SJeremy L Thompson CeedChk(ierr); 139*cdf32b93SJeremy L Thompson if (field_index == -1) 140*cdf32b93SJeremy L Thompson // LCOV_EXCL_START 141*cdf32b93SJeremy L Thompson return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 142*cdf32b93SJeremy L Thompson "QFunctionContext field with name \"%s\" not registered", 143*cdf32b93SJeremy L Thompson field_name); 144*cdf32b93SJeremy L Thompson // LCOV_EXCL_STOP 145*cdf32b93SJeremy L Thompson 146*cdf32b93SJeremy L Thompson if (ctx->field_descriptions[field_index].type != field_type) 147*cdf32b93SJeremy L Thompson // LCOV_EXCL_START 148*cdf32b93SJeremy L Thompson return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 149*cdf32b93SJeremy L Thompson "QFunctionContext field with name \"%s\" registered as %s, " 150*cdf32b93SJeremy L Thompson "not registered as %s", field_name, 151*cdf32b93SJeremy L Thompson CeedContextFieldTypes[ctx->field_descriptions[field_index].type], 152*cdf32b93SJeremy L Thompson CeedContextFieldTypes[field_type]); 153*cdf32b93SJeremy L Thompson // LCOV_EXCL_STOP 154*cdf32b93SJeremy L Thompson 155*cdf32b93SJeremy L Thompson char *data; 156*cdf32b93SJeremy L Thompson ierr = CeedQFunctionContextGetData(ctx, CEED_MEM_HOST, &data); CeedChk(ierr); 157*cdf32b93SJeremy L Thompson memcpy(&data[ctx->field_descriptions[field_index].offset], value, 158*cdf32b93SJeremy L Thompson ctx->field_descriptions[field_index].size); 159*cdf32b93SJeremy L Thompson ierr = CeedQFunctionContextRestoreData(ctx, &data); CeedChk(ierr); 160*cdf32b93SJeremy L Thompson 161*cdf32b93SJeremy L Thompson return CEED_ERROR_SUCCESS; 162*cdf32b93SJeremy L Thompson } 163*cdf32b93SJeremy L Thompson 164*cdf32b93SJeremy L Thompson /// @} 165*cdf32b93SJeremy L Thompson 166*cdf32b93SJeremy L Thompson /// ---------------------------------------------------------------------------- 167777ff853SJeremy L Thompson /// CeedQFunctionContext Backend API 168777ff853SJeremy L Thompson /// ---------------------------------------------------------------------------- 169777ff853SJeremy L Thompson /// @addtogroup CeedQFunctionBackend 170777ff853SJeremy L Thompson /// @{ 171777ff853SJeremy L Thompson 172777ff853SJeremy L Thompson /** 173777ff853SJeremy L Thompson @brief Get the Ceed associated with a CeedQFunctionContext 174777ff853SJeremy L Thompson 175777ff853SJeremy L Thompson @param ctx CeedQFunctionContext 176777ff853SJeremy L Thompson @param[out] ceed Variable to store Ceed 177777ff853SJeremy L Thompson 178777ff853SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 179777ff853SJeremy L Thompson 180777ff853SJeremy L Thompson @ref Backend 181777ff853SJeremy L Thompson **/ 182777ff853SJeremy L Thompson int CeedQFunctionContextGetCeed(CeedQFunctionContext ctx, Ceed *ceed) { 183777ff853SJeremy L Thompson *ceed = ctx->ceed; 184e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 185777ff853SJeremy L Thompson } 186777ff853SJeremy L Thompson 187777ff853SJeremy L Thompson /** 1889c774eddSJeremy L Thompson @brief Check for valid data in a CeedQFunctionContext 1899c774eddSJeremy L Thompson 1909c774eddSJeremy L Thompson @param ctx CeedQFunctionContext to check validity 1919c774eddSJeremy L Thompson @param[out] has_valid_data Variable to store validity 1929c774eddSJeremy L Thompson 1939c774eddSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 1949c774eddSJeremy L Thompson 1959c774eddSJeremy L Thompson @ref Backend 1969c774eddSJeremy L Thompson **/ 1979c774eddSJeremy L Thompson int CeedQFunctionContextHasValidData(CeedQFunctionContext ctx, 1989c774eddSJeremy L Thompson bool *has_valid_data) { 1999c774eddSJeremy L Thompson int ierr; 2009c774eddSJeremy L Thompson 2019c774eddSJeremy L Thompson if (!ctx->HasValidData) 2029c774eddSJeremy L Thompson // LCOV_EXCL_START 2039c774eddSJeremy L Thompson return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 2049c774eddSJeremy L Thompson "Backend does not support HasValidData"); 2059c774eddSJeremy L Thompson // LCOV_EXCL_STOP 2069c774eddSJeremy L Thompson 2079c774eddSJeremy L Thompson ierr = ctx->HasValidData(ctx, has_valid_data); CeedChk(ierr); 2089c774eddSJeremy L Thompson 2099c774eddSJeremy L Thompson return CEED_ERROR_SUCCESS; 2109c774eddSJeremy L Thompson } 2119c774eddSJeremy L Thompson 2129c774eddSJeremy L Thompson /** 2139c774eddSJeremy L Thompson @brief Check for borrowed data of a specific CeedMemType in a 2149c774eddSJeremy L Thompson CeedQFunctionContext 2159c774eddSJeremy L Thompson 2169c774eddSJeremy L Thompson @param ctx CeedQFunctionContext to check 2179c774eddSJeremy L Thompson @param mem_type Memory type to check 2189c774eddSJeremy L Thompson @param[out] has_borrowed_data_of_type Variable to store result 2199c774eddSJeremy L Thompson 2209c774eddSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 2219c774eddSJeremy L Thompson 2229c774eddSJeremy L Thompson @ref Backend 2239c774eddSJeremy L Thompson **/ 2249c774eddSJeremy L Thompson int CeedQFunctionContextHasBorrowedDataOfType(CeedQFunctionContext ctx, 2259c774eddSJeremy L Thompson CeedMemType mem_type, bool *has_borrowed_data_of_type) { 2269c774eddSJeremy L Thompson int ierr; 2279c774eddSJeremy L Thompson 2289c774eddSJeremy L Thompson if (!ctx->HasBorrowedDataOfType) 2299c774eddSJeremy L Thompson // LCOV_EXCL_START 2309c774eddSJeremy L Thompson return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 2319c774eddSJeremy L Thompson "Backend does not support HasBorrowedDataOfType"); 2329c774eddSJeremy L Thompson // LCOV_EXCL_STOP 2339c774eddSJeremy L Thompson 2349c774eddSJeremy L Thompson ierr = ctx->HasBorrowedDataOfType(ctx, mem_type, has_borrowed_data_of_type); 2359c774eddSJeremy L Thompson CeedChk(ierr); 2369c774eddSJeremy L Thompson 2379c774eddSJeremy L Thompson return CEED_ERROR_SUCCESS; 2389c774eddSJeremy L Thompson } 2399c774eddSJeremy L Thompson 2409c774eddSJeremy L Thompson /** 241777ff853SJeremy L Thompson @brief Get the state of a CeedQFunctionContext 242777ff853SJeremy L Thompson 243777ff853SJeremy L Thompson @param ctx CeedQFunctionContext to retrieve state 244777ff853SJeremy L Thompson @param[out] state Variable to store state 245777ff853SJeremy L Thompson 246777ff853SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 247777ff853SJeremy L Thompson 248777ff853SJeremy L Thompson @ref Backend 249777ff853SJeremy L Thompson **/ 250777ff853SJeremy L Thompson int CeedQFunctionContextGetState(CeedQFunctionContext ctx, uint64_t *state) { 251777ff853SJeremy L Thompson *state = ctx->state; 252e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 253777ff853SJeremy L Thompson } 254777ff853SJeremy L Thompson 255777ff853SJeremy L Thompson /** 256777ff853SJeremy L Thompson @brief Get backend data of a CeedQFunctionContext 257777ff853SJeremy L Thompson 258777ff853SJeremy L Thompson @param ctx CeedQFunctionContext 259777ff853SJeremy L Thompson @param[out] data Variable to store data 260777ff853SJeremy L Thompson 261777ff853SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 262777ff853SJeremy L Thompson 263777ff853SJeremy L Thompson @ref Backend 264777ff853SJeremy L Thompson **/ 265777ff853SJeremy L Thompson int CeedQFunctionContextGetBackendData(CeedQFunctionContext ctx, void *data) { 266777ff853SJeremy L Thompson *(void **)data = ctx->data; 267e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 268777ff853SJeremy L Thompson } 269777ff853SJeremy L Thompson 270777ff853SJeremy L Thompson /** 271777ff853SJeremy L Thompson @brief Set backend data of a CeedQFunctionContext 272777ff853SJeremy L Thompson 273777ff853SJeremy L Thompson @param[out] ctx CeedQFunctionContext 274777ff853SJeremy L Thompson @param data Data to set 275777ff853SJeremy L Thompson 276777ff853SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 277777ff853SJeremy L Thompson 278777ff853SJeremy L Thompson @ref Backend 279777ff853SJeremy L Thompson **/ 280777ff853SJeremy L Thompson int CeedQFunctionContextSetBackendData(CeedQFunctionContext ctx, void *data) { 281777ff853SJeremy L Thompson ctx->data = data; 282e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 283777ff853SJeremy L Thompson } 284777ff853SJeremy L Thompson 28534359f16Sjeremylt /** 28634359f16Sjeremylt @brief Increment the reference counter for a CeedQFunctionContext 28734359f16Sjeremylt 28834359f16Sjeremylt @param ctx CeedQFunctionContext to increment the reference counter 28934359f16Sjeremylt 29034359f16Sjeremylt @return An error code: 0 - success, otherwise - failure 29134359f16Sjeremylt 29234359f16Sjeremylt @ref Backend 29334359f16Sjeremylt **/ 2949560d06aSjeremylt int CeedQFunctionContextReference(CeedQFunctionContext ctx) { 29534359f16Sjeremylt ctx->ref_count++; 29634359f16Sjeremylt return CEED_ERROR_SUCCESS; 29734359f16Sjeremylt } 29834359f16Sjeremylt 299777ff853SJeremy L Thompson /// @} 300777ff853SJeremy L Thompson 301777ff853SJeremy L Thompson /// ---------------------------------------------------------------------------- 302777ff853SJeremy L Thompson /// CeedQFunctionContext Public API 303777ff853SJeremy L Thompson /// ---------------------------------------------------------------------------- 304777ff853SJeremy L Thompson /// @addtogroup CeedQFunctionUser 305777ff853SJeremy L Thompson /// @{ 306777ff853SJeremy L Thompson 307777ff853SJeremy L Thompson /** 308777ff853SJeremy L Thompson @brief Create a CeedQFunctionContext for storing CeedQFunction user context data 309777ff853SJeremy L Thompson 310777ff853SJeremy L Thompson @param ceed A Ceed object where the CeedQFunctionContext will be created 311777ff853SJeremy L Thompson @param[out] ctx Address of the variable where the newly created 312777ff853SJeremy L Thompson CeedQFunctionContext will be stored 313777ff853SJeremy L Thompson 314777ff853SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 315777ff853SJeremy L Thompson 316777ff853SJeremy L Thompson @ref User 317777ff853SJeremy L Thompson **/ 318777ff853SJeremy L Thompson int CeedQFunctionContextCreate(Ceed ceed, CeedQFunctionContext *ctx) { 319777ff853SJeremy L Thompson int ierr; 320777ff853SJeremy L Thompson 321777ff853SJeremy L Thompson if (!ceed->QFunctionContextCreate) { 322777ff853SJeremy L Thompson Ceed delegate; 323777ff853SJeremy L Thompson ierr = CeedGetObjectDelegate(ceed, &delegate, "Context"); CeedChk(ierr); 324777ff853SJeremy L Thompson 325777ff853SJeremy L Thompson if (!delegate) 326777ff853SJeremy L Thompson // LCOV_EXCL_START 327e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 328e15f9bd0SJeremy L Thompson "Backend does not support ContextCreate"); 329777ff853SJeremy L Thompson // LCOV_EXCL_STOP 330777ff853SJeremy L Thompson 331777ff853SJeremy L Thompson ierr = CeedQFunctionContextCreate(delegate, ctx); CeedChk(ierr); 332e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 333777ff853SJeremy L Thompson } 334777ff853SJeremy L Thompson 335777ff853SJeremy L Thompson ierr = CeedCalloc(1, ctx); CeedChk(ierr); 336777ff853SJeremy L Thompson (*ctx)->ceed = ceed; 3379560d06aSjeremylt ierr = CeedReference(ceed); CeedChk(ierr); 338d1d35e2fSjeremylt (*ctx)->ref_count = 1; 339777ff853SJeremy L Thompson ierr = ceed->QFunctionContextCreate(*ctx); CeedChk(ierr); 340e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 341777ff853SJeremy L Thompson } 342777ff853SJeremy L Thompson 343777ff853SJeremy L Thompson /** 3449560d06aSjeremylt @brief Copy the pointer to a CeedQFunctionContext. Both pointers should 3459560d06aSjeremylt be destroyed with `CeedQFunctionContextDestroy()`; 3469560d06aSjeremylt Note: If `*ctx_copy` is non-NULL, then it is assumed that 3479560d06aSjeremylt `*ctx_copy` is a pointer to a CeedQFunctionContext. This 3489560d06aSjeremylt CeedQFunctionContext will be destroyed if `*ctx_copy` is the 3499560d06aSjeremylt only reference to this CeedQFunctionContext. 3509560d06aSjeremylt 3519560d06aSjeremylt @param ctx CeedQFunctionContext to copy reference to 3529560d06aSjeremylt @param[out] ctx_copy Variable to store copied reference 3539560d06aSjeremylt 3549560d06aSjeremylt @return An error code: 0 - success, otherwise - failure 3559560d06aSjeremylt 3569560d06aSjeremylt @ref User 3579560d06aSjeremylt **/ 3589560d06aSjeremylt int CeedQFunctionContextReferenceCopy(CeedQFunctionContext ctx, 3599560d06aSjeremylt CeedQFunctionContext *ctx_copy) { 3609560d06aSjeremylt int ierr; 3619560d06aSjeremylt 3629560d06aSjeremylt ierr = CeedQFunctionContextReference(ctx); CeedChk(ierr); 3639560d06aSjeremylt ierr = CeedQFunctionContextDestroy(ctx_copy); CeedChk(ierr); 3649560d06aSjeremylt *ctx_copy = ctx; 3659560d06aSjeremylt return CEED_ERROR_SUCCESS; 3669560d06aSjeremylt } 3679560d06aSjeremylt 3689560d06aSjeremylt /** 369777ff853SJeremy L Thompson @brief Set the data used by a CeedQFunctionContext, freeing any previously allocated 370777ff853SJeremy L Thompson data if applicable. The backend may copy values to a different 371777ff853SJeremy L Thompson memtype, such as during @ref CeedQFunctionApply(). 372777ff853SJeremy L Thompson See also @ref CeedQFunctionContextTakeData(). 373777ff853SJeremy L Thompson 374777ff853SJeremy L Thompson @param ctx CeedQFunctionContext 375d1d35e2fSjeremylt @param mem_type Memory type of the data being passed 376d1d35e2fSjeremylt @param copy_mode Copy mode for the data 377891038deSjeremylt @param size Size of data, in bytes 378777ff853SJeremy L Thompson @param data Data to be used 379777ff853SJeremy L Thompson 380777ff853SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 381777ff853SJeremy L Thompson 382777ff853SJeremy L Thompson @ref User 383777ff853SJeremy L Thompson **/ 384d1d35e2fSjeremylt int CeedQFunctionContextSetData(CeedQFunctionContext ctx, CeedMemType mem_type, 385d1d35e2fSjeremylt CeedCopyMode copy_mode, 386777ff853SJeremy L Thompson size_t size, void *data) { 387777ff853SJeremy L Thompson int ierr; 388777ff853SJeremy L Thompson 389777ff853SJeremy L Thompson if (!ctx->SetData) 390777ff853SJeremy L Thompson // LCOV_EXCL_START 391e15f9bd0SJeremy L Thompson return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 392e15f9bd0SJeremy L Thompson "Backend does not support ContextSetData"); 393777ff853SJeremy L Thompson // LCOV_EXCL_STOP 394777ff853SJeremy L Thompson 395777ff853SJeremy L Thompson if (ctx->state % 2 == 1) 396777ff853SJeremy L Thompson // LCOV_EXCL_START 397777ff853SJeremy L Thompson return CeedError(ctx->ceed, 1, 398777ff853SJeremy L Thompson "Cannot grant CeedQFunctionContext data access, the " 399777ff853SJeremy L Thompson "access lock is already in use"); 400777ff853SJeremy L Thompson // LCOV_EXCL_STOP 401777ff853SJeremy L Thompson 402d1d35e2fSjeremylt ctx->ctx_size = size; 403d1d35e2fSjeremylt ierr = ctx->SetData(ctx, mem_type, copy_mode, data); CeedChk(ierr); 404777ff853SJeremy L Thompson ctx->state += 2; 405e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 406777ff853SJeremy L Thompson } 407777ff853SJeremy L Thompson 408777ff853SJeremy L Thompson /** 409891038deSjeremylt @brief Take ownership of the data in a CeedQFunctionContext via the specified memory type. 410891038deSjeremylt The caller is responsible for managing and freeing the memory. 411891038deSjeremylt 412891038deSjeremylt @param ctx CeedQFunctionContext to access 413891038deSjeremylt @param mem_type Memory type on which to access the data. If the backend 414891038deSjeremylt uses a different memory type, this will perform a copy. 415891038deSjeremylt @param[out] data Data on memory type mem_type 416891038deSjeremylt 417891038deSjeremylt @return An error code: 0 - success, otherwise - failure 418891038deSjeremylt 419891038deSjeremylt @ref User 420891038deSjeremylt **/ 421891038deSjeremylt int CeedQFunctionContextTakeData(CeedQFunctionContext ctx, CeedMemType mem_type, 422891038deSjeremylt void *data) { 423891038deSjeremylt int ierr; 424891038deSjeremylt 4259c774eddSJeremy L Thompson bool has_valid_data = true; 4269c774eddSJeremy L Thompson ierr = CeedQFunctionContextHasValidData(ctx, &has_valid_data); CeedChk(ierr); 4279c774eddSJeremy L Thompson if (!has_valid_data) 4289c774eddSJeremy L Thompson // LCOV_EXCL_START 4299c774eddSJeremy L Thompson return CeedError(ctx->ceed, CEED_ERROR_BACKEND, 4309c774eddSJeremy L Thompson "CeedQFunctionContext has no valid data to take, must set data"); 4319c774eddSJeremy L Thompson // LCOV_EXCL_STOP 4329c774eddSJeremy L Thompson 433891038deSjeremylt if (!ctx->TakeData) 434891038deSjeremylt // LCOV_EXCL_START 435891038deSjeremylt return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 436891038deSjeremylt "Backend does not support TakeData"); 437891038deSjeremylt // LCOV_EXCL_STOP 438891038deSjeremylt 439891038deSjeremylt if (ctx->state % 2 == 1) 440891038deSjeremylt // LCOV_EXCL_START 441891038deSjeremylt return CeedError(ctx->ceed, 1, 442891038deSjeremylt "Cannot grant CeedQFunctionContext data access, the " 443891038deSjeremylt "access lock is already in use"); 444891038deSjeremylt // LCOV_EXCL_STOP 445891038deSjeremylt 4469c774eddSJeremy L Thompson bool has_borrowed_data_of_type = true; 4479c774eddSJeremy L Thompson ierr = CeedQFunctionContextHasBorrowedDataOfType(ctx, mem_type, 4489c774eddSJeremy L Thompson &has_borrowed_data_of_type); CeedChk(ierr); 4499c774eddSJeremy L Thompson if (!has_borrowed_data_of_type) 4509c774eddSJeremy L Thompson // LCOV_EXCL_START 4519c774eddSJeremy L Thompson return CeedError(ctx->ceed, CEED_ERROR_BACKEND, 4529c774eddSJeremy L Thompson "CeedQFunctionContext has no borowed %s data, " 4539c774eddSJeremy L Thompson "must set data with CeedQFunctionContextSetData", 4549c774eddSJeremy L Thompson CeedMemTypes[mem_type]); 4559c774eddSJeremy L Thompson // LCOV_EXCL_STOP 4569c774eddSJeremy L Thompson 457891038deSjeremylt void *temp_data = NULL; 458891038deSjeremylt ierr = ctx->TakeData(ctx, mem_type, &temp_data); CeedChk(ierr); 459891038deSjeremylt if (data) (*(void **)data) = temp_data; 460891038deSjeremylt return CEED_ERROR_SUCCESS; 461891038deSjeremylt } 462891038deSjeremylt 463891038deSjeremylt /** 464777ff853SJeremy L Thompson @brief Get read/write access to a CeedQFunctionContext via the specified memory type. 465777ff853SJeremy L Thompson Restore access with @ref CeedQFunctionContextRestoreData(). 466777ff853SJeremy L Thompson 467777ff853SJeremy L Thompson @param ctx CeedQFunctionContext to access 468d1d35e2fSjeremylt @param mem_type Memory type on which to access the data. If the backend 469777ff853SJeremy L Thompson uses a different memory type, this will perform a copy. 470d1d35e2fSjeremylt @param[out] data Data on memory type mem_type 471777ff853SJeremy L Thompson 472777ff853SJeremy L Thompson @note The CeedQFunctionContextGetData() and @ref CeedQFunctionContextRestoreData() functions 473777ff853SJeremy L Thompson provide access to array pointers in the desired memory space. Pairing 474777ff853SJeremy L Thompson get/restore allows the Context to track access. 475777ff853SJeremy L Thompson 476777ff853SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 477777ff853SJeremy L Thompson 478777ff853SJeremy L Thompson @ref User 479777ff853SJeremy L Thompson **/ 480d1d35e2fSjeremylt int CeedQFunctionContextGetData(CeedQFunctionContext ctx, CeedMemType mem_type, 481777ff853SJeremy L Thompson void *data) { 482777ff853SJeremy L Thompson int ierr; 483777ff853SJeremy L Thompson 484777ff853SJeremy L Thompson if (!ctx->GetData) 485777ff853SJeremy L Thompson // LCOV_EXCL_START 486e15f9bd0SJeremy L Thompson return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 487e15f9bd0SJeremy L Thompson "Backend does not support GetData"); 488777ff853SJeremy L Thompson // LCOV_EXCL_STOP 489777ff853SJeremy L Thompson 490777ff853SJeremy L Thompson if (ctx->state % 2 == 1) 491777ff853SJeremy L Thompson // LCOV_EXCL_START 492777ff853SJeremy L Thompson return CeedError(ctx->ceed, 1, 493777ff853SJeremy L Thompson "Cannot grant CeedQFunctionContext data access, the " 494777ff853SJeremy L Thompson "access lock is already in use"); 495777ff853SJeremy L Thompson // LCOV_EXCL_STOP 496777ff853SJeremy L Thompson 4979c774eddSJeremy L Thompson bool has_valid_data = true; 4989c774eddSJeremy L Thompson ierr = CeedQFunctionContextHasValidData(ctx, &has_valid_data); CeedChk(ierr); 4999c774eddSJeremy L Thompson if (!has_valid_data) 5009c774eddSJeremy L Thompson // LCOV_EXCL_START 5019c774eddSJeremy L Thompson return CeedError(ctx->ceed, CEED_ERROR_BACKEND, 5029c774eddSJeremy L Thompson "CeedQFunctionContext has no valid data to get, must set data"); 5039c774eddSJeremy L Thompson // LCOV_EXCL_STOP 5049c774eddSJeremy L Thompson 505d1d35e2fSjeremylt ierr = ctx->GetData(ctx, mem_type, data); CeedChk(ierr); 506777ff853SJeremy L Thompson ctx->state += 1; 507e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 508777ff853SJeremy L Thompson } 509777ff853SJeremy L Thompson 510777ff853SJeremy L Thompson /** 511777ff853SJeremy L Thompson @brief Restore data obtained using @ref CeedQFunctionContextGetData() 512777ff853SJeremy L Thompson 513777ff853SJeremy L Thompson @param ctx CeedQFunctionContext to restore 514777ff853SJeremy L Thompson @param data Data to restore 515777ff853SJeremy L Thompson 516777ff853SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 517777ff853SJeremy L Thompson 518777ff853SJeremy L Thompson @ref User 519777ff853SJeremy L Thompson **/ 520777ff853SJeremy L Thompson int CeedQFunctionContextRestoreData(CeedQFunctionContext ctx, void *data) { 521777ff853SJeremy L Thompson int ierr; 522777ff853SJeremy L Thompson 523777ff853SJeremy L Thompson if (!ctx->RestoreData) 524777ff853SJeremy L Thompson // LCOV_EXCL_START 525e15f9bd0SJeremy L Thompson return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 526e15f9bd0SJeremy L Thompson "Backend does not support RestoreData"); 527777ff853SJeremy L Thompson // LCOV_EXCL_STOP 528777ff853SJeremy L Thompson 529777ff853SJeremy L Thompson if (ctx->state % 2 != 1) 530777ff853SJeremy L Thompson // LCOV_EXCL_START 531777ff853SJeremy L Thompson return CeedError(ctx->ceed, 1, 532777ff853SJeremy L Thompson "Cannot restore CeedQFunctionContext array access, " 533777ff853SJeremy L Thompson "access was not granted"); 534777ff853SJeremy L Thompson // LCOV_EXCL_STOP 535777ff853SJeremy L Thompson 536777ff853SJeremy L Thompson ierr = ctx->RestoreData(ctx); CeedChk(ierr); 537777ff853SJeremy L Thompson *(void **)data = NULL; 538777ff853SJeremy L Thompson ctx->state += 1; 539e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 540777ff853SJeremy L Thompson } 541777ff853SJeremy L Thompson 542777ff853SJeremy L Thompson /** 543*cdf32b93SJeremy L Thompson @brief Register QFunctionContext a field holding a double precision value 544*cdf32b93SJeremy L Thompson 545*cdf32b93SJeremy L Thompson @param ctx CeedQFunctionContext 546*cdf32b93SJeremy L Thompson @param field_name Name of field to register 547*cdf32b93SJeremy L Thompson @param field_offset Offset of field to register 548*cdf32b93SJeremy L Thompson @param field_description Description of field, or NULL for none 549*cdf32b93SJeremy L Thompson 550*cdf32b93SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 551*cdf32b93SJeremy L Thompson 552*cdf32b93SJeremy L Thompson @ref User 553*cdf32b93SJeremy L Thompson **/ 554*cdf32b93SJeremy L Thompson int CeedQFunctionContextRegisterDouble(CeedQFunctionContext ctx, 555*cdf32b93SJeremy L Thompson const char *field_name, size_t field_offset, 556*cdf32b93SJeremy L Thompson const char *field_description) { 557*cdf32b93SJeremy L Thompson return CeedQFunctionContextRegisterGeneric(ctx, field_name, field_offset, 558*cdf32b93SJeremy L Thompson field_description, CEED_CONTEXT_FIELD_DOUBLE, sizeof(double)); 559*cdf32b93SJeremy L Thompson } 560*cdf32b93SJeremy L Thompson 561*cdf32b93SJeremy L Thompson /** 562*cdf32b93SJeremy L Thompson @brief Register QFunctionContext a field holding a int32 value 563*cdf32b93SJeremy L Thompson 564*cdf32b93SJeremy L Thompson @param ctx CeedQFunctionContext 565*cdf32b93SJeremy L Thompson @param field_name Name of field to register 566*cdf32b93SJeremy L Thompson @param field_offset Offset of field to register 567*cdf32b93SJeremy L Thompson @param field_description Description of field, or NULL for none 568*cdf32b93SJeremy L Thompson 569*cdf32b93SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 570*cdf32b93SJeremy L Thompson 571*cdf32b93SJeremy L Thompson @ref User 572*cdf32b93SJeremy L Thompson **/ 573*cdf32b93SJeremy L Thompson int CeedQFunctionContextRegisterInt32(CeedQFunctionContext ctx, 574*cdf32b93SJeremy L Thompson const char *field_name, size_t field_offset, 575*cdf32b93SJeremy L Thompson const char *field_description) { 576*cdf32b93SJeremy L Thompson return CeedQFunctionContextRegisterGeneric(ctx, field_name, field_offset, 577*cdf32b93SJeremy L Thompson field_description, CEED_CONTEXT_FIELD_INT32, sizeof(int)); 578*cdf32b93SJeremy L Thompson } 579*cdf32b93SJeremy L Thompson 580*cdf32b93SJeremy L Thompson /** 581*cdf32b93SJeremy L Thompson @brief Get descriptions for registered QFunctionContext fields 582*cdf32b93SJeremy L Thompson 583*cdf32b93SJeremy L Thompson @param ctx CeedQFunctionContext 584*cdf32b93SJeremy L Thompson @param[out] field_descriptions Variable to hold array of field descriptions 585*cdf32b93SJeremy L Thompson @param[out] num_fields Length of field descriptions array 586*cdf32b93SJeremy L Thompson 587*cdf32b93SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 588*cdf32b93SJeremy L Thompson 589*cdf32b93SJeremy L Thompson @ref User 590*cdf32b93SJeremy L Thompson **/ 591*cdf32b93SJeremy L Thompson int CeedQFunctionContextGetFieldDescriptions(CeedQFunctionContext ctx, 592*cdf32b93SJeremy L Thompson const CeedQFunctionContextFieldDescription **field_descriptions, 593*cdf32b93SJeremy L Thompson CeedInt *num_fields) { 594*cdf32b93SJeremy L Thompson *field_descriptions = ctx->field_descriptions; 595*cdf32b93SJeremy L Thompson *num_fields = ctx->num_fields; 596*cdf32b93SJeremy L Thompson return CEED_ERROR_SUCCESS; 597*cdf32b93SJeremy L Thompson } 598*cdf32b93SJeremy L Thompson 599*cdf32b93SJeremy L Thompson /** 600*cdf32b93SJeremy L Thompson @brief Set QFunctionContext field holding a double precision value 601*cdf32b93SJeremy L Thompson 602*cdf32b93SJeremy L Thompson @param ctx CeedQFunctionContext 603*cdf32b93SJeremy L Thompson @param field_name Name of field to register 604*cdf32b93SJeremy L Thompson @param value Value to set 605*cdf32b93SJeremy L Thompson 606*cdf32b93SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 607*cdf32b93SJeremy L Thompson 608*cdf32b93SJeremy L Thompson @ref User 609*cdf32b93SJeremy L Thompson **/ 610*cdf32b93SJeremy L Thompson int CeedQFunctionContextSetDouble(CeedQFunctionContext ctx, 611*cdf32b93SJeremy L Thompson const char *field_name, double value) { 612*cdf32b93SJeremy L Thompson return CeedQFunctionContextSetGeneric(ctx, field_name, 613*cdf32b93SJeremy L Thompson CEED_CONTEXT_FIELD_DOUBLE, 614*cdf32b93SJeremy L Thompson &value); 615*cdf32b93SJeremy L Thompson } 616*cdf32b93SJeremy L Thompson 617*cdf32b93SJeremy L Thompson /** 618*cdf32b93SJeremy L Thompson @brief Set QFunctionContext field holding a int32 value 619*cdf32b93SJeremy L Thompson 620*cdf32b93SJeremy L Thompson @param ctx CeedQFunctionContext 621*cdf32b93SJeremy L Thompson @param field_name Name of field to set 622*cdf32b93SJeremy L Thompson @param value Value to set 623*cdf32b93SJeremy L Thompson 624*cdf32b93SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 625*cdf32b93SJeremy L Thompson 626*cdf32b93SJeremy L Thompson @ref User 627*cdf32b93SJeremy L Thompson **/ 628*cdf32b93SJeremy L Thompson int CeedQFunctionContextSetInt32(CeedQFunctionContext ctx, 629*cdf32b93SJeremy L Thompson const char *field_name, int value) { 630*cdf32b93SJeremy L Thompson return CeedQFunctionContextSetGeneric(ctx, field_name, CEED_CONTEXT_FIELD_INT32, 631*cdf32b93SJeremy L Thompson &value); 632*cdf32b93SJeremy L Thompson } 633*cdf32b93SJeremy L Thompson 634*cdf32b93SJeremy L Thompson /** 63580a9ef05SNatalie Beams @brief Get data size for a Context 63680a9ef05SNatalie Beams 63780a9ef05SNatalie Beams @param ctx CeedQFunctionContext 63880a9ef05SNatalie Beams @param[out] ctx_size Variable to store size of context data values 63980a9ef05SNatalie Beams 64080a9ef05SNatalie Beams @return An error code: 0 - success, otherwise - failure 64180a9ef05SNatalie Beams 64280a9ef05SNatalie Beams @ref User 64380a9ef05SNatalie Beams **/ 64480a9ef05SNatalie Beams int CeedQFunctionContextGetContextSize(CeedQFunctionContext ctx, 64580a9ef05SNatalie Beams size_t *ctx_size) { 64680a9ef05SNatalie Beams *ctx_size = ctx->ctx_size; 64780a9ef05SNatalie Beams return CEED_ERROR_SUCCESS; 64880a9ef05SNatalie Beams } 64980a9ef05SNatalie Beams 65080a9ef05SNatalie Beams 65180a9ef05SNatalie Beams /** 652777ff853SJeremy L Thompson @brief View a CeedQFunctionContext 653777ff853SJeremy L Thompson 654777ff853SJeremy L Thompson @param[in] ctx CeedQFunctionContext to view 655777ff853SJeremy L Thompson @param[in] stream Filestream to write to 656777ff853SJeremy L Thompson 657777ff853SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 658777ff853SJeremy L Thompson 659777ff853SJeremy L Thompson @ref User 660777ff853SJeremy L Thompson **/ 661777ff853SJeremy L Thompson int CeedQFunctionContextView(CeedQFunctionContext ctx, FILE *stream) { 662777ff853SJeremy L Thompson fprintf(stream, "CeedQFunctionContext\n"); 663d1d35e2fSjeremylt fprintf(stream, " Context Data Size: %ld\n", ctx->ctx_size); 664e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 665777ff853SJeremy L Thompson } 666777ff853SJeremy L Thompson 667777ff853SJeremy L Thompson /** 668777ff853SJeremy L Thompson @brief Destroy a CeedQFunctionContext 669777ff853SJeremy L Thompson 670777ff853SJeremy L Thompson @param ctx CeedQFunctionContext to destroy 671777ff853SJeremy L Thompson 672777ff853SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 673777ff853SJeremy L Thompson 674777ff853SJeremy L Thompson @ref User 675777ff853SJeremy L Thompson **/ 676777ff853SJeremy L Thompson int CeedQFunctionContextDestroy(CeedQFunctionContext *ctx) { 677777ff853SJeremy L Thompson int ierr; 678777ff853SJeremy L Thompson 679d1d35e2fSjeremylt if (!*ctx || --(*ctx)->ref_count > 0) 680e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 681777ff853SJeremy L Thompson 682777ff853SJeremy L Thompson if ((*ctx) && ((*ctx)->state % 2) == 1) 683777ff853SJeremy L Thompson // LCOV_EXCL_START 684777ff853SJeremy L Thompson return CeedError((*ctx)->ceed, 1, 685777ff853SJeremy L Thompson "Cannot destroy CeedQFunctionContext, the access " 686777ff853SJeremy L Thompson "lock is in use"); 687777ff853SJeremy L Thompson // LCOV_EXCL_STOP 688777ff853SJeremy L Thompson 689777ff853SJeremy L Thompson if ((*ctx)->Destroy) { 690777ff853SJeremy L Thompson ierr = (*ctx)->Destroy(*ctx); CeedChk(ierr); 691777ff853SJeremy L Thompson } 692*cdf32b93SJeremy L Thompson for (CeedInt i=0; i<(*ctx)->num_fields; i++) { 693*cdf32b93SJeremy L Thompson ierr = CeedFree(&(*ctx)->field_descriptions[i].name); CeedChk(ierr); 694*cdf32b93SJeremy L Thompson ierr = CeedFree(&(*ctx)->field_descriptions[i].description); CeedChk(ierr); 695*cdf32b93SJeremy L Thompson } 696*cdf32b93SJeremy L Thompson ierr = CeedFree(&(*ctx)->field_descriptions); CeedChk(ierr); 697777ff853SJeremy L Thompson ierr = CeedDestroy(&(*ctx)->ceed); CeedChk(ierr); 698777ff853SJeremy L Thompson ierr = CeedFree(ctx); CeedChk(ierr); 699*cdf32b93SJeremy L Thompson 700e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 701777ff853SJeremy L Thompson } 702777ff853SJeremy L Thompson 703777ff853SJeremy L Thompson /// @} 704