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