1 // Copyright (c) 2017-2025, 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 <assert.h> 12 #include <math.h> 13 #include <stdbool.h> 14 #include <stdint.h> 15 #include <stdio.h> 16 17 /// @file 18 /// Implementation of public CeedVector interfaces 19 20 /// @cond DOXYGEN_SKIP 21 static struct CeedVector_private ceed_vector_active; 22 static struct CeedVector_private ceed_vector_none; 23 /// @endcond 24 25 /// @addtogroup CeedVectorUser 26 /// @{ 27 28 /// Indicate that vector will be provided as an explicit argument to @ref CeedOperatorApply(). 29 const CeedVector CEED_VECTOR_ACTIVE = &ceed_vector_active; 30 31 /// Indicate that no vector is applicable (i.e., for @ref CEED_EVAL_WEIGHT). 32 const CeedVector CEED_VECTOR_NONE = &ceed_vector_none; 33 34 /// @} 35 36 /// ---------------------------------------------------------------------------- 37 /// CeedVector Backend API 38 /// ---------------------------------------------------------------------------- 39 /// @addtogroup CeedVectorBackend 40 /// @{ 41 42 /** 43 @brief Check for valid data in a `CeedVector` 44 45 @param[in] vec `CeedVector` to check validity 46 @param[out] has_valid_array Variable to store validity 47 48 @return An error code: 0 - success, otherwise - failure 49 50 @ref Backend 51 **/ 52 int CeedVectorHasValidArray(CeedVector vec, bool *has_valid_array) { 53 CeedSize length; 54 55 CeedCheck(vec->HasValidArray, CeedVectorReturnCeed(vec), CEED_ERROR_UNSUPPORTED, "Backend does not support CeedVectorHasValidArray"); 56 CeedCall(CeedVectorGetLength(vec, &length)); 57 if (length == 0) { 58 *has_valid_array = true; 59 return CEED_ERROR_SUCCESS; 60 } 61 CeedCall(vec->HasValidArray(vec, has_valid_array)); 62 return CEED_ERROR_SUCCESS; 63 } 64 65 /** 66 @brief Check for borrowed array of a specific @ref CeedMemType in a `CeedVector` 67 68 @param[in] vec `CeedVector` to check 69 @param[in] mem_type Memory type to check 70 @param[out] has_borrowed_array_of_type Variable to store result 71 72 @return An error code: 0 - success, otherwise - failure 73 74 @ref Backend 75 **/ 76 int CeedVectorHasBorrowedArrayOfType(CeedVector vec, CeedMemType mem_type, bool *has_borrowed_array_of_type) { 77 CeedCheck(vec->HasBorrowedArrayOfType, CeedVectorReturnCeed(vec), CEED_ERROR_UNSUPPORTED, 78 "Backend does not support CeedVectorHasBorrowedArrayOfType"); 79 CeedCall(vec->HasBorrowedArrayOfType(vec, mem_type, has_borrowed_array_of_type)); 80 return CEED_ERROR_SUCCESS; 81 } 82 83 /** 84 @brief Get the state of a `CeedVector` 85 86 @param[in] vec `CeedVector` to retrieve state 87 @param[out] state Variable to store state 88 89 @return An error code: 0 - success, otherwise - failure 90 91 @ref Backend 92 **/ 93 int CeedVectorGetState(CeedVector vec, uint64_t *state) { 94 *state = vec->state; 95 return CEED_ERROR_SUCCESS; 96 } 97 98 /** 99 @brief Get the backend data of a `CeedVector` 100 101 @param[in] vec `CeedVector` to retrieve state 102 @param[out] data Variable to store data 103 104 @return An error code: 0 - success, otherwise - failure 105 106 @ref Backend 107 **/ 108 int CeedVectorGetData(CeedVector vec, void *data) { 109 *(void **)data = vec->data; 110 return CEED_ERROR_SUCCESS; 111 } 112 113 /** 114 @brief Set the backend data of a `CeedVector` 115 116 @param[in,out] vec `CeedVector` to retrieve state 117 @param[in] data Data to set 118 119 @return An error code: 0 - success, otherwise - failure 120 121 @ref Backend 122 **/ 123 int CeedVectorSetData(CeedVector vec, void *data) { 124 vec->data = data; 125 return CEED_ERROR_SUCCESS; 126 } 127 128 /** 129 @brief Increment the reference counter for a `CeedVector` 130 131 @param[in,out] vec `CeedVector` to increment the reference counter 132 133 @return An error code: 0 - success, otherwise - failure 134 135 @ref Backend 136 **/ 137 int CeedVectorReference(CeedVector vec) { 138 vec->ref_count++; 139 return CEED_ERROR_SUCCESS; 140 } 141 142 /// @} 143 144 /// ---------------------------------------------------------------------------- 145 /// CeedVector Public API 146 /// ---------------------------------------------------------------------------- 147 /// @addtogroup CeedVectorUser 148 /// @{ 149 150 /** 151 @brief Create a `CeedVector` of the specified length (does not allocate memory) 152 153 @param[in] ceed `Ceed` object used to create the `CeedVector` 154 @param[in] length Length of vector 155 @param[out] vec Address of the variable where the newly created `CeedVector` will be stored 156 157 @return An error code: 0 - success, otherwise - failure 158 159 @ref User 160 **/ 161 int CeedVectorCreate(Ceed ceed, CeedSize length, CeedVector *vec) { 162 if (!ceed->VectorCreate) { 163 Ceed delegate; 164 165 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Vector")); 166 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement VectorCreate"); 167 CeedCall(CeedVectorCreate(delegate, length, vec)); 168 CeedCall(CeedDestroy(&delegate)); 169 return CEED_ERROR_SUCCESS; 170 } 171 172 CeedCall(CeedCalloc(1, vec)); 173 CeedCall(CeedReferenceCopy(ceed, &(*vec)->ceed)); 174 (*vec)->ref_count = 1; 175 (*vec)->length = length; 176 (*vec)->state = 0; 177 CeedCall(ceed->VectorCreate(length, *vec)); 178 return CEED_ERROR_SUCCESS; 179 } 180 181 /** 182 @brief Copy the pointer to a `CeedVector`. 183 184 Both pointers should be destroyed with @ref CeedVectorDestroy(). 185 186 Note: If the value of `*vec_copy` passed to this function is non-`NULL`, then it is assumed that `*vec_copy` is a pointer to a `CeedVector`. 187 This `CeedVector` will be destroyed if `*vec_copy` is the only reference to this `CeedVector`. 188 189 @param[in] vec `CeedVector` to copy reference to 190 @param[in,out] vec_copy Variable to store copied reference 191 192 @return An error code: 0 - success, otherwise - failure 193 194 @ref User 195 **/ 196 int CeedVectorReferenceCopy(CeedVector vec, CeedVector *vec_copy) { 197 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) CeedCall(CeedVectorReference(vec)); 198 CeedCall(CeedVectorDestroy(vec_copy)); 199 *vec_copy = vec; 200 return CEED_ERROR_SUCCESS; 201 } 202 203 /** 204 @brief Copy a `CeedVector` into a different `CeedVector`. 205 206 @param[in] vec `CeedVector` to copy 207 @param[in,out] vec_copy `CeedVector` to copy array into 208 209 @return An error code: 0 - success, otherwise - failure 210 211 @ref User 212 **/ 213 int CeedVectorCopy(CeedVector vec, CeedVector vec_copy) { 214 CeedMemType mem_type, mem_type_copy; 215 CeedScalar *array; 216 217 // Get the preferred memory types 218 { 219 Ceed ceed; 220 221 CeedCall(CeedVectorGetCeed(vec, &ceed)); 222 CeedCall(CeedGetPreferredMemType(ceed, &mem_type)); 223 CeedCall(CeedDestroy(&ceed)); 224 225 CeedCall(CeedVectorGetCeed(vec_copy, &ceed)); 226 CeedCall(CeedGetPreferredMemType(ceed, &mem_type_copy)); 227 CeedCall(CeedDestroy(&ceed)); 228 } 229 230 // Check that both have same memory type 231 if (mem_type != mem_type_copy) mem_type = CEED_MEM_HOST; 232 233 // Check compatible lengths 234 { 235 CeedSize length_vec, length_copy; 236 237 CeedCall(CeedVectorGetLength(vec, &length_vec)); 238 CeedCall(CeedVectorGetLength(vec_copy, &length_copy)); 239 CeedCheck(length_vec == length_copy, CeedVectorReturnCeed(vec), CEED_ERROR_INCOMPATIBLE, "CeedVectors must have the same length to copy"); 240 } 241 242 // Copy the values from vec to vec_copy 243 CeedCall(CeedVectorGetArray(vec, mem_type, &array)); 244 CeedCall(CeedVectorSetArray(vec_copy, mem_type, CEED_COPY_VALUES, array)); 245 246 CeedCall(CeedVectorRestoreArray(vec, &array)); 247 return CEED_ERROR_SUCCESS; 248 } 249 250 /** 251 @brief Copy a strided portion of `CeedVector` contents into a different `CeedVector` 252 253 @param[in] vec `CeedVector` to copy 254 @param[in] start First index to copy 255 @param[in] step Stride between indices to copy 256 @param[in,out] vec_copy `CeedVector` to copy values to 257 258 @return An error code: 0 - success, otherwise - failure 259 260 @ref User 261 **/ 262 int CeedVectorCopyStrided(CeedVector vec, CeedSize start, CeedInt step, CeedVector vec_copy) { 263 CeedSize length; 264 const CeedScalar *array = NULL; 265 CeedScalar *array_copy = NULL; 266 267 // Backend version 268 if (vec->CopyStrided && vec_copy->CopyStrided) { 269 CeedCall(vec->CopyStrided(vec, start, step, vec_copy)); 270 vec_copy->state += 2; 271 return CEED_ERROR_SUCCESS; 272 } 273 274 // Get length 275 { 276 CeedSize length_vec, length_copy; 277 278 CeedCall(CeedVectorGetLength(vec, &length_vec)); 279 CeedCall(CeedVectorGetLength(vec_copy, &length_copy)); 280 if (length_vec <= 0 || length_copy <= 0) return CEED_ERROR_SUCCESS; 281 length = length_vec < length_copy ? length_vec : length_copy; 282 } 283 284 // Copy 285 CeedCall(CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array)); 286 CeedCall(CeedVectorGetArray(vec_copy, CEED_MEM_HOST, &array_copy)); 287 for (CeedSize i = start; i < length; i += step) array_copy[i] = array[i]; 288 289 // Cleanup 290 CeedCall(CeedVectorRestoreArrayRead(vec, &array)); 291 CeedCall(CeedVectorRestoreArray(vec_copy, &array_copy)); 292 return CEED_ERROR_SUCCESS; 293 } 294 295 /** 296 @brief Set the array used by a `CeedVector`, freeing any previously allocated array if applicable. 297 298 The backend may copy values to a different @ref CeedMemType, such as during @ref CeedOperatorApply(). 299 See also @ref CeedVectorSyncArray() and @ref CeedVectorTakeArray(). 300 301 @param[in,out] vec `CeedVector` 302 @param[in] mem_type Memory type of the array being passed 303 @param[in] copy_mode Copy mode for the array 304 @param[in] array Array to be used, or `NULL` with @ref CEED_COPY_VALUES to have the library allocate 305 306 @return An error code: 0 - success, otherwise - failure 307 308 @ref User 309 **/ 310 int CeedVectorSetArray(CeedVector vec, CeedMemType mem_type, CeedCopyMode copy_mode, CeedScalar *array) { 311 CeedSize length; 312 313 CeedCheck(vec->SetArray, CeedVectorReturnCeed(vec), CEED_ERROR_UNSUPPORTED, "Backend does not support VectorSetArray"); 314 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 315 "Cannot grant CeedVector array access, the access lock is already in use"); 316 CeedCheck(vec->num_readers == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 317 318 CeedCall(CeedVectorGetLength(vec, &length)); 319 if (length > 0) CeedCall(vec->SetArray(vec, mem_type, copy_mode, array)); 320 vec->state += 2; 321 return CEED_ERROR_SUCCESS; 322 } 323 324 /** 325 @brief Set the `CeedVector` to a constant value 326 327 @param[in,out] vec `CeedVector` 328 @param[in] value Value to be used 329 330 @return An error code: 0 - success, otherwise - failure 331 332 @ref User 333 **/ 334 int CeedVectorSetValue(CeedVector vec, CeedScalar value) { 335 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 336 "Cannot grant CeedVector array access, the access lock is already in use"); 337 CeedCheck(vec->num_readers == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 338 339 if (vec->SetValue) { 340 CeedCall(vec->SetValue(vec, value)); 341 vec->state += 2; 342 } else { 343 CeedSize length; 344 CeedScalar *array; 345 346 CeedCall(CeedVectorGetArrayWrite(vec, CEED_MEM_HOST, &array)); 347 CeedCall(CeedVectorGetLength(vec, &length)); 348 for (CeedSize i = 0; i < length; i++) array[i] = value; 349 CeedCall(CeedVectorRestoreArray(vec, &array)); 350 } 351 return CEED_ERROR_SUCCESS; 352 } 353 354 /** 355 @brief Set a portion of a `CeedVector` to a constant value. 356 357 Note: The `CeedVector` must already have valid data set via @ref CeedVectorSetArray() or similar. 358 359 @param[in,out] vec `CeedVector` 360 @param[in] start First index to set in range `[start, stop)` 361 @param[in] stop Last index to set in range `[start, stop)`, or `-1` for `length` 362 @param[in] step Stride between indices to set 363 @param[in] value Value to be used 364 365 @return An error code: 0 - success, otherwise - failure 366 367 @ref User 368 **/ 369 int CeedVectorSetValueStrided(CeedVector vec, CeedSize start, CeedSize stop, CeedSize step, CeedScalar value) { 370 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 371 "Cannot grant CeedVector array access, the access lock is already in use"); 372 CeedCheck(vec->num_readers == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 373 374 if (vec->SetValueStrided) { 375 CeedCall(vec->SetValueStrided(vec, start, stop, step, value)); 376 vec->state += 2; 377 } else { 378 CeedSize length; 379 CeedScalar *array; 380 381 CeedCall(CeedVectorGetLength(vec, &length)); 382 if (length <= 0) return CEED_ERROR_SUCCESS; 383 if (stop == -1) stop = length; 384 CeedCall(CeedVectorGetArray(vec, CEED_MEM_HOST, &array)); 385 for (CeedSize i = start; i < stop; i += step) array[i] = value; 386 CeedCall(CeedVectorRestoreArray(vec, &array)); 387 } 388 return CEED_ERROR_SUCCESS; 389 } 390 391 /** 392 @brief Sync the `CeedVector` to a specified `mem_type`. 393 394 This function is used to force synchronization of arrays set with @ref CeedVectorSetArray(). 395 If the requested `mem_type` is already synchronized, this function results in a no-op. 396 397 @param[in,out] vec `CeedVector` 398 @param[in] mem_type @ref CeedMemType to be synced 399 400 @return An error code: 0 - success, otherwise - failure 401 402 @ref User 403 **/ 404 int CeedVectorSyncArray(CeedVector vec, CeedMemType mem_type) { 405 CeedSize length; 406 407 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot sync CeedVector, the access lock is already in use"); 408 409 // Don't sync empty array 410 CeedCall(CeedVectorGetLength(vec, &length)); 411 if (length == 0) return CEED_ERROR_SUCCESS; 412 413 if (vec->SyncArray) { 414 CeedCall(vec->SyncArray(vec, mem_type)); 415 } else { 416 const CeedScalar *array; 417 418 CeedCall(CeedVectorGetArrayRead(vec, mem_type, &array)); 419 CeedCall(CeedVectorRestoreArrayRead(vec, &array)); 420 } 421 return CEED_ERROR_SUCCESS; 422 } 423 424 /** 425 @brief Take ownership of the `CeedVector` array set by @ref CeedVectorSetArray() with @ref CEED_USE_POINTER and remove the array from the `CeedVector`. 426 427 The caller is responsible for managing and freeing the array. 428 This function will error if @ref CeedVectorSetArray() was not previously called with @ref CEED_USE_POINTER for the corresponding mem_type. 429 430 @param[in,out] vec `CeedVector` 431 @param[in] mem_type Memory type on which to take the array. 432 If the backend uses a different memory type, this will perform a copy. 433 @param[out] array Array on memory type `mem_type`, or `NULL` if array pointer is not required 434 435 @return An error code: 0 - success, otherwise - failure 436 437 @ref User 438 **/ 439 int CeedVectorTakeArray(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 440 CeedSize length; 441 CeedScalar *temp_array = NULL; 442 443 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot take CeedVector array, the access lock is already in use"); 444 CeedCheck(vec->num_readers == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot take CeedVector array, a process has read access"); 445 446 CeedCall(CeedVectorGetLength(vec, &length)); 447 if (length > 0) { 448 bool has_borrowed_array_of_type = true, has_valid_array = true; 449 450 CeedCall(CeedVectorHasBorrowedArrayOfType(vec, mem_type, &has_borrowed_array_of_type)); 451 CeedCheck(has_borrowed_array_of_type, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 452 "CeedVector has no borrowed %s array, must set array with CeedVectorSetArray", CeedMemTypes[mem_type]); 453 454 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 455 CeedCheck(has_valid_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 456 "CeedVector has no valid data to take, must set data with CeedVectorSetValue or CeedVectorSetArray"); 457 458 CeedCall(vec->TakeArray(vec, mem_type, &temp_array)); 459 } 460 if (array) (*array) = temp_array; 461 return CEED_ERROR_SUCCESS; 462 } 463 464 /** 465 @brief Get read/write access to a `CeedVector` via the specified memory type. 466 467 Restore access with @ref CeedVectorRestoreArray(). 468 469 @param[in,out] vec `CeedVector` to access 470 @param[in] mem_type Memory type on which to access the array. 471 If the backend uses a different memory type, this will perform a copy. 472 @param[out] array Array on memory type `mem_type` 473 474 @note The @ref CeedVectorGetArray() and @ref CeedVectorRestoreArray() functions provide access to array pointers in the desired memory space. 475 Pairing get/restore allows the `CeedVector` to track access, thus knowing if norms or other operations may need to be recomputed. 476 477 @return An error code: 0 - success, otherwise - failure 478 479 @ref User 480 **/ 481 int CeedVectorGetArray(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 482 CeedSize length; 483 484 CeedCheck(vec->GetArray, CeedVectorReturnCeed(vec), CEED_ERROR_UNSUPPORTED, "Backend does not support GetArray"); 485 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 486 "Cannot grant CeedVector array access, the access lock is already in use"); 487 CeedCheck(vec->num_readers == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 488 489 CeedCall(CeedVectorGetLength(vec, &length)); 490 if (length > 0) { 491 bool has_valid_array = true; 492 493 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 494 CeedCheck(has_valid_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 495 "CeedVector has no valid data to read, must set data with CeedVectorSetValue or CeedVectorSetArray"); 496 497 CeedCall(vec->GetArray(vec, mem_type, array)); 498 } else { 499 *array = NULL; 500 } 501 vec->state++; 502 return CEED_ERROR_SUCCESS; 503 } 504 505 /** 506 @brief Get read-only access to a `CeedVector` via the specified memory type. 507 508 Restore access with @ref CeedVectorRestoreArrayRead(). 509 510 @param[in] vec `CeedVector` to access 511 @param[in] mem_type Memory type on which to access the array. 512 If the backend uses a different memory type, this will perform a copy (possibly cached). 513 @param[out] array Array on memory type `mem_type` 514 515 @return An error code: 0 - success, otherwise - failure 516 517 @ref User 518 **/ 519 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mem_type, const CeedScalar **array) { 520 CeedSize length; 521 522 CeedCheck(vec->GetArrayRead, CeedVectorReturnCeed(vec), CEED_ERROR_UNSUPPORTED, "Backend does not support GetArrayRead"); 523 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 524 "Cannot grant CeedVector read-only array access, the access lock is already in use"); 525 526 CeedCall(CeedVectorGetLength(vec, &length)); 527 if (length > 0) { 528 bool has_valid_array = true; 529 530 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 531 CeedCheck(has_valid_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 532 "CeedVector has no valid data to read, must set data with CeedVectorSetValue or CeedVectorSetArray"); 533 534 CeedCall(vec->GetArrayRead(vec, mem_type, array)); 535 } else { 536 *array = NULL; 537 } 538 vec->num_readers++; 539 return CEED_ERROR_SUCCESS; 540 } 541 542 /** 543 @brief Get write access to a `CeedVector` via the specified memory type. 544 545 Restore access with @ref CeedVectorRestoreArray(). 546 All old values should be assumed to be invalid. 547 548 @param[in,out] vec `CeedVector` to access 549 @param[in] mem_type Memory type on which to access the array. 550 @param[out] array Array on memory type `mem_type` 551 552 @return An error code: 0 - success, otherwise - failure 553 554 @ref User 555 **/ 556 int CeedVectorGetArrayWrite(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 557 CeedSize length; 558 559 CeedCheck(vec->GetArrayWrite, CeedVectorReturnCeed(vec), CEED_ERROR_UNSUPPORTED, "Backend does not support CeedVectorGetArrayWrite"); 560 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 561 "Cannot grant CeedVector array access, the access lock is already in use"); 562 CeedCheck(vec->num_readers == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 563 564 CeedCall(CeedVectorGetLength(vec, &length)); 565 if (length > 0) { 566 CeedCall(vec->GetArrayWrite(vec, mem_type, array)); 567 } else { 568 *array = NULL; 569 } 570 vec->state++; 571 return CEED_ERROR_SUCCESS; 572 } 573 574 /** 575 @brief Restore an array obtained using @ref CeedVectorGetArray() or @ref CeedVectorGetArrayWrite() 576 577 @param[in,out] vec `CeedVector` to restore 578 @param[in,out] array Array of vector data 579 580 @return An error code: 0 - success, otherwise - failure 581 582 @ref User 583 **/ 584 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) { 585 CeedSize length; 586 587 CeedCheck(vec->state % 2 == 1, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot restore CeedVector array access, access was not granted"); 588 CeedCall(CeedVectorGetLength(vec, &length)); 589 if (length > 0 && vec->RestoreArray) CeedCall(vec->RestoreArray(vec)); 590 *array = NULL; 591 vec->state++; 592 return CEED_ERROR_SUCCESS; 593 } 594 595 /** 596 @brief Restore an array obtained using @ref CeedVectorGetArrayRead() 597 598 @param[in] vec `CeedVector` to restore 599 @param[in,out] array Array of vector data 600 601 @return An error code: 0 - success, otherwise - failure 602 603 @ref User 604 **/ 605 int CeedVectorRestoreArrayRead(CeedVector vec, const CeedScalar **array) { 606 CeedSize length; 607 608 CeedCheck(vec->num_readers > 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 609 "Cannot restore CeedVector array read access, access was not granted"); 610 vec->num_readers--; 611 CeedCall(CeedVectorGetLength(vec, &length)); 612 if (length > 0 && vec->num_readers == 0 && vec->RestoreArrayRead) CeedCall(vec->RestoreArrayRead(vec)); 613 *array = NULL; 614 return CEED_ERROR_SUCCESS; 615 } 616 617 /** 618 @brief Get the norm of a `CeedVector`. 619 620 Note: This operation is local to the `CeedVector`. 621 This function will likely not provide the desired results for the norm of the libCEED portion of a parallel vector or a `CeedVector` with duplicated or hanging nodes. 622 623 @param[in] vec `CeedVector` to retrieve maximum value 624 @param[in] norm_type Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX 625 @param[out] norm Variable to store norm value 626 627 @return An error code: 0 - success, otherwise - failure 628 629 @ref User 630 **/ 631 int CeedVectorNorm(CeedVector vec, CeedNormType norm_type, CeedScalar *norm) { 632 bool has_valid_array = true; 633 CeedSize length; 634 635 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 636 CeedCheck(has_valid_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 637 "CeedVector has no valid data to compute norm, must set data with CeedVectorSetValue or CeedVectorSetArray"); 638 639 CeedCall(CeedVectorGetLength(vec, &length)); 640 if (length == 0) { 641 *norm = 0; 642 return CEED_ERROR_SUCCESS; 643 } 644 645 // Backend impl for GPU, if added 646 if (vec->Norm) { 647 CeedCall(vec->Norm(vec, norm_type, norm)); 648 return CEED_ERROR_SUCCESS; 649 } 650 651 const CeedScalar *array; 652 CeedCall(CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array)); 653 assert(array); 654 655 *norm = 0.; 656 switch (norm_type) { 657 case CEED_NORM_1: 658 for (CeedSize i = 0; i < length; i++) { 659 *norm += fabs(array[i]); 660 } 661 break; 662 case CEED_NORM_2: 663 for (CeedSize i = 0; i < length; i++) { 664 *norm += fabs(array[i]) * fabs(array[i]); 665 } 666 break; 667 case CEED_NORM_MAX: 668 for (CeedSize i = 0; i < length; i++) { 669 const CeedScalar abs_v_i = fabs(array[i]); 670 *norm = *norm > abs_v_i ? *norm : abs_v_i; 671 } 672 } 673 if (norm_type == CEED_NORM_2) *norm = sqrt(*norm); 674 675 CeedCall(CeedVectorRestoreArrayRead(vec, &array)); 676 return CEED_ERROR_SUCCESS; 677 } 678 679 /** 680 @brief Compute `x = alpha x` 681 682 @param[in,out] x `CeedVector` for scaling 683 @param[in] alpha scaling factor 684 685 @return An error code: 0 - success, otherwise - failure 686 687 @ref User 688 **/ 689 int CeedVectorScale(CeedVector x, CeedScalar alpha) { 690 bool has_valid_array = true; 691 CeedSize length; 692 CeedScalar *x_array = NULL; 693 694 CeedCall(CeedVectorHasValidArray(x, &has_valid_array)); 695 CeedCheck(has_valid_array, CeedVectorReturnCeed(x), CEED_ERROR_BACKEND, 696 "CeedVector has no valid data to scale, must set data with CeedVectorSetValue or CeedVectorSetArray"); 697 698 // Return early for empty vector 699 CeedCall(CeedVectorGetLength(x, &length)); 700 if (length == 0) return CEED_ERROR_SUCCESS; 701 702 // Backend implementation 703 if (x->Scale) return x->Scale(x, alpha); 704 705 // Default implementation 706 CeedCall(CeedVectorGetArray(x, CEED_MEM_HOST, &x_array)); 707 assert(x_array); 708 for (CeedSize i = 0; i < length; i++) x_array[i] *= alpha; 709 CeedCall(CeedVectorRestoreArray(x, &x_array)); 710 return CEED_ERROR_SUCCESS; 711 } 712 713 /** 714 @brief Compute `y = alpha x + y` 715 716 @param[in,out] y target `CeedVector` for sum 717 @param[in] alpha scaling factor 718 @param[in] x second `CeedVector`, must be different than ``y` 719 720 @return An error code: 0 - success, otherwise - failure 721 722 @ref User 723 **/ 724 int CeedVectorAXPY(CeedVector y, CeedScalar alpha, CeedVector x) { 725 bool has_valid_array_x = true, has_valid_array_y = true; 726 CeedSize length_x, length_y; 727 CeedScalar *y_array = NULL; 728 CeedScalar const *x_array = NULL; 729 730 CeedCall(CeedVectorGetLength(y, &length_y)); 731 CeedCall(CeedVectorGetLength(x, &length_x)); 732 CeedCheck(length_x == length_y, CeedVectorReturnCeed(y), CEED_ERROR_UNSUPPORTED, 733 "Cannot add vector of different lengths." 734 " x length: %" CeedSize_FMT " y length: %" CeedSize_FMT, 735 length_x, length_y); 736 CeedCheck(x != y, CeedVectorReturnCeed(y), CEED_ERROR_UNSUPPORTED, "Cannot use same vector for x and y in CeedVectorAXPY"); 737 738 CeedCall(CeedVectorHasValidArray(x, &has_valid_array_x)); 739 CeedCheck(has_valid_array_x, CeedVectorReturnCeed(y), CEED_ERROR_BACKEND, 740 "CeedVector x has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 741 CeedCall(CeedVectorHasValidArray(y, &has_valid_array_y)); 742 CeedCheck(has_valid_array_y, CeedVectorReturnCeed(y), CEED_ERROR_BACKEND, 743 "CeedVector y has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 744 745 { 746 Ceed ceed_x, ceed_y, ceed_parent_x, ceed_parent_y; 747 748 CeedCall(CeedVectorGetCeed(y, &ceed_y)); 749 CeedCall(CeedVectorGetCeed(x, &ceed_x)); 750 CeedCall(CeedGetParent(ceed_x, &ceed_parent_x)); 751 CeedCall(CeedGetParent(ceed_y, &ceed_parent_y)); 752 CeedCall(CeedDestroy(&ceed_x)); 753 CeedCall(CeedDestroy(&ceed_y)); 754 CeedCheck(ceed_parent_x == ceed_parent_y, CeedVectorReturnCeed(y), CEED_ERROR_INCOMPATIBLE, 755 "Vectors x and y must be created by the same Ceed context"); 756 CeedCall(CeedDestroy(&ceed_parent_x)); 757 CeedCall(CeedDestroy(&ceed_parent_y)); 758 } 759 760 // Return early for empty vectors 761 if (length_y == 0) return CEED_ERROR_SUCCESS; 762 763 // Backend implementation 764 if (y->AXPY) { 765 CeedCall(y->AXPY(y, alpha, x)); 766 return CEED_ERROR_SUCCESS; 767 } 768 769 // Default implementation 770 CeedCall(CeedVectorGetArray(y, CEED_MEM_HOST, &y_array)); 771 CeedCall(CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array)); 772 773 assert(x_array); 774 assert(y_array); 775 776 for (CeedSize i = 0; i < length_y; i++) y_array[i] += alpha * x_array[i]; 777 778 CeedCall(CeedVectorRestoreArray(y, &y_array)); 779 CeedCall(CeedVectorRestoreArrayRead(x, &x_array)); 780 return CEED_ERROR_SUCCESS; 781 } 782 783 /** 784 @brief Compute `y = alpha x + beta y` 785 786 @param[in,out] y target `CeedVector` for sum 787 @param[in] alpha first scaling factor 788 @param[in] beta second scaling factor 789 @param[in] x second `CeedVector`, must be different than `y` 790 791 @return An error code: 0 - success, otherwise - failure 792 793 @ref User 794 **/ 795 int CeedVectorAXPBY(CeedVector y, CeedScalar alpha, CeedScalar beta, CeedVector x) { 796 bool has_valid_array_x = true, has_valid_array_y = true; 797 CeedSize length_x, length_y; 798 CeedScalar *y_array = NULL; 799 CeedScalar const *x_array = NULL; 800 801 CeedCall(CeedVectorGetLength(y, &length_y)); 802 CeedCall(CeedVectorGetLength(x, &length_x)); 803 CeedCheck(length_x == length_y, CeedVectorReturnCeed(y), CEED_ERROR_UNSUPPORTED, 804 "Cannot add vector of different lengths." 805 " x length: %" CeedSize_FMT " y length: %" CeedSize_FMT, 806 length_x, length_y); 807 CeedCheck(x != y, CeedVectorReturnCeed(y), CEED_ERROR_UNSUPPORTED, "Cannot use same vector for x and y in CeedVectorAXPBY"); 808 809 CeedCall(CeedVectorHasValidArray(x, &has_valid_array_x)); 810 CeedCheck(has_valid_array_x, CeedVectorReturnCeed(y), CEED_ERROR_BACKEND, 811 "CeedVector x has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 812 CeedCall(CeedVectorHasValidArray(y, &has_valid_array_y)); 813 CeedCheck(has_valid_array_y, CeedVectorReturnCeed(y), CEED_ERROR_BACKEND, 814 "CeedVector y has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 815 816 { 817 Ceed ceed_x, ceed_y, ceed_parent_x, ceed_parent_y; 818 819 CeedCall(CeedVectorGetCeed(y, &ceed_y)); 820 CeedCall(CeedVectorGetCeed(x, &ceed_x)); 821 CeedCall(CeedGetParent(ceed_x, &ceed_parent_x)); 822 CeedCall(CeedGetParent(ceed_y, &ceed_parent_y)); 823 CeedCall(CeedDestroy(&ceed_x)); 824 CeedCall(CeedDestroy(&ceed_y)); 825 CeedCheck(ceed_parent_x == ceed_parent_y, CeedVectorReturnCeed(y), CEED_ERROR_INCOMPATIBLE, 826 "Vectors x and y must be created by the same Ceed context"); 827 CeedCall(CeedDestroy(&ceed_parent_x)); 828 CeedCall(CeedDestroy(&ceed_parent_y)); 829 } 830 831 // Return early for empty vectors 832 if (length_y == 0) return CEED_ERROR_SUCCESS; 833 834 // Backend implementation 835 if (y->AXPBY) { 836 CeedCall(y->AXPBY(y, alpha, beta, x)); 837 return CEED_ERROR_SUCCESS; 838 } 839 840 // Default implementation 841 CeedCall(CeedVectorGetArray(y, CEED_MEM_HOST, &y_array)); 842 CeedCall(CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array)); 843 844 assert(x_array); 845 assert(y_array); 846 847 for (CeedSize i = 0; i < length_y; i++) y_array[i] = alpha * x_array[i] + beta * y_array[i]; 848 849 CeedCall(CeedVectorRestoreArray(y, &y_array)); 850 CeedCall(CeedVectorRestoreArrayRead(x, &x_array)); 851 return CEED_ERROR_SUCCESS; 852 } 853 854 /** 855 @brief Compute the pointwise multiplication \f$w = x .* y\f$. 856 857 Any subset of `x`, `y`, and `w` may be the same `CeedVector`. 858 859 @param[out] w target `CeedVector` for the product 860 @param[in] x first `CeedVector` for product 861 @param[in] y second `CeedVector` for the product 862 863 @return An error code: 0 - success, otherwise - failure 864 865 @ref User 866 **/ 867 int CeedVectorPointwiseMult(CeedVector w, CeedVector x, CeedVector y) { 868 bool has_valid_array_x = true, has_valid_array_y = true; 869 CeedScalar *w_array = NULL; 870 CeedScalar const *x_array = NULL, *y_array = NULL; 871 CeedSize length_w, length_x, length_y; 872 873 CeedCall(CeedVectorGetLength(w, &length_w)); 874 CeedCall(CeedVectorGetLength(x, &length_x)); 875 CeedCall(CeedVectorGetLength(y, &length_y)); 876 CeedCheck(length_x >= length_w && length_y >= length_w, CeedVectorReturnCeed(w), CEED_ERROR_UNSUPPORTED, 877 "Cannot pointwise multiply vectors of incompatible lengths." 878 " w length: %" CeedSize_FMT " x length: %" CeedSize_FMT " y length: %" CeedSize_FMT, 879 length_w, length_x, length_y); 880 881 { 882 Ceed ceed_w, ceed_x, ceed_y, ceed_parent_w, ceed_parent_x, ceed_parent_y; 883 884 CeedCall(CeedVectorGetCeed(w, &ceed_w)); 885 CeedCall(CeedVectorGetCeed(x, &ceed_x)); 886 CeedCall(CeedVectorGetCeed(y, &ceed_y)); 887 CeedCall(CeedGetParent(ceed_w, &ceed_parent_w)); 888 CeedCall(CeedGetParent(ceed_x, &ceed_parent_x)); 889 CeedCall(CeedGetParent(ceed_y, &ceed_parent_y)); 890 CeedCall(CeedDestroy(&ceed_w)); 891 CeedCall(CeedDestroy(&ceed_x)); 892 CeedCall(CeedDestroy(&ceed_y)); 893 CeedCheck(ceed_parent_w == ceed_parent_x && ceed_parent_w == ceed_parent_y, CeedVectorReturnCeed(w), CEED_ERROR_INCOMPATIBLE, 894 "Vectors w, x, and y must be created by the same Ceed context"); 895 CeedCall(CeedDestroy(&ceed_parent_w)); 896 CeedCall(CeedDestroy(&ceed_parent_x)); 897 CeedCall(CeedDestroy(&ceed_parent_y)); 898 } 899 900 CeedCall(CeedVectorHasValidArray(x, &has_valid_array_x)); 901 CeedCheck(has_valid_array_x, CeedVectorReturnCeed(w), CEED_ERROR_BACKEND, 902 "CeedVector x has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 903 CeedCall(CeedVectorHasValidArray(y, &has_valid_array_y)); 904 CeedCheck(has_valid_array_y, CeedVectorReturnCeed(w), CEED_ERROR_BACKEND, 905 "CeedVector y has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 906 907 // Return early for empty vectors 908 if (length_w == 0) return CEED_ERROR_SUCCESS; 909 910 // Backend implementation 911 if (w->PointwiseMult) { 912 CeedCall(w->PointwiseMult(w, x, y)); 913 return CEED_ERROR_SUCCESS; 914 } 915 916 // Default implementation 917 if (x == w || y == w) { 918 CeedCall(CeedVectorGetArray(w, CEED_MEM_HOST, &w_array)); 919 } else { 920 CeedCall(CeedVectorGetArrayWrite(w, CEED_MEM_HOST, &w_array)); 921 } 922 if (x != w) { 923 CeedCall(CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array)); 924 } else { 925 x_array = w_array; 926 } 927 if (y != w && y != x) { 928 CeedCall(CeedVectorGetArrayRead(y, CEED_MEM_HOST, &y_array)); 929 } else if (y == x) { 930 y_array = x_array; 931 } else if (y == w) { 932 y_array = w_array; 933 } 934 935 assert(w_array); 936 assert(x_array); 937 assert(y_array); 938 939 for (CeedSize i = 0; i < length_w; i++) w_array[i] = x_array[i] * y_array[i]; 940 941 if (y != w && y != x) CeedCall(CeedVectorRestoreArrayRead(y, &y_array)); 942 if (x != w) CeedCall(CeedVectorRestoreArrayRead(x, &x_array)); 943 CeedCall(CeedVectorRestoreArray(w, &w_array)); 944 return CEED_ERROR_SUCCESS; 945 } 946 947 /** 948 @brief Take the reciprocal of a `CeedVector`. 949 950 @param[in,out] vec `CeedVector` to take reciprocal 951 952 @return An error code: 0 - success, otherwise - failure 953 954 @ref User 955 **/ 956 int CeedVectorReciprocal(CeedVector vec) { 957 bool has_valid_array = true; 958 CeedSize length; 959 CeedScalar *array; 960 961 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 962 CeedCheck(has_valid_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 963 "CeedVector has no valid data to compute reciprocal, must set data with CeedVectorSetValue or CeedVectorSetArray"); 964 965 // Check if vector data set 966 CeedCheck(vec->state > 0, CeedVectorReturnCeed(vec), CEED_ERROR_INCOMPLETE, "CeedVector must have data set to take reciprocal"); 967 968 // Return early for empty vector 969 CeedCall(CeedVectorGetLength(vec, &length)); 970 if (length == 0) return CEED_ERROR_SUCCESS; 971 972 // Backend impl for GPU, if added 973 if (vec->Reciprocal) { 974 CeedCall(vec->Reciprocal(vec)); 975 return CEED_ERROR_SUCCESS; 976 } 977 978 CeedCall(CeedVectorGetArray(vec, CEED_MEM_HOST, &array)); 979 for (CeedSize i = 0; i < length; i++) { 980 if (fabs(array[i]) > CEED_EPSILON) array[i] = 1. / array[i]; 981 } 982 983 CeedCall(CeedVectorRestoreArray(vec, &array)); 984 return CEED_ERROR_SUCCESS; 985 } 986 987 /** 988 @brief View a `CeedVector` 989 990 Note: It is safe to use any unsigned values for `start` or `stop` and any nonzero integer for `step`. 991 Any portion of the provided range that is outside the range of valid indices for the `CeedVector` will be ignored. 992 993 @param[in] vec `CeedVector` to view 994 @param[in] start Index of first `CeedVector` entry to view 995 @param[in] stop Index of last `CeedVector` entry to view 996 @param[in] step Step between `CeedVector` entries to view 997 @param[in] fp_fmt Printing format 998 @param[in] stream Filestream to write to 999 1000 @return An error code: 0 - success, otherwise - failure 1001 1002 @ref User 1003 **/ 1004 int CeedVectorViewRange(CeedVector vec, CeedSize start, CeedSize stop, CeedInt step, const char *fp_fmt, FILE *stream) { 1005 char fmt[1024]; 1006 CeedSize length; 1007 const CeedScalar *x; 1008 1009 CeedCheck(step != 0, CeedVectorReturnCeed(vec), CEED_ERROR_MINOR, "View range 'step' must be nonzero"); 1010 1011 CeedCall(CeedVectorGetLength(vec, &length)); 1012 fprintf(stream, "CeedVector length %" CeedSize_FMT "\n", length); 1013 if (start != 0 || stop != length || step != 1) { 1014 fprintf(stream, " start: %" CeedSize_FMT "\n stop: %" CeedSize_FMT "\n step: %" CeedInt_FMT "\n", start, stop, step); 1015 } 1016 if (start > length) start = length; 1017 if (stop > length) stop = length; 1018 1019 snprintf(fmt, sizeof fmt, " %s\n", fp_fmt ? fp_fmt : "%g"); 1020 CeedCall(CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x)); 1021 for (CeedSize i = start; step > 0 ? (i < stop) : (i > stop); i += step) fprintf(stream, fmt, x[i]); 1022 CeedCall(CeedVectorRestoreArrayRead(vec, &x)); 1023 if (stop != length) fprintf(stream, " ...\n"); 1024 return CEED_ERROR_SUCCESS; 1025 } 1026 1027 /** 1028 @brief View a `CeedVector` 1029 1030 @param[in] vec `CeedVector` to view 1031 @param[in] fp_fmt Printing format 1032 @param[in] stream Filestream to write to 1033 1034 @return An error code: 0 - success, otherwise - failure 1035 1036 @ref User 1037 **/ 1038 int CeedVectorView(CeedVector vec, const char *fp_fmt, FILE *stream) { 1039 CeedSize length; 1040 1041 CeedCall(CeedVectorGetLength(vec, &length)); 1042 CeedCall(CeedVectorViewRange(vec, 0, length, 1, fp_fmt, stream)); 1043 return CEED_ERROR_SUCCESS; 1044 } 1045 1046 /** 1047 @brief Get the `Ceed` associated with a `CeedVector` 1048 1049 @param[in] vec `CeedVector` to retrieve state 1050 @param[out] ceed Variable to store `Ceed` 1051 1052 @return An error code: 0 - success, otherwise - failure 1053 1054 @ref Advanced 1055 **/ 1056 int CeedVectorGetCeed(CeedVector vec, Ceed *ceed) { 1057 *ceed = NULL; 1058 CeedCall(CeedReferenceCopy(CeedVectorReturnCeed(vec), ceed)); 1059 return CEED_ERROR_SUCCESS; 1060 } 1061 1062 /** 1063 @brief Return the `Ceed` associated with a `CeedVector` 1064 1065 @param[in] vec `CeedVector` to retrieve state 1066 1067 @return `Ceed` associated with the `vec` 1068 1069 @ref Advanced 1070 **/ 1071 Ceed CeedVectorReturnCeed(CeedVector vec) { return vec->ceed; } 1072 1073 /** 1074 @brief Get the length of a `CeedVector` 1075 1076 @param[in] vec `CeedVector` to retrieve length 1077 @param[out] length Variable to store length 1078 1079 @return An error code: 0 - success, otherwise - failure 1080 1081 @ref User 1082 **/ 1083 int CeedVectorGetLength(CeedVector vec, CeedSize *length) { 1084 *length = vec->length; 1085 return CEED_ERROR_SUCCESS; 1086 } 1087 1088 /** 1089 @brief Destroy a `CeedVector` 1090 1091 @param[in,out] vec `CeedVector` to destroy 1092 1093 @return An error code: 0 - success, otherwise - failure 1094 1095 @ref User 1096 **/ 1097 int CeedVectorDestroy(CeedVector *vec) { 1098 if (!*vec || *vec == CEED_VECTOR_ACTIVE || *vec == CEED_VECTOR_NONE || --(*vec)->ref_count > 0) { 1099 *vec = NULL; 1100 return CEED_ERROR_SUCCESS; 1101 } 1102 CeedCheck((*vec)->state % 2 == 0, (*vec)->ceed, CEED_ERROR_ACCESS, "Cannot destroy CeedVector, the writable access lock is in use"); 1103 CeedCheck((*vec)->num_readers == 0, (*vec)->ceed, CEED_ERROR_ACCESS, "Cannot destroy CeedVector, a process has read access"); 1104 1105 if ((*vec)->Destroy) CeedCall((*vec)->Destroy(*vec)); 1106 1107 CeedCall(CeedDestroy(&(*vec)->ceed)); 1108 CeedCall(CeedFree(vec)); 1109 return CEED_ERROR_SUCCESS; 1110 } 1111 1112 /// @} 1113