1 // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3 // 4 // SPDX-License-Identifier: BSD-2-Clause 5 // 6 // This file is part of CEED: http://github.com/ceed 7 8 #include <ceed-impl.h> 9 #include <ceed.h> 10 #include <ceed/backend.h> 11 #include <stdbool.h> 12 #include <stdio.h> 13 #include <string.h> 14 15 /// @file 16 /// Implementation of CeedElemRestriction interfaces 17 18 /// ---------------------------------------------------------------------------- 19 /// CeedElemRestriction Library Internal Functions 20 /// ---------------------------------------------------------------------------- 21 /// @addtogroup CeedElemRestrictionDeveloper 22 /// @{ 23 24 /** 25 @brief Permute and pad offsets for a blocked restriction 26 27 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 28 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 29 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. 30 @param[out] blk_offsets Array of permuted and padded offsets of shape [@a num_blk, @a elem_size, @a blk_size]. 31 @param[in] num_blk Number of blocks 32 @param[in] num_elem Number of elements 33 @param[in] blk_size Number of elements in a block 34 @param[in] elem_size Size of each element 35 36 @return An error code: 0 - success, otherwise - failure 37 38 @ref Utility 39 **/ 40 int CeedPermutePadOffsets(const CeedInt *offsets, CeedInt *blk_offsets, CeedInt num_blk, CeedInt num_elem, CeedInt blk_size, CeedInt elem_size) { 41 for (CeedInt e = 0; e < num_blk * blk_size; e += blk_size) { 42 for (CeedInt j = 0; j < blk_size; j++) { 43 for (CeedInt k = 0; k < elem_size; k++) { 44 blk_offsets[e * elem_size + k * blk_size + j] = offsets[CeedIntMin(e + j, num_elem - 1) * elem_size + k]; 45 } 46 } 47 } 48 return CEED_ERROR_SUCCESS; 49 } 50 51 /// @} 52 53 /// ---------------------------------------------------------------------------- 54 /// CeedElemRestriction Backend API 55 /// ---------------------------------------------------------------------------- 56 /// @addtogroup CeedElemRestrictionBackend 57 /// @{ 58 59 /** 60 @brief Restrict an L-vector to an E-vector or apply its transpose ignoring any 61 provided orientations 62 63 @param[in] rstr CeedElemRestriction 64 @param[in] t_mode Apply restriction or transpose 65 @param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 66 @param[out] ru Output vector (of shape [@a num_elem * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). 67 Ordering of the e-vector is decided by the backend. 68 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 69 70 @return An error code: 0 - success, otherwise - failure 71 72 @ref User 73 **/ 74 int CeedElemRestrictionApplyUnsigned(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) { 75 CeedInt m, n; 76 77 CeedCheck(rstr->ApplyUnsigned, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ElemRestrictionApplyUnsigned"); 78 79 if (t_mode == CEED_NOTRANSPOSE) { 80 m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 81 n = rstr->l_size; 82 } else { 83 m = rstr->l_size; 84 n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 85 } 86 CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION, 87 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n); 88 CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION, 89 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n); 90 if (rstr->num_elem > 0) CeedCall(rstr->ApplyUnsigned(rstr, t_mode, u, ru, request)); 91 return CEED_ERROR_SUCCESS; 92 } 93 94 /** 95 96 @brief Get the strides of a strided CeedElemRestriction 97 98 @param[in] rstr CeedElemRestriction 99 @param[out] strides Variable to store strides array 100 101 @return An error code: 0 - success, otherwise - failure 102 103 @ref Backend 104 **/ 105 int CeedElemRestrictionGetStrides(CeedElemRestriction rstr, CeedInt (*strides)[3]) { 106 CeedCheck(rstr->strides, rstr->ceed, CEED_ERROR_MINOR, "ElemRestriction has no stride data"); 107 for (CeedInt i = 0; i < 3; i++) (*strides)[i] = rstr->strides[i]; 108 return CEED_ERROR_SUCCESS; 109 } 110 111 /** 112 @brief Get read-only access to a CeedElemRestriction offsets array by memtype 113 114 @param[in] rstr CeedElemRestriction to retrieve offsets 115 @param[in] mem_type Memory type on which to access the array. 116 If the backend uses a different memory type, this will perform a copy (possibly cached). 117 @param[out] offsets Array on memory type mem_type 118 119 @return An error code: 0 - success, otherwise - failure 120 121 @ref User 122 **/ 123 int CeedElemRestrictionGetOffsets(CeedElemRestriction rstr, CeedMemType mem_type, const CeedInt **offsets) { 124 if (rstr->rstr_signed) { 125 CeedCall(CeedElemRestrictionGetOffsets(rstr->rstr_signed, mem_type, offsets)); 126 } else { 127 CeedCheck(rstr->GetOffsets, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetOffsets"); 128 CeedCall(rstr->GetOffsets(rstr, mem_type, offsets)); 129 rstr->num_readers++; 130 } 131 return CEED_ERROR_SUCCESS; 132 } 133 134 /** 135 @brief Restore an offsets array obtained using CeedElemRestrictionGetOffsets() 136 137 @param[in] rstr CeedElemRestriction to restore 138 @param[in] offsets Array of offset data 139 140 @return An error code: 0 - success, otherwise - failure 141 142 @ref User 143 **/ 144 int CeedElemRestrictionRestoreOffsets(CeedElemRestriction rstr, const CeedInt **offsets) { 145 if (rstr->rstr_signed) { 146 CeedCall(CeedElemRestrictionRestoreOffsets(rstr->rstr_signed, offsets)); 147 } else { 148 *offsets = NULL; 149 rstr->num_readers--; 150 } 151 return CEED_ERROR_SUCCESS; 152 } 153 154 /** 155 @brief Get the strided status of a CeedElemRestriction 156 157 @param[in] rstr CeedElemRestriction 158 @param[out] is_strided Variable to store strided status, 1 if strided else 0 159 160 @return An error code: 0 - success, otherwise - failure 161 162 @ref Backend 163 **/ 164 int CeedElemRestrictionIsStrided(CeedElemRestriction rstr, bool *is_strided) { 165 *is_strided = rstr->strides ? true : false; 166 return CEED_ERROR_SUCCESS; 167 } 168 169 /** 170 @brief Get oriented status of a CeedElemRestriction 171 172 @param[in] rstr CeedElemRestriction 173 @param[out] is_oriented Variable to store oriented status, 1 if oriented else 0 174 175 @return An error code: 0 - success, otherwise - failure 176 177 @ref Backend 178 **/ 179 int CeedElemRestrictionIsOriented(CeedElemRestriction rstr, bool *is_oriented) { 180 *is_oriented = rstr->is_oriented; 181 return CEED_ERROR_SUCCESS; 182 } 183 184 /** 185 @brief Get the backend stride status of a CeedElemRestriction 186 187 @param[in] rstr CeedElemRestriction 188 @param[out] has_backend_strides Variable to store stride status 189 190 @return An error code: 0 - success, otherwise - failure 191 192 @ref Backend 193 **/ 194 int CeedElemRestrictionHasBackendStrides(CeedElemRestriction rstr, bool *has_backend_strides) { 195 CeedCheck(rstr->strides, rstr->ceed, CEED_ERROR_MINOR, "ElemRestriction has no stride data"); 196 *has_backend_strides = ((rstr->strides[0] == CEED_STRIDES_BACKEND[0]) && (rstr->strides[1] == CEED_STRIDES_BACKEND[1]) && 197 (rstr->strides[2] == CEED_STRIDES_BACKEND[2])); 198 return CEED_ERROR_SUCCESS; 199 } 200 201 /** 202 203 @brief Get the E-vector layout of a CeedElemRestriction 204 205 @param[in] rstr CeedElemRestriction 206 @param[out] layout Variable to store layout array, stored as [nodes, components, elements]. 207 The data for node i, component j, element k in the E-vector is given by i*layout[0] + j*layout[1] + k*layout[2] 208 209 @return An error code: 0 - success, otherwise - failure 210 211 @ref Backend 212 **/ 213 int CeedElemRestrictionGetELayout(CeedElemRestriction rstr, CeedInt (*layout)[3]) { 214 CeedCheck(rstr->layout[0], rstr->ceed, CEED_ERROR_MINOR, "ElemRestriction has no layout data"); 215 for (CeedInt i = 0; i < 3; i++) (*layout)[i] = rstr->layout[i]; 216 return CEED_ERROR_SUCCESS; 217 } 218 219 /** 220 221 @brief Set the E-vector layout of a CeedElemRestriction 222 223 @param[in] rstr CeedElemRestriction 224 @param[in] layout Variable to containing layout array, stored as [nodes, components, elements]. 225 The data for node i, component j, element k in the E-vector is given by i*layout[0] + j*layout[1] + k*layout[2] 226 227 @return An error code: 0 - success, otherwise - failure 228 229 @ref Backend 230 **/ 231 int CeedElemRestrictionSetELayout(CeedElemRestriction rstr, CeedInt layout[3]) { 232 for (CeedInt i = 0; i < 3; i++) rstr->layout[i] = layout[i]; 233 return CEED_ERROR_SUCCESS; 234 } 235 236 /** 237 @brief Get the backend data of a CeedElemRestriction 238 239 @param[in] rstr CeedElemRestriction 240 @param[out] data Variable to store data 241 242 @return An error code: 0 - success, otherwise - failure 243 244 @ref Backend 245 **/ 246 int CeedElemRestrictionGetData(CeedElemRestriction rstr, void *data) { 247 *(void **)data = rstr->data; 248 return CEED_ERROR_SUCCESS; 249 } 250 251 /** 252 @brief Set the backend data of a CeedElemRestriction 253 254 @param[in,out] rstr CeedElemRestriction 255 @param[in] data Data to set 256 257 @return An error code: 0 - success, otherwise - failure 258 259 @ref Backend 260 **/ 261 int CeedElemRestrictionSetData(CeedElemRestriction rstr, void *data) { 262 rstr->data = data; 263 return CEED_ERROR_SUCCESS; 264 } 265 266 /** 267 @brief Increment the reference counter for a CeedElemRestriction 268 269 @param[in,out] rstr ElemRestriction to increment the reference counter 270 271 @return An error code: 0 - success, otherwise - failure 272 273 @ref Backend 274 **/ 275 int CeedElemRestrictionReference(CeedElemRestriction rstr) { 276 rstr->ref_count++; 277 return CEED_ERROR_SUCCESS; 278 } 279 280 /** 281 @brief Estimate number of FLOPs required to apply CeedElemRestriction in t_mode 282 283 @param[in] rstr ElemRestriction to estimate FLOPs for 284 @param[in] t_mode Apply restriction or transpose 285 @param[out] flops Address of variable to hold FLOPs estimate 286 287 @ref Backend 288 **/ 289 int CeedElemRestrictionGetFlopsEstimate(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedSize *flops) { 290 bool is_oriented; 291 CeedInt e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp, scale = 0; 292 293 CeedCall(CeedElemRestrictionIsOriented(rstr, &is_oriented)); 294 switch (t_mode) { 295 case CEED_NOTRANSPOSE: 296 scale = is_oriented ? 1 : 0; 297 break; 298 case CEED_TRANSPOSE: 299 scale = is_oriented ? 2 : 1; 300 break; 301 } 302 *flops = e_size * scale; 303 304 return CEED_ERROR_SUCCESS; 305 } 306 307 /// @} 308 309 /// @cond DOXYGEN_SKIP 310 static struct CeedElemRestriction_private ceed_elemrestriction_none; 311 /// @endcond 312 313 /// ---------------------------------------------------------------------------- 314 /// CeedElemRestriction Public API 315 /// ---------------------------------------------------------------------------- 316 /// @addtogroup CeedElemRestrictionUser 317 /// @{ 318 319 /// Indicate that the stride is determined by the backend 320 const CeedInt CEED_STRIDES_BACKEND[3] = {0}; 321 322 /// Indicate that no CeedElemRestriction is provided by the user 323 const CeedElemRestriction CEED_ELEMRESTRICTION_NONE = &ceed_elemrestriction_none; 324 325 /** 326 @brief Create a CeedElemRestriction 327 328 @param[in] ceed Ceed object where the CeedElemRestriction will be created 329 @param[in] num_elem Number of elements described in the @a offsets array 330 @param[in] elem_size Size (number of "nodes") per element 331 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 332 @param[in] comp_stride Stride between components for the same L-vector "node". 333 Data for node i, component j, element k can be found in the L-vector at index offsets[i + k*elem_size] + j*comp_stride. 334 @param[in] l_size The size of the L-vector. 335 This vector may be larger than the elements and fields given by this restriction. 336 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 337 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 338 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 339 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 340 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. 341 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 342 343 @return An error code: 0 - success, otherwise - failure 344 345 @ref User 346 **/ 347 int CeedElemRestrictionCreate(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 348 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, CeedElemRestriction *rstr) { 349 if (!ceed->ElemRestrictionCreate) { 350 Ceed delegate; 351 352 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 353 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ElemRestrictionCreate"); 354 CeedCall(CeedElemRestrictionCreate(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr)); 355 return CEED_ERROR_SUCCESS; 356 } 357 358 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 359 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 360 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 361 362 CeedCall(CeedCalloc(1, rstr)); 363 (*rstr)->ceed = ceed; 364 CeedCall(CeedReference(ceed)); 365 (*rstr)->ref_count = 1; 366 (*rstr)->num_elem = num_elem; 367 (*rstr)->elem_size = elem_size; 368 (*rstr)->num_comp = num_comp; 369 (*rstr)->comp_stride = comp_stride; 370 (*rstr)->l_size = l_size; 371 (*rstr)->num_blk = num_elem; 372 (*rstr)->blk_size = 1; 373 (*rstr)->is_oriented = false; 374 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, *rstr)); 375 return CEED_ERROR_SUCCESS; 376 } 377 378 /** 379 @brief Create a CeedElemRestriction with orientation sign 380 381 @param[in] ceed Ceed object where the CeedElemRestriction will be created 382 @param[in] num_elem Number of elements described in the @a offsets array 383 @param[in] elem_size Size (number of "nodes") per element 384 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 385 @param[in] comp_stride Stride between components for the same L-vector "node". 386 Data for node i, component j, element k can be found in the L-vector at index offsets[i + k*elem_size] + j*comp_stride. 387 @param[in] l_size The size of the L-vector. 388 This vector may be larger than the elements and fields given by this restriction. 389 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 390 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 391 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 392 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 393 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. 394 @param[in] orient Array of shape [@a num_elem, @a elem_size] with bool false for positively oriented and true to flip the orientation. 395 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 396 397 @return An error code: 0 - success, otherwise - failure 398 399 @ref User 400 **/ 401 int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 402 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const bool *orient, 403 CeedElemRestriction *rstr) { 404 if (!ceed->ElemRestrictionCreateOriented) { 405 Ceed delegate; 406 407 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 408 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateOriented"); 409 CeedCall( 410 CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, orient, rstr)); 411 return CEED_ERROR_SUCCESS; 412 } 413 414 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 415 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 416 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 417 418 CeedCall(CeedCalloc(1, rstr)); 419 (*rstr)->ceed = ceed; 420 CeedCall(CeedReference(ceed)); 421 (*rstr)->ref_count = 1; 422 (*rstr)->num_elem = num_elem; 423 (*rstr)->elem_size = elem_size; 424 (*rstr)->num_comp = num_comp; 425 (*rstr)->comp_stride = comp_stride; 426 (*rstr)->l_size = l_size; 427 (*rstr)->num_blk = num_elem; 428 (*rstr)->blk_size = 1; 429 (*rstr)->is_oriented = true; 430 CeedCall(ceed->ElemRestrictionCreateOriented(mem_type, copy_mode, offsets, orient, *rstr)); 431 return CEED_ERROR_SUCCESS; 432 } 433 434 /** 435 @brief Create a strided CeedElemRestriction 436 437 @param[in] ceed Ceed object where the CeedElemRestriction will be created 438 @param[in] num_elem Number of elements described by the restriction 439 @param[in] elem_size Size (number of "nodes") per element 440 @param[in] num_comp Number of field components per interpolation "node" (1 for scalar fields) 441 @param[in] l_size The size of the L-vector. 442 This vector may be larger than the elements and fields given by this restriction. 443 @param[in] strides Array for strides between [nodes, components, elements]. 444 Data for node i, component j, element k can be found in the L-vector at index i*strides[0] + j*strides[1] + k*strides[2]. 445 @a CEED_STRIDES_BACKEND may be used with vectors created by a Ceed backend. 446 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 447 448 @return An error code: 0 - success, otherwise - failure 449 450 @ref User 451 **/ 452 int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedSize l_size, const CeedInt strides[3], 453 CeedElemRestriction *rstr) { 454 if (!ceed->ElemRestrictionCreate) { 455 Ceed delegate; 456 457 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 458 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ElemRestrictionCreateStrided"); 459 CeedCall(CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp, l_size, strides, rstr)); 460 return CEED_ERROR_SUCCESS; 461 } 462 463 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 464 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 465 466 CeedCall(CeedCalloc(1, rstr)); 467 (*rstr)->ceed = ceed; 468 CeedCall(CeedReference(ceed)); 469 (*rstr)->ref_count = 1; 470 (*rstr)->num_elem = num_elem; 471 (*rstr)->elem_size = elem_size; 472 (*rstr)->num_comp = num_comp; 473 (*rstr)->l_size = l_size; 474 (*rstr)->num_blk = num_elem; 475 (*rstr)->blk_size = 1; 476 (*rstr)->is_oriented = false; 477 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 478 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 479 CeedCall(ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, *rstr)); 480 return CEED_ERROR_SUCCESS; 481 } 482 483 /** 484 @brief Create a blocked CeedElemRestriction, typically only called by backends 485 486 @param[in] ceed Ceed object where the CeedElemRestriction will be created. 487 @param[in] num_elem Number of elements described in the @a offsets array. 488 @param[in] elem_size Size (number of unknowns) per element 489 @param[in] blk_size Number of elements in a block 490 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 491 @param[in] comp_stride Stride between components for the same L-vector "node". 492 Data for node i, component j, element k can be found in the L-vector at index offsets[i + k*elem_size] + j*comp_stride. 493 @param[in] l_size The size of the L-vector. 494 This vector may be larger than the elements and fields given by this restriction. 495 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 496 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 497 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 498 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 499 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. The backend will permute and pad this array to the desired ordering for 500 the blocksize, which is typically given by the backend. The default reordering is to interlace elements. 501 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 502 503 @return An error code: 0 - success, otherwise - failure 504 505 @ref Backend 506 **/ 507 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedInt comp_stride, 508 CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, 509 CeedElemRestriction *rstr) { 510 CeedInt *blk_offsets; 511 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 512 513 if (!ceed->ElemRestrictionCreateBlocked) { 514 Ceed delegate; 515 516 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 517 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlocked"); 518 CeedCall( 519 CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, blk_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr)); 520 return CEED_ERROR_SUCCESS; 521 } 522 523 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 524 CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 525 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 526 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 527 528 CeedCall(CeedCalloc(1, rstr)); 529 530 CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_offsets)); 531 CeedCall(CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size, elem_size)); 532 533 (*rstr)->ceed = ceed; 534 CeedCall(CeedReference(ceed)); 535 (*rstr)->ref_count = 1; 536 (*rstr)->num_elem = num_elem; 537 (*rstr)->elem_size = elem_size; 538 (*rstr)->num_comp = num_comp; 539 (*rstr)->comp_stride = comp_stride; 540 (*rstr)->l_size = l_size; 541 (*rstr)->num_blk = num_blk; 542 (*rstr)->blk_size = blk_size; 543 (*rstr)->is_oriented = false; 544 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)blk_offsets, *rstr)); 545 if (copy_mode == CEED_OWN_POINTER) { 546 CeedCall(CeedFree(&offsets)); 547 } 548 return CEED_ERROR_SUCCESS; 549 } 550 551 /** 552 @brief Create a blocked strided CeedElemRestriction 553 554 @param[in] ceed Ceed object where the CeedElemRestriction will be created 555 @param[in] num_elem Number of elements described by the restriction 556 @param[in] elem_size Size (number of "nodes") per element 557 @param[in] blk_size Number of elements in a block 558 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 559 @param[in] l_size The size of the L-vector. 560 This vector may be larger than the elements and fields given by this restriction. 561 @param[in] strides Array for strides between [nodes, components, elements]. 562 Data for node i, component j, element k can be found in the L-vector at index i*strides[0] + j*strides[1] + k*strides[2]. 563 @a CEED_STRIDES_BACKEND may be used with vectors created by a Ceed backend. 564 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 565 566 @return An error code: 0 - success, otherwise - failure 567 568 @ref User 569 **/ 570 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedSize l_size, 571 const CeedInt strides[3], CeedElemRestriction *rstr) { 572 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 573 574 if (!ceed->ElemRestrictionCreateBlocked) { 575 Ceed delegate; 576 577 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 578 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlockedStrided"); 579 CeedCall(CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size, blk_size, num_comp, l_size, strides, rstr)); 580 return CEED_ERROR_SUCCESS; 581 } 582 583 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 584 CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 585 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 586 587 CeedCall(CeedCalloc(1, rstr)); 588 589 (*rstr)->ceed = ceed; 590 CeedCall(CeedReference(ceed)); 591 (*rstr)->ref_count = 1; 592 (*rstr)->num_elem = num_elem; 593 (*rstr)->elem_size = elem_size; 594 (*rstr)->num_comp = num_comp; 595 (*rstr)->l_size = l_size; 596 (*rstr)->num_blk = num_blk; 597 (*rstr)->blk_size = blk_size; 598 (*rstr)->is_oriented = false; 599 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 600 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 601 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, *rstr)); 602 return CEED_ERROR_SUCCESS; 603 } 604 605 /** 606 @brief Copy the pointer to a CeedElemRestriction and set `CeedElemRestrictionApply()` implementation to `CeedElemRestrictionApplyUnsigned()`. 607 608 Both pointers should be destroyed with `CeedElemRestrictionDestroy()`. 609 610 @param[in] rstr CeedElemRestriction to create unsigned reference to 611 @param[in,out] rstr_unsigned Variable to store unsigned CeedElemRestriction 612 613 @return An error code: 0 - success, otherwise - failure 614 615 @ref User 616 **/ 617 int CeedElemRestrictionCreateUnsignedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unsigned) { 618 CeedCall(CeedCalloc(1, rstr_unsigned)); 619 620 // Copy old rstr 621 memcpy(*rstr_unsigned, rstr, sizeof(struct CeedElemRestriction_private)); 622 (*rstr_unsigned)->ceed = NULL; 623 CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unsigned)->ceed)); 624 (*rstr_unsigned)->ref_count = 1; 625 (*rstr_unsigned)->strides = NULL; 626 if (rstr->strides) { 627 CeedCall(CeedMalloc(3, &(*rstr_unsigned)->strides)); 628 for (CeedInt i = 0; i < 3; i++) (*rstr_unsigned)->strides[i] = rstr->strides[i]; 629 } 630 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unsigned)->rstr_signed)); 631 632 // Override Apply 633 (*rstr_unsigned)->Apply = rstr->ApplyUnsigned; 634 635 return CEED_ERROR_SUCCESS; 636 } 637 638 /** 639 @brief Copy the pointer to a CeedElemRestriction. 640 641 Both pointers should be destroyed with `CeedElemRestrictionDestroy()`. 642 643 Note: If the value of `rstr_copy` passed into this function is non-NULL, then it is assumed that `rstr_copy` is a pointer to a CeedElemRestriction. 644 This CeedElemRestriction will be destroyed if `rstr_copy` is the only reference to this CeedElemRestriction. 645 646 @param[in] rstr CeedElemRestriction to copy reference to 647 @param[in,out] rstr_copy Variable to store copied reference 648 649 @return An error code: 0 - success, otherwise - failure 650 651 @ref User 652 **/ 653 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_copy) { 654 if (rstr != CEED_ELEMRESTRICTION_NONE) CeedCall(CeedElemRestrictionReference(rstr)); 655 CeedCall(CeedElemRestrictionDestroy(rstr_copy)); 656 *rstr_copy = rstr; 657 return CEED_ERROR_SUCCESS; 658 } 659 660 /** 661 @brief Create CeedVectors associated with a CeedElemRestriction 662 663 @param[in] rstr CeedElemRestriction 664 @param[out] l_vec The address of the L-vector to be created, or NULL 665 @param[out] e_vec The address of the E-vector to be created, or NULL 666 667 @return An error code: 0 - success, otherwise - failure 668 669 @ref User 670 **/ 671 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec, CeedVector *e_vec) { 672 CeedSize e_size, l_size; 673 l_size = rstr->l_size; 674 e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 675 if (l_vec) CeedCall(CeedVectorCreate(rstr->ceed, l_size, l_vec)); 676 if (e_vec) CeedCall(CeedVectorCreate(rstr->ceed, e_size, e_vec)); 677 return CEED_ERROR_SUCCESS; 678 } 679 680 /** 681 @brief Restrict an L-vector to an E-vector or apply its transpose 682 683 @param[in] rstr CeedElemRestriction 684 @param[in] t_mode Apply restriction or transpose 685 @param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 686 @param[out] ru Output vector (of shape [@a num_elem * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). 687 Ordering of the e-vector is decided by the backend. 688 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 689 690 @return An error code: 0 - success, otherwise - failure 691 692 @ref User 693 **/ 694 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) { 695 CeedInt m, n; 696 697 if (t_mode == CEED_NOTRANSPOSE) { 698 m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 699 n = rstr->l_size; 700 } else { 701 m = rstr->l_size; 702 n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 703 } 704 CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION, 705 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n); 706 CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION, 707 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n); 708 if (rstr->num_elem > 0) CeedCall(rstr->Apply(rstr, t_mode, u, ru, request)); 709 return CEED_ERROR_SUCCESS; 710 } 711 712 /** 713 @brief Restrict an L-vector to a block of an E-vector or apply its transpose 714 715 @param[in] rstr CeedElemRestriction 716 @param[in] block Block number to restrict to/from, i.e. block=0 will handle elements [0 : blk_size] and block=3 will handle elements [3*blk_size 717 : 4*blk_size] 718 @param[in] t_mode Apply restriction or transpose 719 @param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 720 @param[out] ru Output vector (of shape [@a blk_size * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). 721 Ordering of the e-vector is decided by the backend. 722 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 723 724 @return An error code: 0 - success, otherwise - failure 725 726 @ref Backend 727 **/ 728 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 729 CeedRequest *request) { 730 CeedInt m, n; 731 732 CeedCheck(rstr->ApplyBlock, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionApplyBlock"); 733 734 if (t_mode == CEED_NOTRANSPOSE) { 735 m = rstr->blk_size * rstr->elem_size * rstr->num_comp; 736 n = rstr->l_size; 737 } else { 738 m = rstr->l_size; 739 n = rstr->blk_size * rstr->elem_size * rstr->num_comp; 740 } 741 CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION, 742 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n); 743 CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION, 744 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n); 745 CeedCheck(rstr->blk_size * block <= rstr->num_elem, rstr->ceed, CEED_ERROR_DIMENSION, 746 "Cannot retrieve block %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", block, rstr->blk_size * block, 747 rstr->num_elem); 748 CeedCall(rstr->ApplyBlock(rstr, block, t_mode, u, ru, request)); 749 return CEED_ERROR_SUCCESS; 750 } 751 752 /** 753 @brief Get the Ceed associated with a CeedElemRestriction 754 755 @param[in] rstr CeedElemRestriction 756 @param[out] ceed Variable to store Ceed 757 758 @return An error code: 0 - success, otherwise - failure 759 760 @ref Advanced 761 **/ 762 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) { 763 *ceed = rstr->ceed; 764 return CEED_ERROR_SUCCESS; 765 } 766 767 /** 768 @brief Get the L-vector component stride 769 770 @param[in] rstr CeedElemRestriction 771 @param[out] comp_stride Variable to store component stride 772 773 @return An error code: 0 - success, otherwise - failure 774 775 @ref Advanced 776 **/ 777 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, CeedInt *comp_stride) { 778 *comp_stride = rstr->comp_stride; 779 return CEED_ERROR_SUCCESS; 780 } 781 782 /** 783 @brief Get the total number of elements in the range of a CeedElemRestriction 784 785 @param[in] rstr CeedElemRestriction 786 @param[out] num_elem Variable to store number of elements 787 788 @return An error code: 0 - success, otherwise - failure 789 790 @ref Advanced 791 **/ 792 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, CeedInt *num_elem) { 793 *num_elem = rstr->num_elem; 794 return CEED_ERROR_SUCCESS; 795 } 796 797 /** 798 @brief Get the size of elements in the CeedElemRestriction 799 800 @param[in] rstr CeedElemRestriction 801 @param[out] elem_size Variable to store size of elements 802 803 @return An error code: 0 - success, otherwise - failure 804 805 @ref Advanced 806 **/ 807 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, CeedInt *elem_size) { 808 *elem_size = rstr->elem_size; 809 return CEED_ERROR_SUCCESS; 810 } 811 812 /** 813 @brief Get the size of the l-vector for a CeedElemRestriction 814 815 @param[in] rstr CeedElemRestriction 816 @param[out] l_size Variable to store number of nodes 817 818 @return An error code: 0 - success, otherwise - failure 819 820 @ref Advanced 821 **/ 822 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, CeedSize *l_size) { 823 *l_size = rstr->l_size; 824 return CEED_ERROR_SUCCESS; 825 } 826 827 /** 828 @brief Get the number of components in the elements of a CeedElemRestriction 829 830 @param[in] rstr CeedElemRestriction 831 @param[out] num_comp Variable to store number of components 832 833 @return An error code: 0 - success, otherwise - failure 834 835 @ref Advanced 836 **/ 837 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, CeedInt *num_comp) { 838 *num_comp = rstr->num_comp; 839 return CEED_ERROR_SUCCESS; 840 } 841 842 /** 843 @brief Get the number of blocks in a CeedElemRestriction 844 845 @param[in] rstr CeedElemRestriction 846 @param[out] num_block Variable to store number of blocks 847 848 @return An error code: 0 - success, otherwise - failure 849 850 @ref Advanced 851 **/ 852 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, CeedInt *num_block) { 853 *num_block = rstr->num_blk; 854 return CEED_ERROR_SUCCESS; 855 } 856 857 /** 858 @brief Get the size of blocks in the CeedElemRestriction 859 860 @param[in] rstr CeedElemRestriction 861 @param[out] blk_size Variable to store size of blocks 862 863 @return An error code: 0 - success, otherwise - failure 864 865 @ref Advanced 866 **/ 867 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, CeedInt *blk_size) { 868 *blk_size = rstr->blk_size; 869 return CEED_ERROR_SUCCESS; 870 } 871 872 /** 873 @brief Get the multiplicity of nodes in a CeedElemRestriction 874 875 @param[in] rstr CeedElemRestriction 876 @param[out] mult Vector to store multiplicity (of size l_size) 877 878 @return An error code: 0 - success, otherwise - failure 879 880 @ref User 881 **/ 882 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, CeedVector mult) { 883 CeedVector e_vec; 884 885 // Create e_vec to hold intermediate computation in E^T (E 1) 886 CeedCall(CeedElemRestrictionCreateVector(rstr, NULL, &e_vec)); 887 888 // Compute e_vec = E * 1 889 CeedCall(CeedVectorSetValue(mult, 1.0)); 890 CeedCall(CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, CEED_REQUEST_IMMEDIATE)); 891 // Compute multiplicity, mult = E^T * e_vec = E^T (E 1) 892 CeedCall(CeedVectorSetValue(mult, 0.0)); 893 CeedCall(CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, CEED_REQUEST_IMMEDIATE)); 894 // Cleanup 895 CeedCall(CeedVectorDestroy(&e_vec)); 896 return CEED_ERROR_SUCCESS; 897 } 898 899 /** 900 @brief View a CeedElemRestriction 901 902 @param[in] rstr CeedElemRestriction to view 903 @param[in] stream Stream to write; typically stdout/stderr or a file 904 905 @return Error code: 0 - success, otherwise - failure 906 907 @ref User 908 **/ 909 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) { 910 char stridesstr[500]; 911 if (rstr->strides) { 912 sprintf(stridesstr, "[%" CeedInt_FMT ", %" CeedInt_FMT ", %" CeedInt_FMT "]", rstr->strides[0], rstr->strides[1], rstr->strides[2]); 913 } else { 914 sprintf(stridesstr, "%" CeedInt_FMT, rstr->comp_stride); 915 } 916 917 fprintf(stream, "%sCeedElemRestriction from (%td, %" CeedInt_FMT ") to %" CeedInt_FMT " elements with %" CeedInt_FMT " nodes each and %s %s\n", 918 rstr->blk_size > 1 ? "Blocked " : "", rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size, 919 rstr->strides ? "strides" : "component stride", stridesstr); 920 return CEED_ERROR_SUCCESS; 921 } 922 923 /** 924 @brief Destroy a CeedElemRestriction 925 926 @param[in,out] rstr CeedElemRestriction to destroy 927 928 @return An error code: 0 - success, otherwise - failure 929 930 @ref User 931 **/ 932 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) { 933 if (!*rstr || *rstr == CEED_ELEMRESTRICTION_NONE || --(*rstr)->ref_count > 0) { 934 *rstr = NULL; 935 return CEED_ERROR_SUCCESS; 936 } 937 CeedCheck((*rstr)->num_readers == 0, (*rstr)->ceed, CEED_ERROR_ACCESS, 938 "Cannot destroy CeedElemRestriction, a process has read access to the offset data"); 939 940 // Only destroy backend data once between rstr and unsigned copy 941 if ((*rstr)->rstr_signed) CeedCall(CeedElemRestrictionDestroy(&(*rstr)->rstr_signed)); 942 else if ((*rstr)->Destroy) CeedCall((*rstr)->Destroy(*rstr)); 943 944 CeedCall(CeedFree(&(*rstr)->strides)); 945 CeedCall(CeedDestroy(&(*rstr)->ceed)); 946 CeedCall(CeedFree(rstr)); 947 return CEED_ERROR_SUCCESS; 948 } 949 950 /// @} 951