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