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