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 = 0; 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 = 1; 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 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 413 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ElemRestrictionCreate"); 414 CeedCall(CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp, l_size, strides, rstr)); 415 return CEED_ERROR_SUCCESS; 416 } 417 418 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 419 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 420 421 CeedCall(CeedCalloc(1, rstr)); 422 (*rstr)->ceed = ceed; 423 CeedCall(CeedReference(ceed)); 424 (*rstr)->ref_count = 1; 425 (*rstr)->num_elem = num_elem; 426 (*rstr)->elem_size = elem_size; 427 (*rstr)->num_comp = num_comp; 428 (*rstr)->l_size = l_size; 429 (*rstr)->num_blk = num_elem; 430 (*rstr)->blk_size = 1; 431 (*rstr)->is_oriented = 0; 432 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 433 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 434 CeedCall(ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, *rstr)); 435 return CEED_ERROR_SUCCESS; 436 } 437 438 /** 439 @brief Create a blocked CeedElemRestriction, typically only called by backends 440 441 @param[in] ceed Ceed object where the CeedElemRestriction will be created. 442 @param[in] num_elem Number of elements described in the @a offsets array. 443 @param[in] elem_size Size (number of unknowns) per element 444 @param[in] blk_size Number of elements in a block 445 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 446 @param[in] comp_stride Stride between components for the same L-vector "node". 447 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. 448 @param[in] l_size The size of the L-vector. 449 This vector may be larger than the elements and fields given by this restriction. 450 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 451 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 452 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 453 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 454 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 455 the blocksize, which is typically given by the backend. The default reordering is to interlace elements. 456 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 457 458 @return An error code: 0 - success, otherwise - failure 459 460 @ref Backend 461 **/ 462 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedInt comp_stride, 463 CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, 464 CeedElemRestriction *rstr) { 465 CeedInt *blk_offsets; 466 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 467 468 if (!ceed->ElemRestrictionCreateBlocked) { 469 Ceed delegate; 470 471 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 472 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ElemRestrictionCreateBlocked"); 473 CeedCall( 474 CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, blk_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr)); 475 return CEED_ERROR_SUCCESS; 476 } 477 478 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 479 CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 480 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 481 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 482 483 CeedCall(CeedCalloc(1, rstr)); 484 485 CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_offsets)); 486 CeedCall(CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size, elem_size)); 487 488 (*rstr)->ceed = ceed; 489 CeedCall(CeedReference(ceed)); 490 (*rstr)->ref_count = 1; 491 (*rstr)->num_elem = num_elem; 492 (*rstr)->elem_size = elem_size; 493 (*rstr)->num_comp = num_comp; 494 (*rstr)->comp_stride = comp_stride; 495 (*rstr)->l_size = l_size; 496 (*rstr)->num_blk = num_blk; 497 (*rstr)->blk_size = blk_size; 498 (*rstr)->is_oriented = 0; 499 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)blk_offsets, *rstr)); 500 if (copy_mode == CEED_OWN_POINTER) { 501 CeedCall(CeedFree(&offsets)); 502 } 503 return CEED_ERROR_SUCCESS; 504 } 505 506 /** 507 @brief Create a blocked strided CeedElemRestriction 508 509 @param[in] ceed Ceed object where the CeedElemRestriction will be created 510 @param[in] num_elem Number of elements described by the restriction 511 @param[in] elem_size Size (number of "nodes") per element 512 @param[in] blk_size Number of elements in a block 513 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 514 @param[in] l_size The size of the L-vector. 515 This vector may be larger than the elements and fields given by this restriction. 516 @param[in] strides Array for strides between [nodes, components, elements]. 517 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]. 518 @a CEED_STRIDES_BACKEND may be used with vectors created by a Ceed backend. 519 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 520 521 @return An error code: 0 - success, otherwise - failure 522 523 @ref User 524 **/ 525 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedSize l_size, 526 const CeedInt strides[3], CeedElemRestriction *rstr) { 527 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 528 529 if (!ceed->ElemRestrictionCreateBlocked) { 530 Ceed delegate; 531 532 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 533 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ElemRestrictionCreateBlocked"); 534 CeedCall(CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size, blk_size, num_comp, l_size, strides, rstr)); 535 return CEED_ERROR_SUCCESS; 536 } 537 538 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 539 CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 540 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 541 542 CeedCall(CeedCalloc(1, rstr)); 543 544 (*rstr)->ceed = ceed; 545 CeedCall(CeedReference(ceed)); 546 (*rstr)->ref_count = 1; 547 (*rstr)->num_elem = num_elem; 548 (*rstr)->elem_size = elem_size; 549 (*rstr)->num_comp = num_comp; 550 (*rstr)->l_size = l_size; 551 (*rstr)->num_blk = num_blk; 552 (*rstr)->blk_size = blk_size; 553 (*rstr)->is_oriented = 0; 554 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 555 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 556 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, *rstr)); 557 return CEED_ERROR_SUCCESS; 558 } 559 560 /** 561 @brief Copy the pointer to a CeedElemRestriction. 562 Both pointers should be destroyed with `CeedElemRestrictionDestroy()`. 563 564 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 565 CeedElemRestriction. This CeedElemRestriction will be destroyed if `rstr_copy` is the only reference to this CeedElemRestriction. 566 567 @param[in] rstr CeedElemRestriction to copy reference to 568 @param[in,out] rstr_copy Variable to store copied reference 569 570 @return An error code: 0 - success, otherwise - failure 571 572 @ref User 573 **/ 574 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_copy) { 575 if (rstr != CEED_ELEMRESTRICTION_NONE) CeedCall(CeedElemRestrictionReference(rstr)); 576 CeedCall(CeedElemRestrictionDestroy(rstr_copy)); 577 *rstr_copy = rstr; 578 return CEED_ERROR_SUCCESS; 579 } 580 581 /** 582 @brief Create CeedVectors associated with a CeedElemRestriction 583 584 @param[in] rstr CeedElemRestriction 585 @param[out] l_vec The address of the L-vector to be created, or NULL 586 @param[out] e_vec The address of the E-vector to be created, or NULL 587 588 @return An error code: 0 - success, otherwise - failure 589 590 @ref User 591 **/ 592 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec, CeedVector *e_vec) { 593 CeedSize e_size, l_size; 594 l_size = rstr->l_size; 595 e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 596 if (l_vec) CeedCall(CeedVectorCreate(rstr->ceed, l_size, l_vec)); 597 if (e_vec) CeedCall(CeedVectorCreate(rstr->ceed, e_size, e_vec)); 598 return CEED_ERROR_SUCCESS; 599 } 600 601 /** 602 @brief Restrict an L-vector to an E-vector or apply its transpose 603 604 @param[in] rstr CeedElemRestriction 605 @param[in] t_mode Apply restriction or transpose 606 @param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 607 @param[out] ru Output vector (of shape [@a num_elem * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). 608 Ordering of the e-vector is decided by the backend. 609 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 610 611 @return An error code: 0 - success, otherwise - failure 612 613 @ref User 614 **/ 615 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) { 616 CeedInt m, n; 617 618 if (t_mode == CEED_NOTRANSPOSE) { 619 m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 620 n = rstr->l_size; 621 } else { 622 m = rstr->l_size; 623 n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 624 } 625 CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION, 626 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n); 627 CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION, 628 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n); 629 if (rstr->num_elem > 0) CeedCall(rstr->Apply(rstr, t_mode, u, ru, request)); 630 return CEED_ERROR_SUCCESS; 631 } 632 633 /** 634 @brief Restrict an L-vector to a block of an E-vector or apply its transpose 635 636 @param[in] rstr CeedElemRestriction 637 @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 638 : 4*blk_size] 639 @param[in] t_mode Apply restriction or transpose 640 @param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 641 @param[out] ru Output vector (of shape [@a blk_size * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). 642 Ordering of the e-vector is decided by the backend. 643 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 644 645 @return An error code: 0 - success, otherwise - failure 646 647 @ref Backend 648 **/ 649 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 650 CeedRequest *request) { 651 CeedInt m, n; 652 653 if (t_mode == CEED_NOTRANSPOSE) { 654 m = rstr->blk_size * rstr->elem_size * rstr->num_comp; 655 n = rstr->l_size; 656 } else { 657 m = rstr->l_size; 658 n = rstr->blk_size * rstr->elem_size * rstr->num_comp; 659 } 660 CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION, 661 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n); 662 CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION, 663 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n); 664 CeedCheck(rstr->blk_size * block <= rstr->num_elem, rstr->ceed, CEED_ERROR_DIMENSION, 665 "Cannot retrieve block %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", block, rstr->blk_size * block, 666 rstr->num_elem); 667 CeedCall(rstr->ApplyBlock(rstr, block, t_mode, u, ru, request)); 668 return CEED_ERROR_SUCCESS; 669 } 670 671 /** 672 @brief Get the Ceed associated with a CeedElemRestriction 673 674 @param[in] rstr CeedElemRestriction 675 @param[out] ceed Variable to store Ceed 676 677 @return An error code: 0 - success, otherwise - failure 678 679 @ref Advanced 680 **/ 681 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) { 682 *ceed = rstr->ceed; 683 return CEED_ERROR_SUCCESS; 684 } 685 686 /** 687 @brief Get the L-vector component stride 688 689 @param[in] rstr CeedElemRestriction 690 @param[out] comp_stride Variable to store component stride 691 692 @return An error code: 0 - success, otherwise - failure 693 694 @ref Advanced 695 **/ 696 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, CeedInt *comp_stride) { 697 *comp_stride = rstr->comp_stride; 698 return CEED_ERROR_SUCCESS; 699 } 700 701 /** 702 @brief Get the total number of elements in the range of a CeedElemRestriction 703 704 @param[in] rstr CeedElemRestriction 705 @param[out] num_elem Variable to store number of elements 706 707 @return An error code: 0 - success, otherwise - failure 708 709 @ref Advanced 710 **/ 711 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, CeedInt *num_elem) { 712 *num_elem = rstr->num_elem; 713 return CEED_ERROR_SUCCESS; 714 } 715 716 /** 717 @brief Get the size of elements in the CeedElemRestriction 718 719 @param[in] rstr CeedElemRestriction 720 @param[out] elem_size Variable to store size of elements 721 722 @return An error code: 0 - success, otherwise - failure 723 724 @ref Advanced 725 **/ 726 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, CeedInt *elem_size) { 727 *elem_size = rstr->elem_size; 728 return CEED_ERROR_SUCCESS; 729 } 730 731 /** 732 @brief Get the size of the l-vector for a CeedElemRestriction 733 734 @param[in] rstr CeedElemRestriction 735 @param[out] l_size Variable to store number of nodes 736 737 @return An error code: 0 - success, otherwise - failure 738 739 @ref Advanced 740 **/ 741 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, CeedSize *l_size) { 742 *l_size = rstr->l_size; 743 return CEED_ERROR_SUCCESS; 744 } 745 746 /** 747 @brief Get the number of components in the elements of a CeedElemRestriction 748 749 @param[in] rstr CeedElemRestriction 750 @param[out] num_comp Variable to store number of components 751 752 @return An error code: 0 - success, otherwise - failure 753 754 @ref Advanced 755 **/ 756 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, CeedInt *num_comp) { 757 *num_comp = rstr->num_comp; 758 return CEED_ERROR_SUCCESS; 759 } 760 761 /** 762 @brief Get the number of blocks in a CeedElemRestriction 763 764 @param[in] rstr CeedElemRestriction 765 @param[out] num_block Variable to store number of blocks 766 767 @return An error code: 0 - success, otherwise - failure 768 769 @ref Advanced 770 **/ 771 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, CeedInt *num_block) { 772 *num_block = rstr->num_blk; 773 return CEED_ERROR_SUCCESS; 774 } 775 776 /** 777 @brief Get the size of blocks in the CeedElemRestriction 778 779 @param[in] rstr CeedElemRestriction 780 @param[out] blk_size Variable to store size of blocks 781 782 @return An error code: 0 - success, otherwise - failure 783 784 @ref Advanced 785 **/ 786 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, CeedInt *blk_size) { 787 *blk_size = rstr->blk_size; 788 return CEED_ERROR_SUCCESS; 789 } 790 791 /** 792 @brief Get the multiplicity of nodes in a CeedElemRestriction 793 794 @param[in] rstr CeedElemRestriction 795 @param[out] mult Vector to store multiplicity (of size l_size) 796 797 @return An error code: 0 - success, otherwise - failure 798 799 @ref User 800 **/ 801 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, CeedVector mult) { 802 CeedVector e_vec; 803 804 // Create e_vec to hold intermediate computation in E^T (E 1) 805 CeedCall(CeedElemRestrictionCreateVector(rstr, NULL, &e_vec)); 806 807 // Compute e_vec = E * 1 808 CeedCall(CeedVectorSetValue(mult, 1.0)); 809 CeedCall(CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, CEED_REQUEST_IMMEDIATE)); 810 // Compute multiplicity, mult = E^T * e_vec = E^T (E 1) 811 CeedCall(CeedVectorSetValue(mult, 0.0)); 812 CeedCall(CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, CEED_REQUEST_IMMEDIATE)); 813 // Cleanup 814 CeedCall(CeedVectorDestroy(&e_vec)); 815 return CEED_ERROR_SUCCESS; 816 } 817 818 /** 819 @brief View a CeedElemRestriction 820 821 @param[in] rstr CeedElemRestriction to view 822 @param[in] stream Stream to write; typically stdout/stderr or a file 823 824 @return Error code: 0 - success, otherwise - failure 825 826 @ref User 827 **/ 828 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) { 829 char stridesstr[500]; 830 if (rstr->strides) { 831 sprintf(stridesstr, "[%" CeedInt_FMT ", %" CeedInt_FMT ", %" CeedInt_FMT "]", rstr->strides[0], rstr->strides[1], rstr->strides[2]); 832 } else { 833 sprintf(stridesstr, "%" CeedInt_FMT, rstr->comp_stride); 834 } 835 836 fprintf(stream, "%sCeedElemRestriction from (%td, %" CeedInt_FMT ") to %" CeedInt_FMT " elements with %" CeedInt_FMT " nodes each and %s %s\n", 837 rstr->blk_size > 1 ? "Blocked " : "", rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size, 838 rstr->strides ? "strides" : "component stride", stridesstr); 839 return CEED_ERROR_SUCCESS; 840 } 841 842 /** 843 @brief Destroy a CeedElemRestriction 844 845 @param[in,out] rstr CeedElemRestriction to destroy 846 847 @return An error code: 0 - success, otherwise - failure 848 849 @ref User 850 **/ 851 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) { 852 if (!*rstr || *rstr == CEED_ELEMRESTRICTION_NONE || --(*rstr)->ref_count > 0) { 853 *rstr = NULL; 854 return CEED_ERROR_SUCCESS; 855 } 856 CeedCheck((*rstr)->num_readers == 0, (*rstr)->ceed, CEED_ERROR_ACCESS, 857 "Cannot destroy CeedElemRestriction, a process has read access to the offset data"); 858 if ((*rstr)->Destroy) CeedCall((*rstr)->Destroy(*rstr)); 859 CeedCall(CeedFree(&(*rstr)->strides)); 860 CeedCall(CeedDestroy(&(*rstr)->ceed)); 861 CeedCall(CeedFree(rstr)); 862 return CEED_ERROR_SUCCESS; 863 } 864 865 /// @} 866