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