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-impl.h> 18 #include <ceed-backend.h> 19 #include <math.h> 20 21 /// @file 22 /// Implementation of public CeedVector interfaces 23 24 /// @cond DOXYGEN_SKIP 25 static struct CeedVector_private ceed_vector_active; 26 static struct CeedVector_private ceed_vector_none; 27 /// @endcond 28 29 /// @addtogroup CeedVectorUser 30 /// @{ 31 32 /// Indicate that vector will be provided as an explicit argument to 33 /// CeedOperatorApply(). 34 const CeedVector CEED_VECTOR_ACTIVE = &ceed_vector_active; 35 36 /// Indicate that no vector is applicable (i.e., for @ref CEED_EVAL_WEIGHTS). 37 const CeedVector CEED_VECTOR_NONE = &ceed_vector_none; 38 39 /// @} 40 41 /// ---------------------------------------------------------------------------- 42 /// CeedVector Backend API 43 /// ---------------------------------------------------------------------------- 44 /// @addtogroup CeedVectorBackend 45 /// @{ 46 47 /** 48 @brief Get the Ceed associated with a CeedVector 49 50 @param vec CeedVector to retrieve state 51 @param[out] ceed Variable to store ceed 52 53 @return An error code: 0 - success, otherwise - failure 54 55 @ref Backend 56 **/ 57 int CeedVectorGetCeed(CeedVector vec, Ceed *ceed) { 58 *ceed = vec->ceed; 59 return 0; 60 } 61 62 /** 63 @brief Get the state of a CeedVector 64 65 @param vec CeedVector to retrieve state 66 @param[out] state Variable to store state 67 68 @return An error code: 0 - success, otherwise - failure 69 70 @ref Backend 71 **/ 72 int CeedVectorGetState(CeedVector vec, uint64_t *state) { 73 *state = vec->state; 74 return 0; 75 } 76 77 /** 78 @brief Add a refrence to a CeedVector 79 80 @param[out] vec CeedVector to increment reference counter 81 82 @return An error code: 0 - success, otherwise - failure 83 84 @ref Backend 85 **/ 86 int CeedVectorAddReference(CeedVector vec) { 87 vec->refcount++; 88 return 0; 89 } 90 91 /** 92 @brief Get the backend data of a CeedVector 93 94 @param vec CeedVector to retrieve state 95 @param[out] data Variable to store data 96 97 @return An error code: 0 - success, otherwise - failure 98 99 @ref Backend 100 **/ 101 int CeedVectorGetData(CeedVector vec, void **data) { 102 *data = vec->data; 103 return 0; 104 } 105 106 /** 107 @brief Set the backend data of a CeedVector 108 109 @param[out] vec CeedVector to retrieve state 110 @param data Data to set 111 112 @return An error code: 0 - success, otherwise - failure 113 114 @ref Backend 115 **/ 116 int CeedVectorSetData(CeedVector vec, void **data) { 117 vec->data = *data; 118 return 0; 119 } 120 121 /// @} 122 123 /// ---------------------------------------------------------------------------- 124 /// CeedVector Public API 125 /// ---------------------------------------------------------------------------- 126 /// @addtogroup CeedVectorUser 127 /// @{ 128 129 /** 130 @brief Create a CeedVector of the specified length (does not allocate memory) 131 132 @param ceed Ceed object where the CeedVector will be created 133 @param length Length of vector 134 @param[out] vec Address of the variable where the newly created 135 CeedVector will be stored 136 137 @return An error code: 0 - success, otherwise - failure 138 139 @ref User 140 **/ 141 int CeedVectorCreate(Ceed ceed, CeedInt length, CeedVector *vec) { 142 int ierr; 143 144 if (!ceed->VectorCreate) { 145 Ceed delegate; 146 ierr = CeedGetObjectDelegate(ceed, &delegate, "Vector"); CeedChk(ierr); 147 148 if (!delegate) 149 // LCOV_EXCL_START 150 return CeedError(ceed, 1, "Backend does not support VectorCreate"); 151 // LCOV_EXCL_STOP 152 153 ierr = CeedVectorCreate(delegate, length, vec); CeedChk(ierr); 154 return 0; 155 } 156 157 ierr = CeedCalloc(1,vec); CeedChk(ierr); 158 (*vec)->ceed = ceed; 159 ceed->refcount++; 160 (*vec)->refcount = 1; 161 (*vec)->length = length; 162 (*vec)->state = 0; 163 ierr = ceed->VectorCreate(length, *vec); CeedChk(ierr); 164 return 0; 165 } 166 167 /** 168 @brief Set the array used by a CeedVector, freeing any previously allocated 169 array if applicable. The backend may copy values to a different 170 memtype, such as during @ref CeedOperatorApply(). 171 Use @CeedVectorSyncArray() to force synchronization for externally 172 allocated arrays, such as arrays set with @ref CEED_USE_POINTER. 173 174 @param vec CeedVector 175 @param mtype Memory type of the array being passed 176 @param cmode Copy mode for the array 177 @param array Array to be used, or NULL with @ref CEED_COPY_VALUES to have the 178 library allocate 179 180 @return An error code: 0 - success, otherwise - failure 181 182 @ref User 183 **/ 184 int CeedVectorSetArray(CeedVector vec, CeedMemType mtype, CeedCopyMode cmode, 185 CeedScalar *array) { 186 int ierr; 187 188 if (!vec->SetArray) 189 // LCOV_EXCL_START 190 return CeedError(vec->ceed, 1, "Backend does not support VectorSetArray"); 191 // LCOV_EXCL_STOP 192 193 if (vec->state % 2 == 1) 194 return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, the " 195 "access lock is already in use"); 196 197 if (vec->numreaders > 0) 198 return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, a " 199 "process has read access"); 200 201 ierr = vec->SetArray(vec, mtype, cmode, array); CeedChk(ierr); 202 vec->state += 2; 203 204 return 0; 205 } 206 207 /** 208 @brief Set the CeedVector to a constant value 209 210 @param vec CeedVector 211 @param[in] value Value to be used 212 213 @return An error code: 0 - success, otherwise - failure 214 215 @ref User 216 **/ 217 int CeedVectorSetValue(CeedVector vec, CeedScalar value) { 218 int ierr; 219 220 if (vec->state % 2 == 1) 221 return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, the " 222 "access lock is already in use"); 223 224 if (vec->SetValue) { 225 ierr = vec->SetValue(vec, value); CeedChk(ierr); 226 } else { 227 CeedScalar *array; 228 ierr = CeedVectorGetArray(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 229 for (int i=0; i<vec->length; i++) array[i] = value; 230 ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr); 231 } 232 233 vec->state += 2; 234 235 return 0; 236 } 237 238 /** 239 @brief Sync the CeedVector to a specified memtype. This function is used to 240 force synchronization of arrays set with @ref CeedVectorSetArray(). 241 If the requested memtype is already synchronized, this function 242 results in a no-op. 243 244 @param vec CeedVector 245 @param mtype Memtype to be synced 246 247 @return An error code: 0 - success, otherwise - failure 248 249 @ref User 250 **/ 251 int CeedVectorSyncArray(CeedVector vec, CeedMemType mtype) { 252 int ierr; 253 254 if (vec->state % 2 == 1) 255 return CeedError(vec->ceed, 1, "Cannot sync CeedVector, the access lock is " 256 "already in use"); 257 258 if (vec->SyncArray) { 259 ierr = vec->SyncArray(vec, mtype); CeedChk(ierr); 260 } else { 261 const CeedScalar *array; 262 ierr = CeedVectorGetArrayRead(vec, mtype, &array); CeedChk(ierr); 263 ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr); 264 } 265 266 return 0; 267 } 268 269 /** 270 @brief Get read/write access to a CeedVector via the specified memory type. 271 Restore access with @ref CeedVectorRestoreArray(). 272 273 @param vec CeedVector to access 274 @param mtype Memory type on which to access the array. If the backend 275 uses a different memory type, this will perform a copy. 276 @param[out] array Array on memory type mtype 277 278 @note The CeedVectorGetArray* and CeedVectorRestoreArray* functions provide 279 access to array pointers in the desired memory space. Pairing get/restore 280 allows the Vector to track access, thus knowing if norms or other 281 operations may need to be recomputed. 282 283 @return An error code: 0 - success, otherwise - failure 284 285 @ref User 286 **/ 287 int CeedVectorGetArray(CeedVector vec, CeedMemType mtype, CeedScalar **array) { 288 int ierr; 289 290 if (!vec->GetArray) 291 // LCOV_EXCL_START 292 return CeedError(vec->ceed, 1, "Backend does not support GetArray"); 293 // LCOV_EXCL_STOP 294 295 if (vec->state % 2 == 1) 296 return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, the " 297 "access lock is already in use"); 298 299 if (vec->numreaders > 0) 300 return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, a " 301 "process has read access"); 302 303 ierr = vec->GetArray(vec, mtype, array); CeedChk(ierr); 304 vec->state += 1; 305 306 return 0; 307 } 308 309 /** 310 @brief Get read-only access to a CeedVector via the specified memory type. 311 Restore access with @ref CeedVectorRestoreArrayRead(). 312 313 @param vec CeedVector to access 314 @param mtype Memory type on which to access the array. If the backend 315 uses a different memory type, this will perform a copy 316 (possibly cached). 317 @param[out] array Array on memory type mtype 318 319 @return An error code: 0 - success, otherwise - failure 320 321 @ref User 322 **/ 323 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mtype, 324 const CeedScalar **array) { 325 int ierr; 326 327 if (!vec->GetArrayRead) 328 // LCOV_EXCL_START 329 return CeedError(vec->ceed, 1, "Backend does not support GetArrayRead"); 330 // LCOV_EXCL_STOP 331 332 if (vec->state % 2 == 1) 333 return CeedError(vec->ceed, 1, "Cannot grant CeedVector read-only array " 334 "access, the access lock is already in use"); 335 336 ierr = vec->GetArrayRead(vec, mtype, array); CeedChk(ierr); 337 vec->numreaders++; 338 339 return 0; 340 } 341 342 /** 343 @brief Restore an array obtained using @ref CeedVectorGetArray() 344 345 @param vec CeedVector to restore 346 @param array Array of vector data 347 348 @return An error code: 0 - success, otherwise - failure 349 350 @ref User 351 **/ 352 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) { 353 int ierr; 354 355 if (!vec->RestoreArray) 356 // LCOV_EXCL_START 357 return CeedError(vec->ceed, 1, "Backend does not support RestoreArray"); 358 // LCOV_EXCL_STOP 359 360 if (vec->state % 2 != 1) 361 return CeedError(vec->ceed, 1, "Cannot restore CeedVector array access, " 362 "access was not granted"); 363 364 ierr = vec->RestoreArray(vec); CeedChk(ierr); 365 *array = NULL; 366 vec->state += 1; 367 368 return 0; 369 } 370 371 /** 372 @brief Restore an array obtained using @ref CeedVectorGetArrayRead() 373 374 @param vec CeedVector to restore 375 @param array Array of vector data 376 377 @return An error code: 0 - success, otherwise - failure 378 379 @ref User 380 **/ 381 int CeedVectorRestoreArrayRead(CeedVector vec, const CeedScalar **array) { 382 int ierr; 383 384 if (!vec->RestoreArrayRead) 385 // LCOV_EXCL_START 386 return CeedError(vec->ceed, 1, "Backend does not support RestoreArrayRead"); 387 // LCOV_EXCL_STOP 388 389 ierr = vec->RestoreArrayRead(vec); CeedChk(ierr); 390 *array = NULL; 391 vec->numreaders--; 392 393 return 0; 394 } 395 396 /** 397 @brief Get the norm of a CeedVector. 398 399 Note: This operation is local to the CeedVector. This function will likely 400 not provide the desired results for the norm of the libCEED portion 401 of a parallel vector or a CeedVector with duplicated or hanging nodes. 402 403 @param vec CeedVector to retrieve maximum value 404 @param type Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX 405 @param[out] norm Variable to store norm value 406 407 @return An error code: 0 - success, otherwise - failure 408 409 @ref User 410 **/ 411 int CeedVectorNorm(CeedVector vec, CeedNormType type, CeedScalar *norm) { 412 int ierr; 413 414 // Backend impl for GPU, if added 415 if (vec->Norm) { 416 ierr = vec->Norm(vec, type, norm); CeedChk(ierr); 417 return 0; 418 } 419 420 const CeedScalar *array; 421 ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 422 423 *norm = 0.; 424 switch (type) { 425 case CEED_NORM_1: 426 for (int i=0; i<vec->length; i++) { 427 *norm += fabs(array[i]); 428 } 429 break; 430 case CEED_NORM_2: 431 for (int i=0; i<vec->length; i++) { 432 *norm += fabs(array[i])*fabs(array[i]); 433 } 434 break; 435 case CEED_NORM_MAX: 436 for (int i=0; i<vec->length; i++) { 437 const CeedScalar absi = fabs(array[i]); 438 *norm = *norm > absi ? *norm : absi; 439 } 440 } 441 if (type == CEED_NORM_2) 442 *norm = sqrt(*norm); 443 444 ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr); 445 446 return 0; 447 } 448 449 /** 450 @brief View a CeedVector 451 452 @param[in] vec CeedVector to view 453 @param[in] fpfmt Printing format 454 @param[in] stream Filestream to write to 455 456 @return An error code: 0 - success, otherwise - failure 457 458 @ref User 459 **/ 460 int CeedVectorView(CeedVector vec, const char *fpfmt, FILE *stream) { 461 const CeedScalar *x; 462 463 int ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x); CeedChk(ierr); 464 465 char fmt[1024]; 466 fprintf(stream, "CeedVector length %ld\n", (long)vec->length); 467 snprintf(fmt, sizeof fmt, " %s\n", fpfmt ? fpfmt : "%g"); 468 for (CeedInt i=0; i<vec->length; i++) 469 fprintf(stream, fmt, x[i]); 470 471 ierr = CeedVectorRestoreArrayRead(vec, &x); CeedChk(ierr); 472 473 return 0; 474 } 475 476 /** 477 @brief Get the length of a CeedVector 478 479 @param vec CeedVector to retrieve length 480 @param[out] length Variable to store length 481 482 @return An error code: 0 - success, otherwise - failure 483 484 @ref User 485 **/ 486 int CeedVectorGetLength(CeedVector vec, CeedInt *length) { 487 *length = vec->length; 488 return 0; 489 } 490 491 /** 492 @brief Destroy a CeedVector 493 494 @param vec CeedVector to destroy 495 496 @return An error code: 0 - success, otherwise - failure 497 498 @ref User 499 **/ 500 int CeedVectorDestroy(CeedVector *vec) { 501 int ierr; 502 503 if (!*vec || --(*vec)->refcount > 0) 504 return 0; 505 506 if ((*vec) && ((*vec)->state % 2) == 1) 507 return CeedError((*vec)->ceed, 1, "Cannot destroy CeedVector, the access " 508 "lock is in use"); 509 510 if ((*vec)->Destroy) { 511 ierr = (*vec)->Destroy(*vec); CeedChk(ierr); 512 } 513 514 ierr = CeedDestroy(&(*vec)->ceed); CeedChk(ierr); 515 ierr = CeedFree(vec); CeedChk(ierr); 516 517 return 0; 518 } 519 520 /// @} 521