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