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 61 @brief Get the strides of a strided CeedElemRestriction 62 63 @param[in] rstr CeedElemRestriction 64 @param[out] strides Variable to store strides array 65 66 @return An error code: 0 - success, otherwise - failure 67 68 @ref Backend 69 **/ 70 int CeedElemRestrictionGetStrides(CeedElemRestriction rstr, CeedInt (*strides)[3]) { 71 CeedCheck(rstr->strides, rstr->ceed, CEED_ERROR_MINOR, "ElemRestriction has no stride data"); 72 for (CeedInt i = 0; i < 3; i++) (*strides)[i] = rstr->strides[i]; 73 return CEED_ERROR_SUCCESS; 74 } 75 76 /** 77 @brief Get read-only access to a CeedElemRestriction offsets array by memtype 78 79 @param[in] rstr CeedElemRestriction to retrieve offsets 80 @param[in] mem_type Memory type on which to access the array. 81 If the backend uses a different memory type, this will perform a copy (possibly cached). 82 @param[out] offsets Array on memory type mem_type 83 84 @return An error code: 0 - success, otherwise - failure 85 86 @ref User 87 **/ 88 int CeedElemRestrictionGetOffsets(CeedElemRestriction rstr, CeedMemType mem_type, const CeedInt **offsets) { 89 if (rstr->rstr_signed) { 90 CeedCall(CeedElemRestrictionGetOffsets(rstr->rstr_signed, mem_type, offsets)); 91 } else { 92 CeedCheck(rstr->GetOffsets, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetOffsets"); 93 CeedCall(rstr->GetOffsets(rstr, mem_type, offsets)); 94 rstr->num_readers++; 95 } 96 return CEED_ERROR_SUCCESS; 97 } 98 99 /** 100 @brief Restore an offsets array obtained using CeedElemRestrictionGetOffsets() 101 102 @param[in] rstr CeedElemRestriction to restore 103 @param[in] offsets Array of offset data 104 105 @return An error code: 0 - success, otherwise - failure 106 107 @ref User 108 **/ 109 int CeedElemRestrictionRestoreOffsets(CeedElemRestriction rstr, const CeedInt **offsets) { 110 if (rstr->rstr_signed) { 111 CeedCall(CeedElemRestrictionRestoreOffsets(rstr->rstr_signed, offsets)); 112 } else { 113 *offsets = NULL; 114 rstr->num_readers--; 115 } 116 return CEED_ERROR_SUCCESS; 117 } 118 119 /** 120 @brief Get the strided status of a CeedElemRestriction 121 122 @param[in] rstr CeedElemRestriction 123 @param[out] is_strided Variable to store strided status, 1 if strided else 0 124 125 @return An error code: 0 - success, otherwise - failure 126 127 @ref Backend 128 **/ 129 int CeedElemRestrictionIsStrided(CeedElemRestriction rstr, bool *is_strided) { 130 *is_strided = rstr->strides ? true : false; 131 return CEED_ERROR_SUCCESS; 132 } 133 134 /** 135 @brief Get oriented status of a CeedElemRestriction 136 137 @param[in] rstr CeedElemRestriction 138 @param[out] is_oriented Variable to store oriented status, 1 if oriented else 0 139 140 @return An error code: 0 - success, otherwise - failure 141 142 @ref Backend 143 **/ 144 int CeedElemRestrictionIsOriented(CeedElemRestriction rstr, bool *is_oriented) { 145 *is_oriented = rstr->is_oriented; 146 return CEED_ERROR_SUCCESS; 147 } 148 149 /** 150 @brief Get the backend stride status of a CeedElemRestriction 151 152 @param[in] rstr CeedElemRestriction 153 @param[out] has_backend_strides Variable to store stride status 154 155 @return An error code: 0 - success, otherwise - failure 156 157 @ref Backend 158 **/ 159 int CeedElemRestrictionHasBackendStrides(CeedElemRestriction rstr, bool *has_backend_strides) { 160 CeedCheck(rstr->strides, rstr->ceed, CEED_ERROR_MINOR, "ElemRestriction has no stride data"); 161 *has_backend_strides = ((rstr->strides[0] == CEED_STRIDES_BACKEND[0]) && (rstr->strides[1] == CEED_STRIDES_BACKEND[1]) && 162 (rstr->strides[2] == CEED_STRIDES_BACKEND[2])); 163 return CEED_ERROR_SUCCESS; 164 } 165 166 /** 167 168 @brief Get the E-vector layout of a CeedElemRestriction 169 170 @param[in] rstr CeedElemRestriction 171 @param[out] layout Variable to store layout array, stored as [nodes, components, elements]. 172 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] 173 174 @return An error code: 0 - success, otherwise - failure 175 176 @ref Backend 177 **/ 178 int CeedElemRestrictionGetELayout(CeedElemRestriction rstr, CeedInt (*layout)[3]) { 179 CeedCheck(rstr->layout[0], rstr->ceed, CEED_ERROR_MINOR, "ElemRestriction has no layout data"); 180 for (CeedInt i = 0; i < 3; i++) (*layout)[i] = rstr->layout[i]; 181 return CEED_ERROR_SUCCESS; 182 } 183 184 /** 185 186 @brief Set the E-vector layout of a CeedElemRestriction 187 188 @param[in] rstr CeedElemRestriction 189 @param[in] layout Variable to containing layout array, stored as [nodes, components, elements]. 190 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] 191 192 @return An error code: 0 - success, otherwise - failure 193 194 @ref Backend 195 **/ 196 int CeedElemRestrictionSetELayout(CeedElemRestriction rstr, CeedInt layout[3]) { 197 for (CeedInt i = 0; i < 3; i++) rstr->layout[i] = layout[i]; 198 return CEED_ERROR_SUCCESS; 199 } 200 201 /** 202 @brief Get the backend data of a CeedElemRestriction 203 204 @param[in] rstr CeedElemRestriction 205 @param[out] data Variable to store data 206 207 @return An error code: 0 - success, otherwise - failure 208 209 @ref Backend 210 **/ 211 int CeedElemRestrictionGetData(CeedElemRestriction rstr, void *data) { 212 *(void **)data = rstr->data; 213 return CEED_ERROR_SUCCESS; 214 } 215 216 /** 217 @brief Set the backend data of a CeedElemRestriction 218 219 @param[in,out] rstr CeedElemRestriction 220 @param[in] data Data to set 221 222 @return An error code: 0 - success, otherwise - failure 223 224 @ref Backend 225 **/ 226 int CeedElemRestrictionSetData(CeedElemRestriction rstr, void *data) { 227 rstr->data = data; 228 return CEED_ERROR_SUCCESS; 229 } 230 231 /** 232 @brief Increment the reference counter for a CeedElemRestriction 233 234 @param[in,out] rstr ElemRestriction to increment the reference counter 235 236 @return An error code: 0 - success, otherwise - failure 237 238 @ref Backend 239 **/ 240 int CeedElemRestrictionReference(CeedElemRestriction rstr) { 241 rstr->ref_count++; 242 return CEED_ERROR_SUCCESS; 243 } 244 245 /** 246 @brief Estimate number of FLOPs required to apply CeedElemRestriction in t_mode 247 248 @param[in] rstr ElemRestriction to estimate FLOPs for 249 @param[in] t_mode Apply restriction or transpose 250 @param[out] flops Address of variable to hold FLOPs estimate 251 252 @ref Backend 253 **/ 254 int CeedElemRestrictionGetFlopsEstimate(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedSize *flops) { 255 bool is_oriented; 256 CeedInt e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp, scale = 0; 257 258 CeedCall(CeedElemRestrictionIsOriented(rstr, &is_oriented)); 259 switch (t_mode) { 260 case CEED_NOTRANSPOSE: 261 scale = is_oriented ? 1 : 0; 262 break; 263 case CEED_TRANSPOSE: 264 scale = is_oriented ? 2 : 1; 265 break; 266 } 267 *flops = e_size * scale; 268 269 return CEED_ERROR_SUCCESS; 270 } 271 272 /// @} 273 274 /// @cond DOXYGEN_SKIP 275 static struct CeedElemRestriction_private ceed_elemrestriction_none; 276 /// @endcond 277 278 /// ---------------------------------------------------------------------------- 279 /// CeedElemRestriction Public API 280 /// ---------------------------------------------------------------------------- 281 /// @addtogroup CeedElemRestrictionUser 282 /// @{ 283 284 /// Indicate that the stride is determined by the backend 285 const CeedInt CEED_STRIDES_BACKEND[3] = {0}; 286 287 /// Indicate that no CeedElemRestriction is provided by the user 288 const CeedElemRestriction CEED_ELEMRESTRICTION_NONE = &ceed_elemrestriction_none; 289 290 /** 291 @brief Create a CeedElemRestriction 292 293 @param[in] ceed Ceed object where the CeedElemRestriction will be created 294 @param[in] num_elem Number of elements described in the @a offsets array 295 @param[in] elem_size Size (number of "nodes") per element 296 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 297 @param[in] comp_stride Stride between components for the same L-vector "node". 298 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. 299 @param[in] l_size The size of the L-vector. 300 This vector may be larger than the elements and fields given by this restriction. 301 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 302 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 303 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 304 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 305 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. 306 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 307 308 @return An error code: 0 - success, otherwise - failure 309 310 @ref User 311 **/ 312 int CeedElemRestrictionCreate(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 313 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, CeedElemRestriction *rstr) { 314 if (!ceed->ElemRestrictionCreate) { 315 Ceed delegate; 316 317 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 318 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ElemRestrictionCreate"); 319 CeedCall(CeedElemRestrictionCreate(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr)); 320 return CEED_ERROR_SUCCESS; 321 } 322 323 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 324 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 325 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 326 327 CeedCall(CeedCalloc(1, rstr)); 328 (*rstr)->ceed = ceed; 329 CeedCall(CeedReference(ceed)); 330 (*rstr)->ref_count = 1; 331 (*rstr)->num_elem = num_elem; 332 (*rstr)->elem_size = elem_size; 333 (*rstr)->num_comp = num_comp; 334 (*rstr)->comp_stride = comp_stride; 335 (*rstr)->l_size = l_size; 336 (*rstr)->num_blk = num_elem; 337 (*rstr)->blk_size = 1; 338 (*rstr)->is_oriented = false; 339 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, *rstr)); 340 return CEED_ERROR_SUCCESS; 341 } 342 343 /** 344 @brief Create a CeedElemRestriction with orientation sign 345 346 @param[in] ceed Ceed object where the CeedElemRestriction will be created 347 @param[in] num_elem Number of elements described in the @a offsets array 348 @param[in] elem_size Size (number of "nodes") per element 349 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 350 @param[in] comp_stride Stride between components for the same L-vector "node". 351 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. 352 @param[in] l_size The size of the L-vector. 353 This vector may be larger than the elements and fields given by this restriction. 354 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 355 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 356 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 357 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 358 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. 359 @param[in] orient Array of shape [@a num_elem, @a elem_size] with bool false for positively oriented and true to flip the orientation. 360 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 361 362 @return An error code: 0 - success, otherwise - failure 363 364 @ref User 365 **/ 366 int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 367 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const bool *orient, 368 CeedElemRestriction *rstr) { 369 if (!ceed->ElemRestrictionCreateOriented) { 370 Ceed delegate; 371 372 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 373 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateOriented"); 374 CeedCall( 375 CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, orient, rstr)); 376 return CEED_ERROR_SUCCESS; 377 } 378 379 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 380 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 381 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 382 383 CeedCall(CeedCalloc(1, rstr)); 384 (*rstr)->ceed = ceed; 385 CeedCall(CeedReference(ceed)); 386 (*rstr)->ref_count = 1; 387 (*rstr)->num_elem = num_elem; 388 (*rstr)->elem_size = elem_size; 389 (*rstr)->num_comp = num_comp; 390 (*rstr)->comp_stride = comp_stride; 391 (*rstr)->l_size = l_size; 392 (*rstr)->num_blk = num_elem; 393 (*rstr)->blk_size = 1; 394 (*rstr)->is_oriented = true; 395 CeedCall(ceed->ElemRestrictionCreateOriented(mem_type, copy_mode, offsets, orient, *rstr)); 396 return CEED_ERROR_SUCCESS; 397 } 398 399 /** 400 @brief Create a strided CeedElemRestriction 401 402 @param[in] ceed Ceed object where the CeedElemRestriction will be created 403 @param[in] num_elem Number of elements described by the restriction 404 @param[in] elem_size Size (number of "nodes") per element 405 @param[in] num_comp Number of field components per interpolation "node" (1 for scalar fields) 406 @param[in] l_size The size of the L-vector. 407 This vector may be larger than the elements and fields given by this restriction. 408 @param[in] strides Array for strides between [nodes, components, elements]. 409 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]. 410 @a CEED_STRIDES_BACKEND may be used with vectors created by a Ceed backend. 411 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 412 413 @return An error code: 0 - success, otherwise - failure 414 415 @ref User 416 **/ 417 int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedSize l_size, const CeedInt strides[3], 418 CeedElemRestriction *rstr) { 419 if (!ceed->ElemRestrictionCreate) { 420 Ceed delegate; 421 422 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 423 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ElemRestrictionCreateStrided"); 424 CeedCall(CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp, l_size, strides, rstr)); 425 return CEED_ERROR_SUCCESS; 426 } 427 428 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 429 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 430 431 CeedCall(CeedCalloc(1, rstr)); 432 (*rstr)->ceed = ceed; 433 CeedCall(CeedReference(ceed)); 434 (*rstr)->ref_count = 1; 435 (*rstr)->num_elem = num_elem; 436 (*rstr)->elem_size = elem_size; 437 (*rstr)->num_comp = num_comp; 438 (*rstr)->l_size = l_size; 439 (*rstr)->num_blk = num_elem; 440 (*rstr)->blk_size = 1; 441 (*rstr)->is_oriented = false; 442 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 443 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 444 CeedCall(ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, *rstr)); 445 return CEED_ERROR_SUCCESS; 446 } 447 448 /** 449 @brief Create a blocked CeedElemRestriction, typically only called by backends 450 451 @param[in] ceed Ceed object where the CeedElemRestriction will be created. 452 @param[in] num_elem Number of elements described in the @a offsets array. 453 @param[in] elem_size Size (number of unknowns) per element 454 @param[in] blk_size Number of elements in a block 455 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 456 @param[in] comp_stride Stride between components for the same L-vector "node". 457 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. 458 @param[in] l_size The size of the L-vector. 459 This vector may be larger than the elements and fields given by this restriction. 460 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 461 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 462 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 463 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 464 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 465 the blocksize, which is typically given by the backend. The default reordering is to interlace elements. 466 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 467 468 @return An error code: 0 - success, otherwise - failure 469 470 @ref Backend 471 **/ 472 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedInt comp_stride, 473 CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, 474 CeedElemRestriction *rstr) { 475 CeedInt *blk_offsets; 476 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 477 478 if (!ceed->ElemRestrictionCreateBlocked) { 479 Ceed delegate; 480 481 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 482 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlocked"); 483 CeedCall( 484 CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, blk_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr)); 485 return CEED_ERROR_SUCCESS; 486 } 487 488 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 489 CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 490 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 491 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 492 493 CeedCall(CeedCalloc(1, rstr)); 494 495 CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_offsets)); 496 CeedCall(CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size, elem_size)); 497 498 (*rstr)->ceed = ceed; 499 CeedCall(CeedReference(ceed)); 500 (*rstr)->ref_count = 1; 501 (*rstr)->num_elem = num_elem; 502 (*rstr)->elem_size = elem_size; 503 (*rstr)->num_comp = num_comp; 504 (*rstr)->comp_stride = comp_stride; 505 (*rstr)->l_size = l_size; 506 (*rstr)->num_blk = num_blk; 507 (*rstr)->blk_size = blk_size; 508 (*rstr)->is_oriented = false; 509 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)blk_offsets, *rstr)); 510 if (copy_mode == CEED_OWN_POINTER) { 511 CeedCall(CeedFree(&offsets)); 512 } 513 return CEED_ERROR_SUCCESS; 514 } 515 516 /** 517 @brief Create a blocked strided CeedElemRestriction 518 519 @param[in] ceed Ceed object where the CeedElemRestriction will be created 520 @param[in] num_elem Number of elements described by the restriction 521 @param[in] elem_size Size (number of "nodes") per element 522 @param[in] blk_size Number of elements in a block 523 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 524 @param[in] l_size The size of the L-vector. 525 This vector may be larger than the elements and fields given by this restriction. 526 @param[in] strides Array for strides between [nodes, components, elements]. 527 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]. 528 @a CEED_STRIDES_BACKEND may be used with vectors created by a Ceed backend. 529 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 530 531 @return An error code: 0 - success, otherwise - failure 532 533 @ref User 534 **/ 535 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedSize l_size, 536 const CeedInt strides[3], CeedElemRestriction *rstr) { 537 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 538 539 if (!ceed->ElemRestrictionCreateBlocked) { 540 Ceed delegate; 541 542 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 543 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlockedStrided"); 544 CeedCall(CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size, blk_size, num_comp, l_size, strides, rstr)); 545 return CEED_ERROR_SUCCESS; 546 } 547 548 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 549 CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 550 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 551 552 CeedCall(CeedCalloc(1, rstr)); 553 554 (*rstr)->ceed = ceed; 555 CeedCall(CeedReference(ceed)); 556 (*rstr)->ref_count = 1; 557 (*rstr)->num_elem = num_elem; 558 (*rstr)->elem_size = elem_size; 559 (*rstr)->num_comp = num_comp; 560 (*rstr)->l_size = l_size; 561 (*rstr)->num_blk = num_blk; 562 (*rstr)->blk_size = blk_size; 563 (*rstr)->is_oriented = false; 564 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 565 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 566 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, *rstr)); 567 return CEED_ERROR_SUCCESS; 568 } 569 570 /** 571 @brief Copy the pointer to a CeedElemRestriction and set `CeedElemRestrictionApply()` implementation to `CeedElemRestrictionApplyUnsigned()`. 572 573 Both pointers should be destroyed with `CeedElemRestrictionDestroy()`. 574 575 @param[in] rstr CeedElemRestriction to create unsigned reference to 576 @param[in,out] rstr_unsigned Variable to store unsigned CeedElemRestriction 577 578 @return An error code: 0 - success, otherwise - failure 579 580 @ref User 581 **/ 582 int CeedElemRestrictionCreateUnsignedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unsigned) { 583 CeedCall(CeedCalloc(1, rstr_unsigned)); 584 585 // Copy old rstr 586 memcpy(*rstr_unsigned, rstr, sizeof(struct CeedElemRestriction_private)); 587 (*rstr_unsigned)->ceed = NULL; 588 CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unsigned)->ceed)); 589 (*rstr_unsigned)->ref_count = 1; 590 (*rstr_unsigned)->strides = NULL; 591 if (rstr->strides) { 592 CeedCall(CeedMalloc(3, &(*rstr_unsigned)->strides)); 593 for (CeedInt i = 0; i < 3; i++) (*rstr_unsigned)->strides[i] = rstr->strides[i]; 594 } 595 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unsigned)->rstr_signed)); 596 597 // Override Apply 598 (*rstr_unsigned)->Apply = rstr->ApplyUnsigned; 599 600 return CEED_ERROR_SUCCESS; 601 } 602 603 /** 604 @brief Copy the pointer to a CeedElemRestriction. 605 606 Both pointers should be destroyed with `CeedElemRestrictionDestroy()`. 607 608 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. 609 This CeedElemRestriction will be destroyed if `rstr_copy` is the only reference to this CeedElemRestriction. 610 611 @param[in] rstr CeedElemRestriction to copy reference to 612 @param[in,out] rstr_copy Variable to store copied reference 613 614 @return An error code: 0 - success, otherwise - failure 615 616 @ref User 617 **/ 618 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_copy) { 619 if (rstr != CEED_ELEMRESTRICTION_NONE) CeedCall(CeedElemRestrictionReference(rstr)); 620 CeedCall(CeedElemRestrictionDestroy(rstr_copy)); 621 *rstr_copy = rstr; 622 return CEED_ERROR_SUCCESS; 623 } 624 625 /** 626 @brief Create CeedVectors associated with a CeedElemRestriction 627 628 @param[in] rstr CeedElemRestriction 629 @param[out] l_vec The address of the L-vector to be created, or NULL 630 @param[out] e_vec The address of the E-vector to be created, or NULL 631 632 @return An error code: 0 - success, otherwise - failure 633 634 @ref User 635 **/ 636 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec, CeedVector *e_vec) { 637 CeedSize e_size, l_size; 638 l_size = rstr->l_size; 639 e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 640 if (l_vec) CeedCall(CeedVectorCreate(rstr->ceed, l_size, l_vec)); 641 if (e_vec) CeedCall(CeedVectorCreate(rstr->ceed, e_size, e_vec)); 642 return CEED_ERROR_SUCCESS; 643 } 644 645 /** 646 @brief Restrict an L-vector to an E-vector or apply its transpose 647 648 @param[in] rstr CeedElemRestriction 649 @param[in] t_mode Apply restriction or transpose 650 @param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 651 @param[out] ru Output vector (of shape [@a num_elem * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). 652 Ordering of the e-vector is decided by the backend. 653 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 654 655 @return An error code: 0 - success, otherwise - failure 656 657 @ref User 658 **/ 659 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) { 660 CeedInt m, n; 661 662 if (t_mode == CEED_NOTRANSPOSE) { 663 m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 664 n = rstr->l_size; 665 } else { 666 m = rstr->l_size; 667 n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 668 } 669 CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION, 670 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n); 671 CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION, 672 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n); 673 if (rstr->num_elem > 0) CeedCall(rstr->Apply(rstr, t_mode, u, ru, request)); 674 return CEED_ERROR_SUCCESS; 675 } 676 677 /** 678 @brief Restrict an L-vector to an E-vector or apply its transpose ignoring any 679 provided orientations 680 681 @param[in] rstr CeedElemRestriction 682 @param[in] t_mode Apply restriction or transpose 683 @param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 684 @param[out] ru Output vector (of shape [@a num_elem * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). 685 Ordering of the e-vector is decided by the backend. 686 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 687 688 @return An error code: 0 - success, otherwise - failure 689 690 @ref User 691 **/ 692 int CeedElemRestrictionApplyUnsigned(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) { 693 CeedInt m, n; 694 695 CeedCheck(rstr->ApplyUnsigned, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ElemRestrictionApplyUnsigned"); 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->ApplyUnsigned(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