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