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 in the range `[start, stop)` 255 @param[in] stop One past the last element to copy in the range, or `-1` for `length` 256 @param[in] step Stride between indices to copy 257 @param[in,out] vec_copy `CeedVector` to copy values to 258 259 @return An error code: 0 - success, otherwise - failure 260 261 @ref User 262 **/ 263 int CeedVectorCopyStrided(CeedVector vec, CeedSize start, CeedSize stop, CeedSize step, CeedVector vec_copy) { 264 CeedSize length; 265 const CeedScalar *array = NULL; 266 CeedScalar *array_copy = NULL; 267 268 // Check length 269 { 270 CeedSize length_vec, length_copy; 271 272 CeedCall(CeedVectorGetLength(vec, &length_vec)); 273 CeedCall(CeedVectorGetLength(vec_copy, &length_copy)); 274 if (length_vec <= 0 || length_copy <= 0) return CEED_ERROR_SUCCESS; 275 length = length_vec < length_copy ? length_vec : length_copy; 276 } 277 CeedCheck(stop >= -1 && stop <= length, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 278 "Invalid value for stop %" CeedSize_FMT ", must be in the range [-1, length]", stop); 279 CeedCheck(start >= 0 && start <= length && (start <= stop || stop == -1), CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 280 "Invalid value for start %" CeedSize_FMT ", must be in the range [0, stop]", start); 281 282 // Backend version 283 if (vec->CopyStrided && vec_copy->CopyStrided) { 284 CeedCall(vec->CopyStrided(vec, start, stop, step, vec_copy)); 285 vec_copy->state += 2; 286 return CEED_ERROR_SUCCESS; 287 } 288 289 // Copy 290 CeedCall(CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array)); 291 CeedCall(CeedVectorGetArray(vec_copy, CEED_MEM_HOST, &array_copy)); 292 if (stop == -1) stop = length; 293 for (CeedSize i = start; i < stop; i += step) array_copy[i] = array[i]; 294 295 // Cleanup 296 CeedCall(CeedVectorRestoreArrayRead(vec, &array)); 297 CeedCall(CeedVectorRestoreArray(vec_copy, &array_copy)); 298 return CEED_ERROR_SUCCESS; 299 } 300 301 /** 302 @brief Set the array used by a `CeedVector`, freeing any previously allocated array if applicable. 303 304 The backend may copy values to a different @ref CeedMemType, such as during @ref CeedOperatorApply(). 305 See also @ref CeedVectorSyncArray() and @ref CeedVectorTakeArray(). 306 307 @param[in,out] vec `CeedVector` 308 @param[in] mem_type Memory type of the array being passed 309 @param[in] copy_mode Copy mode for the array 310 @param[in] array Array to be used, or `NULL` with @ref CEED_COPY_VALUES to have the library allocate 311 312 @return An error code: 0 - success, otherwise - failure 313 314 @ref User 315 **/ 316 int CeedVectorSetArray(CeedVector vec, CeedMemType mem_type, CeedCopyMode copy_mode, CeedScalar *array) { 317 CeedSize length; 318 319 CeedCheck(vec->SetArray, CeedVectorReturnCeed(vec), CEED_ERROR_UNSUPPORTED, "Backend does not support VectorSetArray"); 320 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 321 "Cannot grant CeedVector array access, the access lock is already in use"); 322 CeedCheck(vec->num_readers == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 323 324 CeedCall(CeedVectorGetLength(vec, &length)); 325 if (length > 0) CeedCall(vec->SetArray(vec, mem_type, copy_mode, array)); 326 vec->state += 2; 327 return CEED_ERROR_SUCCESS; 328 } 329 330 /** 331 @brief Set the `CeedVector` to a constant value 332 333 @param[in,out] vec `CeedVector` 334 @param[in] value Value to be used 335 336 @return An error code: 0 - success, otherwise - failure 337 338 @ref User 339 **/ 340 int CeedVectorSetValue(CeedVector vec, CeedScalar value) { 341 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 342 "Cannot grant CeedVector array access, the access lock is already in use"); 343 CeedCheck(vec->num_readers == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 344 345 if (vec->SetValue) { 346 CeedCall(vec->SetValue(vec, value)); 347 vec->state += 2; 348 } else { 349 CeedSize length; 350 CeedScalar *array; 351 352 CeedCall(CeedVectorGetArrayWrite(vec, CEED_MEM_HOST, &array)); 353 CeedCall(CeedVectorGetLength(vec, &length)); 354 for (CeedSize i = 0; i < length; i++) array[i] = value; 355 CeedCall(CeedVectorRestoreArray(vec, &array)); 356 } 357 return CEED_ERROR_SUCCESS; 358 } 359 360 /** 361 @brief Set a portion of a `CeedVector` to a constant value. 362 363 Note: The `CeedVector` must already have valid data set via @ref CeedVectorSetArray() or similar. 364 365 @param[in,out] vec `CeedVector` 366 @param[in] start First index to set in range `[start, stop)` 367 @param[in] stop One past the last element to set in the range, or `-1` for `length` 368 @param[in] step Stride between indices to set 369 @param[in] value Value to be used 370 371 @return An error code: 0 - success, otherwise - failure 372 373 @ref User 374 **/ 375 int CeedVectorSetValueStrided(CeedVector vec, CeedSize start, CeedSize stop, CeedSize step, CeedScalar value) { 376 CeedSize length; 377 378 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 379 "Cannot grant CeedVector array access, the access lock is already in use"); 380 CeedCheck(vec->num_readers == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 381 CeedCall(CeedVectorGetLength(vec, &length)); 382 CeedCheck(stop >= -1 && stop <= length, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 383 "Invalid value for stop %" CeedSize_FMT ", must be in the range [-1, length]", stop); 384 385 if (vec->SetValueStrided) { 386 CeedCall(vec->SetValueStrided(vec, start, stop, step, value)); 387 vec->state += 2; 388 } else { 389 CeedScalar *array; 390 391 if (length <= 0) return CEED_ERROR_SUCCESS; 392 if (stop == -1) stop = length; 393 CeedCall(CeedVectorGetArray(vec, CEED_MEM_HOST, &array)); 394 for (CeedSize i = start; i < stop; i += step) array[i] = value; 395 CeedCall(CeedVectorRestoreArray(vec, &array)); 396 } 397 return CEED_ERROR_SUCCESS; 398 } 399 400 /** 401 @brief Sync the `CeedVector` to a specified `mem_type`. 402 403 This function is used to force synchronization of arrays set with @ref CeedVectorSetArray(). 404 If the requested `mem_type` is already synchronized, this function results in a no-op. 405 406 @param[in,out] vec `CeedVector` 407 @param[in] mem_type @ref CeedMemType to be synced 408 409 @return An error code: 0 - success, otherwise - failure 410 411 @ref User 412 **/ 413 int CeedVectorSyncArray(CeedVector vec, CeedMemType mem_type) { 414 CeedSize length; 415 416 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot sync CeedVector, the access lock is already in use"); 417 418 // Don't sync empty array 419 CeedCall(CeedVectorGetLength(vec, &length)); 420 if (length == 0) return CEED_ERROR_SUCCESS; 421 422 if (vec->SyncArray) { 423 CeedCall(vec->SyncArray(vec, mem_type)); 424 } else { 425 const CeedScalar *array; 426 427 CeedCall(CeedVectorGetArrayRead(vec, mem_type, &array)); 428 CeedCall(CeedVectorRestoreArrayRead(vec, &array)); 429 } 430 return CEED_ERROR_SUCCESS; 431 } 432 433 /** 434 @brief Take ownership of the `CeedVector` array set by @ref CeedVectorSetArray() with @ref CEED_USE_POINTER and remove the array from the `CeedVector`. 435 436 The caller is responsible for managing and freeing the array. 437 This function will error if @ref CeedVectorSetArray() was not previously called with @ref CEED_USE_POINTER for the corresponding mem_type. 438 439 @param[in,out] vec `CeedVector` 440 @param[in] mem_type Memory type on which to take the array. 441 If the backend uses a different memory type, this will perform a copy. 442 @param[out] array Array on memory type `mem_type`, or `NULL` if array pointer is not required 443 444 @return An error code: 0 - success, otherwise - failure 445 446 @ref User 447 **/ 448 int CeedVectorTakeArray(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 449 CeedSize length; 450 CeedScalar *temp_array = NULL; 451 452 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot take CeedVector array, the access lock is already in use"); 453 CeedCheck(vec->num_readers == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot take CeedVector array, a process has read access"); 454 455 CeedCall(CeedVectorGetLength(vec, &length)); 456 if (length > 0) { 457 bool has_borrowed_array_of_type = true, has_valid_array = true; 458 459 CeedCall(CeedVectorHasBorrowedArrayOfType(vec, mem_type, &has_borrowed_array_of_type)); 460 CeedCheck(has_borrowed_array_of_type, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 461 "CeedVector has no borrowed %s array, must set array with CeedVectorSetArray", CeedMemTypes[mem_type]); 462 463 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 464 CeedCheck(has_valid_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 465 "CeedVector has no valid data to take, must set data with CeedVectorSetValue or CeedVectorSetArray"); 466 467 CeedCall(vec->TakeArray(vec, mem_type, &temp_array)); 468 } 469 if (array) (*array) = temp_array; 470 return CEED_ERROR_SUCCESS; 471 } 472 473 /** 474 @brief Get read/write access to a `CeedVector` via the specified memory type. 475 476 Restore access with @ref CeedVectorRestoreArray(). 477 478 @param[in,out] vec `CeedVector` to access 479 @param[in] mem_type Memory type on which to access the array. 480 If the backend uses a different memory type, this will perform a copy. 481 @param[out] array Array on memory type `mem_type` 482 483 @note The @ref CeedVectorGetArray() and @ref CeedVectorRestoreArray() functions provide access to array pointers in the desired memory space. 484 Pairing get/restore allows the `CeedVector` to track access, thus knowing if norms or other operations may need to be recomputed. 485 486 @return An error code: 0 - success, otherwise - failure 487 488 @ref User 489 **/ 490 int CeedVectorGetArray(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 491 CeedSize length; 492 493 CeedCheck(vec->GetArray, CeedVectorReturnCeed(vec), CEED_ERROR_UNSUPPORTED, "Backend does not support GetArray"); 494 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 495 "Cannot grant CeedVector array access, the access lock is already in use"); 496 CeedCheck(vec->num_readers == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 497 498 CeedCall(CeedVectorGetLength(vec, &length)); 499 if (length > 0) { 500 bool has_valid_array = true; 501 502 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 503 CeedCheck(has_valid_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 504 "CeedVector has no valid data to read, must set data with CeedVectorSetValue or CeedVectorSetArray"); 505 506 CeedCall(vec->GetArray(vec, mem_type, array)); 507 } else { 508 *array = NULL; 509 } 510 vec->state++; 511 return CEED_ERROR_SUCCESS; 512 } 513 514 /** 515 @brief Get read-only access to a `CeedVector` via the specified memory type. 516 517 Restore access with @ref CeedVectorRestoreArrayRead(). 518 519 @param[in] vec `CeedVector` to access 520 @param[in] mem_type Memory type on which to access the array. 521 If the backend uses a different memory type, this will perform a copy (possibly cached). 522 @param[out] array Array on memory type `mem_type` 523 524 @return An error code: 0 - success, otherwise - failure 525 526 @ref User 527 **/ 528 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mem_type, const CeedScalar **array) { 529 CeedSize length; 530 531 CeedCheck(vec->GetArrayRead, CeedVectorReturnCeed(vec), CEED_ERROR_UNSUPPORTED, "Backend does not support GetArrayRead"); 532 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 533 "Cannot grant CeedVector read-only array access, the access lock is already in use"); 534 535 CeedCall(CeedVectorGetLength(vec, &length)); 536 if (length > 0) { 537 bool has_valid_array = true; 538 539 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 540 CeedCheck(has_valid_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 541 "CeedVector has no valid data to read, must set data with CeedVectorSetValue or CeedVectorSetArray"); 542 543 CeedCall(vec->GetArrayRead(vec, mem_type, array)); 544 } else { 545 *array = NULL; 546 } 547 vec->num_readers++; 548 return CEED_ERROR_SUCCESS; 549 } 550 551 /** 552 @brief Get write access to a `CeedVector` via the specified memory type. 553 554 Restore access with @ref CeedVectorRestoreArray(). 555 All old values should be assumed to be invalid. 556 557 @param[in,out] vec `CeedVector` to access 558 @param[in] mem_type Memory type on which to access the array. 559 @param[out] array Array on memory type `mem_type` 560 561 @return An error code: 0 - success, otherwise - failure 562 563 @ref User 564 **/ 565 int CeedVectorGetArrayWrite(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 566 CeedSize length; 567 568 CeedCheck(vec->GetArrayWrite, CeedVectorReturnCeed(vec), CEED_ERROR_UNSUPPORTED, "Backend does not support CeedVectorGetArrayWrite"); 569 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 570 "Cannot grant CeedVector array access, the access lock is already in use"); 571 CeedCheck(vec->num_readers == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 572 573 CeedCall(CeedVectorGetLength(vec, &length)); 574 if (length > 0) { 575 CeedCall(vec->GetArrayWrite(vec, mem_type, array)); 576 } else { 577 *array = NULL; 578 } 579 vec->state++; 580 return CEED_ERROR_SUCCESS; 581 } 582 583 /** 584 @brief Restore an array obtained using @ref CeedVectorGetArray() or @ref CeedVectorGetArrayWrite() 585 586 @param[in,out] vec `CeedVector` to restore 587 @param[in,out] array Array of vector data 588 589 @return An error code: 0 - success, otherwise - failure 590 591 @ref User 592 **/ 593 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) { 594 CeedSize length; 595 596 CeedCheck(vec->state % 2 == 1, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot restore CeedVector array access, access was not granted"); 597 CeedCall(CeedVectorGetLength(vec, &length)); 598 if (length > 0 && vec->RestoreArray) CeedCall(vec->RestoreArray(vec)); 599 *array = NULL; 600 vec->state++; 601 return CEED_ERROR_SUCCESS; 602 } 603 604 /** 605 @brief Restore an array obtained using @ref CeedVectorGetArrayRead() 606 607 @param[in] vec `CeedVector` to restore 608 @param[in,out] array Array of vector data 609 610 @return An error code: 0 - success, otherwise - failure 611 612 @ref User 613 **/ 614 int CeedVectorRestoreArrayRead(CeedVector vec, const CeedScalar **array) { 615 CeedSize length; 616 617 CeedCheck(vec->num_readers > 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 618 "Cannot restore CeedVector array read access, access was not granted"); 619 vec->num_readers--; 620 CeedCall(CeedVectorGetLength(vec, &length)); 621 if (length > 0 && vec->num_readers == 0 && vec->RestoreArrayRead) CeedCall(vec->RestoreArrayRead(vec)); 622 *array = NULL; 623 return CEED_ERROR_SUCCESS; 624 } 625 626 /** 627 @brief Get the norm of a `CeedVector`. 628 629 Note: This operation is local to the `CeedVector`. 630 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. 631 632 @param[in] vec `CeedVector` to retrieve maximum value 633 @param[in] norm_type Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX 634 @param[out] norm Variable to store norm value 635 636 @return An error code: 0 - success, otherwise - failure 637 638 @ref User 639 **/ 640 int CeedVectorNorm(CeedVector vec, CeedNormType norm_type, CeedScalar *norm) { 641 bool has_valid_array = true; 642 CeedSize length; 643 644 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 645 CeedCheck(has_valid_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 646 "CeedVector has no valid data to compute norm, must set data with CeedVectorSetValue or CeedVectorSetArray"); 647 648 CeedCall(CeedVectorGetLength(vec, &length)); 649 if (length == 0) { 650 *norm = 0; 651 return CEED_ERROR_SUCCESS; 652 } 653 654 // Backend impl for GPU, if added 655 if (vec->Norm) { 656 CeedCall(vec->Norm(vec, norm_type, norm)); 657 return CEED_ERROR_SUCCESS; 658 } 659 660 const CeedScalar *array; 661 CeedCall(CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array)); 662 assert(array); 663 664 *norm = 0.; 665 switch (norm_type) { 666 case CEED_NORM_1: 667 for (CeedSize i = 0; i < length; i++) { 668 *norm += fabs(array[i]); 669 } 670 break; 671 case CEED_NORM_2: 672 for (CeedSize i = 0; i < length; i++) { 673 *norm += fabs(array[i]) * fabs(array[i]); 674 } 675 break; 676 case CEED_NORM_MAX: 677 for (CeedSize i = 0; i < length; i++) { 678 const CeedScalar abs_v_i = fabs(array[i]); 679 *norm = *norm > abs_v_i ? *norm : abs_v_i; 680 } 681 } 682 if (norm_type == CEED_NORM_2) *norm = sqrt(*norm); 683 684 CeedCall(CeedVectorRestoreArrayRead(vec, &array)); 685 return CEED_ERROR_SUCCESS; 686 } 687 688 /** 689 @brief Compute `x = alpha x` 690 691 @param[in,out] x `CeedVector` for scaling 692 @param[in] alpha scaling factor 693 694 @return An error code: 0 - success, otherwise - failure 695 696 @ref User 697 **/ 698 int CeedVectorScale(CeedVector x, CeedScalar alpha) { 699 bool has_valid_array = true; 700 CeedSize length; 701 CeedScalar *x_array = NULL; 702 703 CeedCall(CeedVectorHasValidArray(x, &has_valid_array)); 704 CeedCheck(has_valid_array, CeedVectorReturnCeed(x), CEED_ERROR_BACKEND, 705 "CeedVector has no valid data to scale, must set data with CeedVectorSetValue or CeedVectorSetArray"); 706 707 // Return early for empty vector 708 CeedCall(CeedVectorGetLength(x, &length)); 709 if (length == 0) return CEED_ERROR_SUCCESS; 710 711 // Backend implementation 712 if (x->Scale) return x->Scale(x, alpha); 713 714 // Default implementation 715 CeedCall(CeedVectorGetArray(x, CEED_MEM_HOST, &x_array)); 716 assert(x_array); 717 for (CeedSize i = 0; i < length; i++) x_array[i] *= alpha; 718 CeedCall(CeedVectorRestoreArray(x, &x_array)); 719 return CEED_ERROR_SUCCESS; 720 } 721 722 /** 723 @brief Compute `y = alpha x + y` 724 725 @param[in,out] y target `CeedVector` for sum 726 @param[in] alpha scaling factor 727 @param[in] x second `CeedVector`, must be different than ``y` 728 729 @return An error code: 0 - success, otherwise - failure 730 731 @ref User 732 **/ 733 int CeedVectorAXPY(CeedVector y, CeedScalar alpha, CeedVector x) { 734 bool has_valid_array_x = true, has_valid_array_y = true; 735 CeedSize length_x, length_y; 736 CeedScalar *y_array = NULL; 737 CeedScalar const *x_array = NULL; 738 739 CeedCall(CeedVectorGetLength(y, &length_y)); 740 CeedCall(CeedVectorGetLength(x, &length_x)); 741 CeedCheck(length_x == length_y, CeedVectorReturnCeed(y), CEED_ERROR_UNSUPPORTED, 742 "Cannot add vector of different lengths." 743 " x length: %" CeedSize_FMT " y length: %" CeedSize_FMT, 744 length_x, length_y); 745 CeedCheck(x != y, CeedVectorReturnCeed(y), CEED_ERROR_UNSUPPORTED, "Cannot use same vector for x and y in CeedVectorAXPY"); 746 747 CeedCall(CeedVectorHasValidArray(x, &has_valid_array_x)); 748 CeedCheck(has_valid_array_x, CeedVectorReturnCeed(y), CEED_ERROR_BACKEND, 749 "CeedVector x has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 750 CeedCall(CeedVectorHasValidArray(y, &has_valid_array_y)); 751 CeedCheck(has_valid_array_y, CeedVectorReturnCeed(y), CEED_ERROR_BACKEND, 752 "CeedVector y has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 753 754 { 755 Ceed ceed_x, ceed_y, ceed_parent_x, ceed_parent_y; 756 757 CeedCall(CeedVectorGetCeed(y, &ceed_y)); 758 CeedCall(CeedVectorGetCeed(x, &ceed_x)); 759 CeedCall(CeedGetParent(ceed_x, &ceed_parent_x)); 760 CeedCall(CeedGetParent(ceed_y, &ceed_parent_y)); 761 CeedCall(CeedDestroy(&ceed_x)); 762 CeedCall(CeedDestroy(&ceed_y)); 763 CeedCheck(ceed_parent_x == ceed_parent_y, CeedVectorReturnCeed(y), CEED_ERROR_INCOMPATIBLE, 764 "Vectors x and y must be created by the same Ceed context"); 765 CeedCall(CeedDestroy(&ceed_parent_x)); 766 CeedCall(CeedDestroy(&ceed_parent_y)); 767 } 768 769 // Return early for empty vectors 770 if (length_y == 0) return CEED_ERROR_SUCCESS; 771 772 // Backend implementation 773 if (y->AXPY) { 774 CeedCall(y->AXPY(y, alpha, x)); 775 return CEED_ERROR_SUCCESS; 776 } 777 778 // Default implementation 779 CeedCall(CeedVectorGetArray(y, CEED_MEM_HOST, &y_array)); 780 CeedCall(CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array)); 781 782 assert(x_array); 783 assert(y_array); 784 785 for (CeedSize i = 0; i < length_y; i++) y_array[i] += alpha * x_array[i]; 786 787 CeedCall(CeedVectorRestoreArray(y, &y_array)); 788 CeedCall(CeedVectorRestoreArrayRead(x, &x_array)); 789 return CEED_ERROR_SUCCESS; 790 } 791 792 /** 793 @brief Compute `y = alpha x + beta y` 794 795 @param[in,out] y target `CeedVector` for sum 796 @param[in] alpha first scaling factor 797 @param[in] beta second scaling factor 798 @param[in] x second `CeedVector`, must be different than `y` 799 800 @return An error code: 0 - success, otherwise - failure 801 802 @ref User 803 **/ 804 int CeedVectorAXPBY(CeedVector y, CeedScalar alpha, CeedScalar beta, CeedVector x) { 805 bool has_valid_array_x = true, has_valid_array_y = true; 806 CeedSize length_x, length_y; 807 CeedScalar *y_array = NULL; 808 CeedScalar const *x_array = NULL; 809 810 CeedCall(CeedVectorGetLength(y, &length_y)); 811 CeedCall(CeedVectorGetLength(x, &length_x)); 812 CeedCheck(length_x == length_y, CeedVectorReturnCeed(y), CEED_ERROR_UNSUPPORTED, 813 "Cannot add vector of different lengths." 814 " x length: %" CeedSize_FMT " y length: %" CeedSize_FMT, 815 length_x, length_y); 816 CeedCheck(x != y, CeedVectorReturnCeed(y), CEED_ERROR_UNSUPPORTED, "Cannot use same vector for x and y in CeedVectorAXPBY"); 817 818 CeedCall(CeedVectorHasValidArray(x, &has_valid_array_x)); 819 CeedCheck(has_valid_array_x, CeedVectorReturnCeed(y), CEED_ERROR_BACKEND, 820 "CeedVector x has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 821 CeedCall(CeedVectorHasValidArray(y, &has_valid_array_y)); 822 CeedCheck(has_valid_array_y, CeedVectorReturnCeed(y), CEED_ERROR_BACKEND, 823 "CeedVector y has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 824 825 { 826 Ceed ceed_x, ceed_y, ceed_parent_x, ceed_parent_y; 827 828 CeedCall(CeedVectorGetCeed(y, &ceed_y)); 829 CeedCall(CeedVectorGetCeed(x, &ceed_x)); 830 CeedCall(CeedGetParent(ceed_x, &ceed_parent_x)); 831 CeedCall(CeedGetParent(ceed_y, &ceed_parent_y)); 832 CeedCall(CeedDestroy(&ceed_x)); 833 CeedCall(CeedDestroy(&ceed_y)); 834 CeedCheck(ceed_parent_x == ceed_parent_y, CeedVectorReturnCeed(y), CEED_ERROR_INCOMPATIBLE, 835 "Vectors x and y must be created by the same Ceed context"); 836 CeedCall(CeedDestroy(&ceed_parent_x)); 837 CeedCall(CeedDestroy(&ceed_parent_y)); 838 } 839 840 // Return early for empty vectors 841 if (length_y == 0) return CEED_ERROR_SUCCESS; 842 843 // Backend implementation 844 if (y->AXPBY) { 845 CeedCall(y->AXPBY(y, alpha, beta, x)); 846 return CEED_ERROR_SUCCESS; 847 } 848 849 // Default implementation 850 CeedCall(CeedVectorGetArray(y, CEED_MEM_HOST, &y_array)); 851 CeedCall(CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array)); 852 853 assert(x_array); 854 assert(y_array); 855 856 for (CeedSize i = 0; i < length_y; i++) y_array[i] = alpha * x_array[i] + beta * y_array[i]; 857 858 CeedCall(CeedVectorRestoreArray(y, &y_array)); 859 CeedCall(CeedVectorRestoreArrayRead(x, &x_array)); 860 return CEED_ERROR_SUCCESS; 861 } 862 863 /** 864 @brief Compute the pointwise multiplication \f$w = x .* y\f$. 865 866 Any subset of `x`, `y`, and `w` may be the same `CeedVector`. 867 868 @param[out] w target `CeedVector` for the product 869 @param[in] x first `CeedVector` for product 870 @param[in] y second `CeedVector` for the product 871 872 @return An error code: 0 - success, otherwise - failure 873 874 @ref User 875 **/ 876 int CeedVectorPointwiseMult(CeedVector w, CeedVector x, CeedVector y) { 877 bool has_valid_array_x = true, has_valid_array_y = true; 878 CeedScalar *w_array = NULL; 879 CeedScalar const *x_array = NULL, *y_array = NULL; 880 CeedSize length_w, length_x, length_y; 881 882 CeedCall(CeedVectorGetLength(w, &length_w)); 883 CeedCall(CeedVectorGetLength(x, &length_x)); 884 CeedCall(CeedVectorGetLength(y, &length_y)); 885 CeedCheck(length_x >= length_w && length_y >= length_w, CeedVectorReturnCeed(w), CEED_ERROR_UNSUPPORTED, 886 "Cannot pointwise multiply vectors of incompatible lengths." 887 " w length: %" CeedSize_FMT " x length: %" CeedSize_FMT " y length: %" CeedSize_FMT, 888 length_w, length_x, length_y); 889 890 { 891 Ceed ceed_w, ceed_x, ceed_y, ceed_parent_w, ceed_parent_x, ceed_parent_y; 892 893 CeedCall(CeedVectorGetCeed(w, &ceed_w)); 894 CeedCall(CeedVectorGetCeed(x, &ceed_x)); 895 CeedCall(CeedVectorGetCeed(y, &ceed_y)); 896 CeedCall(CeedGetParent(ceed_w, &ceed_parent_w)); 897 CeedCall(CeedGetParent(ceed_x, &ceed_parent_x)); 898 CeedCall(CeedGetParent(ceed_y, &ceed_parent_y)); 899 CeedCall(CeedDestroy(&ceed_w)); 900 CeedCall(CeedDestroy(&ceed_x)); 901 CeedCall(CeedDestroy(&ceed_y)); 902 CeedCheck(ceed_parent_w == ceed_parent_x && ceed_parent_w == ceed_parent_y, CeedVectorReturnCeed(w), CEED_ERROR_INCOMPATIBLE, 903 "Vectors w, x, and y must be created by the same Ceed context"); 904 CeedCall(CeedDestroy(&ceed_parent_w)); 905 CeedCall(CeedDestroy(&ceed_parent_x)); 906 CeedCall(CeedDestroy(&ceed_parent_y)); 907 } 908 909 CeedCall(CeedVectorHasValidArray(x, &has_valid_array_x)); 910 CeedCheck(has_valid_array_x, CeedVectorReturnCeed(w), CEED_ERROR_BACKEND, 911 "CeedVector x has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 912 CeedCall(CeedVectorHasValidArray(y, &has_valid_array_y)); 913 CeedCheck(has_valid_array_y, CeedVectorReturnCeed(w), CEED_ERROR_BACKEND, 914 "CeedVector y has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 915 916 // Return early for empty vectors 917 if (length_w == 0) return CEED_ERROR_SUCCESS; 918 919 // Backend implementation 920 if (w->PointwiseMult) { 921 CeedCall(w->PointwiseMult(w, x, y)); 922 return CEED_ERROR_SUCCESS; 923 } 924 925 // Default implementation 926 if (x == w || y == w) { 927 CeedCall(CeedVectorGetArray(w, CEED_MEM_HOST, &w_array)); 928 } else { 929 CeedCall(CeedVectorGetArrayWrite(w, CEED_MEM_HOST, &w_array)); 930 } 931 if (x != w) { 932 CeedCall(CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array)); 933 } else { 934 x_array = w_array; 935 } 936 if (y != w && y != x) { 937 CeedCall(CeedVectorGetArrayRead(y, CEED_MEM_HOST, &y_array)); 938 } else if (y == x) { 939 y_array = x_array; 940 } else if (y == w) { 941 y_array = w_array; 942 } 943 944 assert(w_array); 945 assert(x_array); 946 assert(y_array); 947 948 for (CeedSize i = 0; i < length_w; i++) w_array[i] = x_array[i] * y_array[i]; 949 950 if (y != w && y != x) CeedCall(CeedVectorRestoreArrayRead(y, &y_array)); 951 if (x != w) CeedCall(CeedVectorRestoreArrayRead(x, &x_array)); 952 CeedCall(CeedVectorRestoreArray(w, &w_array)); 953 return CEED_ERROR_SUCCESS; 954 } 955 956 /** 957 @brief Take the reciprocal of a `CeedVector`. 958 959 @param[in,out] vec `CeedVector` to take reciprocal 960 961 @return An error code: 0 - success, otherwise - failure 962 963 @ref User 964 **/ 965 int CeedVectorReciprocal(CeedVector vec) { 966 bool has_valid_array = true; 967 CeedSize length; 968 CeedScalar *array; 969 970 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 971 CeedCheck(has_valid_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 972 "CeedVector has no valid data to compute reciprocal, must set data with CeedVectorSetValue or CeedVectorSetArray"); 973 974 // Check if vector data set 975 CeedCheck(vec->state > 0, CeedVectorReturnCeed(vec), CEED_ERROR_INCOMPLETE, "CeedVector must have data set to take reciprocal"); 976 977 // Return early for empty vector 978 CeedCall(CeedVectorGetLength(vec, &length)); 979 if (length == 0) return CEED_ERROR_SUCCESS; 980 981 // Backend impl for GPU, if added 982 if (vec->Reciprocal) { 983 CeedCall(vec->Reciprocal(vec)); 984 return CEED_ERROR_SUCCESS; 985 } 986 987 CeedCall(CeedVectorGetArray(vec, CEED_MEM_HOST, &array)); 988 for (CeedSize i = 0; i < length; i++) { 989 if (fabs(array[i]) > CEED_EPSILON) array[i] = 1. / array[i]; 990 } 991 992 CeedCall(CeedVectorRestoreArray(vec, &array)); 993 return CEED_ERROR_SUCCESS; 994 } 995 996 /** 997 @brief View a `CeedVector` 998 999 Note: It is safe to use any unsigned values for `start` or `stop` and any nonzero integer for `step`. 1000 Any portion of the provided range that is outside the range of valid indices for the `CeedVector` will be ignored. 1001 1002 @param[in] vec `CeedVector` to view 1003 @param[in] start Index of first `CeedVector` entry to view in the range `[start, stop)` 1004 @param[in] stop One past the last element to view in the range, or `-1` for `length` 1005 @param[in] step Step between `CeedVector` entries to view 1006 @param[in] fp_fmt Printing format 1007 @param[in] stream Filestream to write to 1008 1009 @return An error code: 0 - success, otherwise - failure 1010 1011 @ref User 1012 **/ 1013 int CeedVectorViewRange(CeedVector vec, CeedSize start, CeedSize stop, CeedInt step, const char *fp_fmt, FILE *stream) { 1014 char fmt[1024]; 1015 CeedSize length; 1016 const CeedScalar *x; 1017 1018 CeedCheck(step != 0, CeedVectorReturnCeed(vec), CEED_ERROR_MINOR, "View range 'step' must be nonzero"); 1019 1020 CeedCall(CeedVectorGetLength(vec, &length)); 1021 fprintf(stream, "CeedVector length %" CeedSize_FMT "\n", length); 1022 if (start != 0 || stop != length || step != 1) { 1023 fprintf(stream, " start: %" CeedSize_FMT "\n stop: %" CeedSize_FMT "\n step: %" CeedInt_FMT "\n", start, stop, step); 1024 } 1025 if (start > length) start = length; 1026 if (stop == -1 || stop > length) stop = length; 1027 1028 snprintf(fmt, sizeof fmt, " %s\n", fp_fmt ? fp_fmt : "%g"); 1029 CeedCall(CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x)); 1030 for (CeedSize i = start; step > 0 ? (i < stop) : (i > stop); i += step) fprintf(stream, fmt, x[i]); 1031 CeedCall(CeedVectorRestoreArrayRead(vec, &x)); 1032 if (stop != length) fprintf(stream, " ...\n"); 1033 return CEED_ERROR_SUCCESS; 1034 } 1035 1036 /** 1037 @brief View a `CeedVector` 1038 1039 @param[in] vec `CeedVector` to view 1040 @param[in] fp_fmt Printing format 1041 @param[in] stream Filestream to write to 1042 1043 @return An error code: 0 - success, otherwise - failure 1044 1045 @ref User 1046 **/ 1047 int CeedVectorView(CeedVector vec, const char *fp_fmt, FILE *stream) { 1048 CeedSize length; 1049 1050 CeedCall(CeedVectorGetLength(vec, &length)); 1051 CeedCall(CeedVectorViewRange(vec, 0, length, 1, fp_fmt, stream)); 1052 return CEED_ERROR_SUCCESS; 1053 } 1054 1055 /** 1056 @brief Get the `Ceed` associated with a `CeedVector` 1057 1058 @param[in] vec `CeedVector` to retrieve state 1059 @param[out] ceed Variable to store `Ceed` 1060 1061 @return An error code: 0 - success, otherwise - failure 1062 1063 @ref Advanced 1064 **/ 1065 int CeedVectorGetCeed(CeedVector vec, Ceed *ceed) { 1066 *ceed = NULL; 1067 CeedCall(CeedReferenceCopy(CeedVectorReturnCeed(vec), ceed)); 1068 return CEED_ERROR_SUCCESS; 1069 } 1070 1071 /** 1072 @brief Return the `Ceed` associated with a `CeedVector` 1073 1074 @param[in] vec `CeedVector` to retrieve state 1075 1076 @return `Ceed` associated with the `vec` 1077 1078 @ref Advanced 1079 **/ 1080 Ceed CeedVectorReturnCeed(CeedVector vec) { return vec->ceed; } 1081 1082 /** 1083 @brief Get the length of a `CeedVector` 1084 1085 @param[in] vec `CeedVector` to retrieve length 1086 @param[out] length Variable to store length 1087 1088 @return An error code: 0 - success, otherwise - failure 1089 1090 @ref User 1091 **/ 1092 int CeedVectorGetLength(CeedVector vec, CeedSize *length) { 1093 *length = vec->length; 1094 return CEED_ERROR_SUCCESS; 1095 } 1096 1097 /** 1098 @brief Destroy a `CeedVector` 1099 1100 @param[in,out] vec `CeedVector` to destroy 1101 1102 @return An error code: 0 - success, otherwise - failure 1103 1104 @ref User 1105 **/ 1106 int CeedVectorDestroy(CeedVector *vec) { 1107 if (!*vec || *vec == CEED_VECTOR_ACTIVE || *vec == CEED_VECTOR_NONE || --(*vec)->ref_count > 0) { 1108 *vec = NULL; 1109 return CEED_ERROR_SUCCESS; 1110 } 1111 CeedCheck((*vec)->state % 2 == 0, (*vec)->ceed, CEED_ERROR_ACCESS, "Cannot destroy CeedVector, the writable access lock is in use"); 1112 CeedCheck((*vec)->num_readers == 0, (*vec)->ceed, CEED_ERROR_ACCESS, "Cannot destroy CeedVector, a process has read access"); 1113 1114 if ((*vec)->Destroy) CeedCall((*vec)->Destroy(*vec)); 1115 1116 CeedCall(CeedDestroy(&(*vec)->ceed)); 1117 CeedCall(CeedFree(vec)); 1118 return CEED_ERROR_SUCCESS; 1119 } 1120 1121 /// @} 1122