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_WEIGHTS). 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 Get the Ceed associated with a CeedVector 52 53 @param vec CeedVector to retrieve state 54 @param[out] ceed Variable to store ceed 55 56 @return An error code: 0 - success, otherwise - failure 57 58 @ref Backend 59 **/ 60 int CeedVectorGetCeed(CeedVector vec, Ceed *ceed) { 61 *ceed = vec->ceed; 62 return CEED_ERROR_SUCCESS; 63 } 64 65 /** 66 @brief Get the state of a CeedVector 67 68 @param vec CeedVector to retrieve state 69 @param[out] state Variable to store state 70 71 @return An error code: 0 - success, otherwise - failure 72 73 @ref Backend 74 **/ 75 int CeedVectorGetState(CeedVector vec, uint64_t *state) { 76 *state = vec->state; 77 return CEED_ERROR_SUCCESS; 78 } 79 80 /** 81 @brief Add a reference to a CeedVector 82 83 @param[out] vec CeedVector to increment reference counter 84 85 @return An error code: 0 - success, otherwise - failure 86 87 @ref Backend 88 **/ 89 int CeedVectorAddReference(CeedVector vec) { 90 vec->ref_count++; 91 return CEED_ERROR_SUCCESS; 92 } 93 94 /** 95 @brief Get the backend data of a CeedVector 96 97 @param vec CeedVector to retrieve state 98 @param[out] data Variable to store data 99 100 @return An error code: 0 - success, otherwise - failure 101 102 @ref Backend 103 **/ 104 int CeedVectorGetData(CeedVector vec, void *data) { 105 *(void **)data = vec->data; 106 return CEED_ERROR_SUCCESS; 107 } 108 109 /** 110 @brief Set the backend data of a CeedVector 111 112 @param[out] vec CeedVector to retrieve state 113 @param data Data to set 114 115 @return An error code: 0 - success, otherwise - failure 116 117 @ref Backend 118 **/ 119 int CeedVectorSetData(CeedVector vec, void *data) { 120 vec->data = data; 121 return CEED_ERROR_SUCCESS; 122 } 123 124 /** 125 @brief Increment the reference counter for a CeedVector 126 127 @param vec CeedVector to increment the reference counter 128 129 @return An error code: 0 - success, otherwise - failure 130 131 @ref Backend 132 **/ 133 int CeedVectorIncrementRefCounter(CeedVector vec) { 134 vec->ref_count++; 135 return CEED_ERROR_SUCCESS; 136 } 137 138 /// @} 139 140 /// ---------------------------------------------------------------------------- 141 /// CeedVector Public API 142 /// ---------------------------------------------------------------------------- 143 /// @addtogroup CeedVectorUser 144 /// @{ 145 146 /** 147 @brief Create a CeedVector of the specified length (does not allocate memory) 148 149 @param ceed Ceed object where the CeedVector will be created 150 @param length Length of vector 151 @param[out] vec Address of the variable where the newly created 152 CeedVector will be stored 153 154 @return An error code: 0 - success, otherwise - failure 155 156 @ref User 157 **/ 158 int CeedVectorCreate(Ceed ceed, CeedInt length, CeedVector *vec) { 159 int ierr; 160 161 if (!ceed->VectorCreate) { 162 Ceed delegate; 163 ierr = CeedGetObjectDelegate(ceed, &delegate, "Vector"); CeedChk(ierr); 164 165 if (!delegate) 166 // LCOV_EXCL_START 167 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 168 "Backend does not support VectorCreate"); 169 // LCOV_EXCL_STOP 170 171 ierr = CeedVectorCreate(delegate, length, vec); CeedChk(ierr); 172 return CEED_ERROR_SUCCESS; 173 } 174 175 ierr = CeedCalloc(1, vec); CeedChk(ierr); 176 (*vec)->ceed = ceed; 177 ierr = CeedIncrementRefCounter(ceed); CeedChk(ierr); 178 (*vec)->ref_count = 1; 179 (*vec)->length = length; 180 (*vec)->state = 0; 181 ierr = ceed->VectorCreate(length, *vec); CeedChk(ierr); 182 return CEED_ERROR_SUCCESS; 183 } 184 185 /** 186 @brief Set the array used by a CeedVector, freeing any previously allocated 187 array if applicable. The backend may copy values to a different 188 memtype, such as during @ref CeedOperatorApply(). 189 See also @ref CeedVectorSyncArray() and @ref CeedVectorTakeArray(). 190 191 @param vec CeedVector 192 @param mem_type Memory type of the array being passed 193 @param copy_mode Copy mode for the array 194 @param array Array to be used, or NULL with @ref CEED_COPY_VALUES to have the 195 library allocate 196 197 @return An error code: 0 - success, otherwise - failure 198 199 @ref User 200 **/ 201 int CeedVectorSetArray(CeedVector vec, CeedMemType mem_type, 202 CeedCopyMode copy_mode, 203 CeedScalar *array) { 204 int ierr; 205 206 if (!vec->SetArray) 207 // LCOV_EXCL_START 208 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 209 "Backend does not support VectorSetArray"); 210 // LCOV_EXCL_STOP 211 212 if (vec->state % 2 == 1) 213 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 214 "Cannot grant CeedVector array access, the " 215 "access lock is already in use"); 216 217 if (vec->num_readers > 0) 218 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 219 "Cannot grant CeedVector array access, a " 220 "process has read access"); 221 222 ierr = vec->SetArray(vec, mem_type, copy_mode, array); CeedChk(ierr); 223 vec->state += 2; 224 return CEED_ERROR_SUCCESS; 225 } 226 227 /** 228 @brief Set the CeedVector to a constant value 229 230 @param vec CeedVector 231 @param[in] value Value to be used 232 233 @return An error code: 0 - success, otherwise - failure 234 235 @ref User 236 **/ 237 int CeedVectorSetValue(CeedVector vec, CeedScalar value) { 238 int ierr; 239 240 if (vec->state % 2 == 1) 241 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 242 "Cannot grant CeedVector array access, the " 243 "access lock is already in use"); 244 245 if (vec->SetValue) { 246 ierr = vec->SetValue(vec, value); CeedChk(ierr); 247 } else { 248 CeedScalar *array; 249 ierr = CeedVectorGetArray(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 250 for (int i=0; i<vec->length; i++) array[i] = value; 251 ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr); 252 } 253 vec->state += 2; 254 return CEED_ERROR_SUCCESS; 255 } 256 257 /** 258 @brief Sync the CeedVector to a specified memtype. This function is used to 259 force synchronization of arrays set with @ref CeedVectorSetArray(). 260 If the requested memtype is already synchronized, this function 261 results in a no-op. 262 263 @param vec CeedVector 264 @param mem_type Memtype to be synced 265 266 @return An error code: 0 - success, otherwise - failure 267 268 @ref User 269 **/ 270 int CeedVectorSyncArray(CeedVector vec, CeedMemType mem_type) { 271 int ierr; 272 273 if (vec->state % 2 == 1) 274 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 275 "Cannot sync CeedVector, the access lock is " 276 "already in use"); 277 278 if (vec->SyncArray) { 279 ierr = vec->SyncArray(vec, mem_type); CeedChk(ierr); 280 } else { 281 const CeedScalar *array; 282 ierr = CeedVectorGetArrayRead(vec, mem_type, &array); CeedChk(ierr); 283 ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr); 284 } 285 return CEED_ERROR_SUCCESS; 286 } 287 288 /** 289 @brief Take ownership of the CeedVector array and remove the array from the 290 CeedVector. The caller is responsible for managing and freeing 291 the array. 292 293 @param vec CeedVector 294 @param mem_type Memory type on which to take the array. If the backend 295 uses a different memory type, this will perform a copy. 296 @param[out] array Array on memory type mem_type, or NULL if array pointer is 297 not required 298 299 @return An error code: 0 - success, otherwise - failure 300 301 @ref User 302 **/ 303 int CeedVectorTakeArray(CeedVector vec, CeedMemType mem_type, 304 CeedScalar **array) { 305 int ierr; 306 307 if (vec->state % 2 == 1) 308 // LCOV_EXCL_START 309 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 310 "Cannot take CeedVector array, the access " 311 "lock is already in use"); 312 // LCOV_EXCL_STOP 313 if (vec->num_readers > 0) 314 // LCOV_EXCL_START 315 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 316 "Cannot take CeedVector array, a process " 317 "has read access"); 318 // LCOV_EXCL_STOP 319 320 CeedScalar *temp_array = NULL; 321 ierr = vec->TakeArray(vec, mem_type, &temp_array); CeedChk(ierr); 322 if (array) (*array) = temp_array; 323 return CEED_ERROR_SUCCESS; 324 } 325 326 /** 327 @brief Get read/write access to a CeedVector via the specified memory type. 328 Restore access with @ref CeedVectorRestoreArray(). 329 330 @param vec CeedVector to access 331 @param mem_type Memory type on which to access the array. If the backend 332 uses a different memory type, this will perform a copy. 333 @param[out] array Array on memory type mem_type 334 335 @note The CeedVectorGetArray* and CeedVectorRestoreArray* functions provide 336 access to array pointers in the desired memory space. Pairing get/restore 337 allows the Vector to track access, thus knowing if norms or other 338 operations may need to be recomputed. 339 340 @return An error code: 0 - success, otherwise - failure 341 342 @ref User 343 **/ 344 int CeedVectorGetArray(CeedVector vec, CeedMemType mem_type, 345 CeedScalar **array) { 346 int ierr; 347 348 if (!vec->GetArray) 349 // LCOV_EXCL_START 350 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 351 "Backend does not support GetArray"); 352 // LCOV_EXCL_STOP 353 354 if (vec->state % 2 == 1) 355 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 356 "Cannot grant CeedVector array access, the " 357 "access lock is already in use"); 358 359 if (vec->num_readers > 0) 360 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 361 "Cannot grant CeedVector array access, a " 362 "process has read access"); 363 364 ierr = vec->GetArray(vec, mem_type, array); CeedChk(ierr); 365 vec->state += 1; 366 return CEED_ERROR_SUCCESS; 367 } 368 369 /** 370 @brief Get read-only access to a CeedVector via the specified memory type. 371 Restore access with @ref CeedVectorRestoreArrayRead(). 372 373 @param vec CeedVector to access 374 @param mem_type Memory type on which to access the array. If the backend 375 uses a different memory type, this will perform a copy 376 (possibly cached). 377 @param[out] array Array on memory type mem_type 378 379 @return An error code: 0 - success, otherwise - failure 380 381 @ref User 382 **/ 383 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mem_type, 384 const CeedScalar **array) { 385 int ierr; 386 387 if (!vec->GetArrayRead) 388 // LCOV_EXCL_START 389 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 390 "Backend does not support GetArrayRead"); 391 // LCOV_EXCL_STOP 392 393 if (vec->state % 2 == 1) 394 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 395 "Cannot grant CeedVector read-only array " 396 "access, the access lock is already in use"); 397 398 ierr = vec->GetArrayRead(vec, mem_type, array); CeedChk(ierr); 399 vec->num_readers++; 400 return CEED_ERROR_SUCCESS; 401 } 402 403 /** 404 @brief Restore an array obtained using @ref CeedVectorGetArray() 405 406 @param vec CeedVector to restore 407 @param array Array of vector data 408 409 @return An error code: 0 - success, otherwise - failure 410 411 @ref User 412 **/ 413 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) { 414 int ierr; 415 416 if (!vec->RestoreArray) 417 // LCOV_EXCL_START 418 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 419 "Backend does not support RestoreArray"); 420 // LCOV_EXCL_STOP 421 422 if (vec->state % 2 != 1) 423 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 424 "Cannot restore CeedVector array access, " 425 "access was not granted"); 426 427 ierr = vec->RestoreArray(vec); CeedChk(ierr); 428 *array = NULL; 429 vec->state += 1; 430 return CEED_ERROR_SUCCESS; 431 } 432 433 /** 434 @brief Restore an array obtained using @ref CeedVectorGetArrayRead() 435 436 @param vec CeedVector to restore 437 @param array Array of vector data 438 439 @return An error code: 0 - success, otherwise - failure 440 441 @ref User 442 **/ 443 int CeedVectorRestoreArrayRead(CeedVector vec, const CeedScalar **array) { 444 int ierr; 445 446 if (!vec->RestoreArrayRead) 447 // LCOV_EXCL_START 448 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 449 "Backend does not support RestoreArrayRead"); 450 // LCOV_EXCL_STOP 451 452 ierr = vec->RestoreArrayRead(vec); CeedChk(ierr); 453 *array = NULL; 454 vec->num_readers--; 455 return CEED_ERROR_SUCCESS; 456 } 457 458 /** 459 @brief Get the norm of a CeedVector. 460 461 Note: This operation is local to the CeedVector. This function will likely 462 not provide the desired results for the norm of the libCEED portion 463 of a parallel vector or a CeedVector with duplicated or hanging nodes. 464 465 @param vec CeedVector to retrieve maximum value 466 @param norm_type Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX 467 @param[out] norm Variable to store norm value 468 469 @return An error code: 0 - success, otherwise - failure 470 471 @ref User 472 **/ 473 int CeedVectorNorm(CeedVector vec, CeedNormType norm_type, CeedScalar *norm) { 474 int ierr; 475 476 // Backend impl for GPU, if added 477 if (vec->Norm) { 478 ierr = vec->Norm(vec, norm_type, norm); CeedChk(ierr); 479 return CEED_ERROR_SUCCESS; 480 } 481 482 const CeedScalar *array; 483 ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 484 485 *norm = 0.; 486 switch (norm_type) { 487 case CEED_NORM_1: 488 for (int i=0; i<vec->length; i++) { 489 *norm += fabs(array[i]); 490 } 491 break; 492 case CEED_NORM_2: 493 for (int i=0; i<vec->length; i++) { 494 *norm += fabs(array[i])*fabs(array[i]); 495 } 496 break; 497 case CEED_NORM_MAX: 498 for (int i=0; i<vec->length; i++) { 499 const CeedScalar abs_v_i = fabs(array[i]); 500 *norm = *norm > abs_v_i ? *norm : abs_v_i; 501 } 502 } 503 if (norm_type == CEED_NORM_2) 504 *norm = sqrt(*norm); 505 506 ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr); 507 return CEED_ERROR_SUCCESS; 508 } 509 510 /** 511 @brief Take the reciprocal of a CeedVector. 512 513 @param vec CeedVector to take reciprocal 514 515 @return An error code: 0 - success, otherwise - failure 516 517 @ref User 518 **/ 519 int CeedVectorReciprocal(CeedVector vec) { 520 int ierr; 521 522 // Check if vector data set 523 if (!vec->state) 524 // LCOV_EXCL_START 525 return CeedError(vec->ceed, CEED_ERROR_INCOMPLETE, 526 "CeedVector must have data set to take reciprocal"); 527 // LCOV_EXCL_STOP 528 529 // Backend impl for GPU, if added 530 if (vec->Reciprocal) { 531 ierr = vec->Reciprocal(vec); CeedChk(ierr); 532 return CEED_ERROR_SUCCESS; 533 } 534 535 CeedInt len; 536 ierr = CeedVectorGetLength(vec, &len); CeedChk(ierr); 537 CeedScalar *array; 538 ierr = CeedVectorGetArray(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 539 for (CeedInt i=0; i<len; i++) 540 if (fabs(array[i]) > CEED_EPSILON) 541 array[i] = 1./array[i]; 542 543 ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr); 544 return CEED_ERROR_SUCCESS; 545 } 546 547 /** 548 @brief View a CeedVector 549 550 @param[in] vec CeedVector to view 551 @param[in] fp_fmt Printing format 552 @param[in] stream Filestream to write to 553 554 @return An error code: 0 - success, otherwise - failure 555 556 @ref User 557 **/ 558 int CeedVectorView(CeedVector vec, const char *fp_fmt, FILE *stream) { 559 const CeedScalar *x; 560 561 int ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x); CeedChk(ierr); 562 563 char fmt[1024]; 564 fprintf(stream, "CeedVector length %ld\n", (long)vec->length); 565 snprintf(fmt, sizeof fmt, " %s\n", fp_fmt ? fp_fmt : "%g"); 566 for (CeedInt i=0; i<vec->length; i++) 567 fprintf(stream, fmt, x[i]); 568 569 ierr = CeedVectorRestoreArrayRead(vec, &x); CeedChk(ierr); 570 return CEED_ERROR_SUCCESS; 571 } 572 573 /** 574 @brief Get the length of a CeedVector 575 576 @param vec CeedVector to retrieve length 577 @param[out] length Variable to store length 578 579 @return An error code: 0 - success, otherwise - failure 580 581 @ref User 582 **/ 583 int CeedVectorGetLength(CeedVector vec, CeedInt *length) { 584 *length = vec->length; 585 return CEED_ERROR_SUCCESS; 586 } 587 588 /** 589 @brief Destroy a CeedVector 590 591 @param vec CeedVector to destroy 592 593 @return An error code: 0 - success, otherwise - failure 594 595 @ref User 596 **/ 597 int CeedVectorDestroy(CeedVector *vec) { 598 int ierr; 599 600 if (!*vec || --(*vec)->ref_count > 0) return CEED_ERROR_SUCCESS; 601 602 if (((*vec)->state % 2) == 1) 603 return CeedError((*vec)->ceed, CEED_ERROR_ACCESS, 604 "Cannot destroy CeedVector, the writable access " 605 "lock is in use"); 606 607 if ((*vec)->num_readers > 0) 608 return CeedError((*vec)->ceed, CEED_ERROR_ACCESS, 609 "Cannot destroy CeedVector, a process has " 610 "read access"); 611 612 if ((*vec)->Destroy) { 613 ierr = (*vec)->Destroy(*vec); CeedChk(ierr); 614 } 615 616 ierr = CeedDestroy(&(*vec)->ceed); CeedChk(ierr); 617 ierr = CeedFree(vec); CeedChk(ierr); 618 return CEED_ERROR_SUCCESS; 619 } 620 621 /// @} 622