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