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