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