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