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 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 refrence 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 170 171 @param vec CeedVector 172 @param mtype Memory type of the array being passed 173 @param cmode Copy mode for the array 174 @param array Array to be used, or NULL with CEED_COPY_VALUES to have the 175 library allocate 176 177 @return An error code: 0 - success, otherwise - failure 178 179 @ref User 180 **/ 181 int CeedVectorSetArray(CeedVector vec, CeedMemType mtype, CeedCopyMode cmode, 182 CeedScalar *array) { 183 int ierr; 184 185 if (!vec->SetArray) 186 // LCOV_EXCL_START 187 return CeedError(vec->ceed, 1, "Backend does not support VectorSetArray"); 188 // LCOV_EXCL_STOP 189 190 if (vec->state % 2 == 1) 191 return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, the " 192 "access lock is already in use"); 193 194 if (vec->numreaders > 0) 195 return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, a " 196 "process has read access"); 197 198 ierr = vec->SetArray(vec, mtype, cmode, array); CeedChk(ierr); 199 vec->state += 2; 200 201 return 0; 202 } 203 204 /** 205 @brief Set the CeedVector to a constant value 206 207 @param vec CeedVector 208 @param[in] value Value to be used 209 210 @return An error code: 0 - success, otherwise - failure 211 212 @ref User 213 **/ 214 int CeedVectorSetValue(CeedVector vec, CeedScalar value) { 215 int ierr; 216 217 if (vec->state % 2 == 1) 218 return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, the " 219 "access lock is already in use"); 220 221 if (vec->SetValue) { 222 ierr = vec->SetValue(vec, value); CeedChk(ierr); 223 } else { 224 CeedScalar *array; 225 ierr = CeedVectorGetArray(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 226 for (int i=0; i<vec->length; i++) array[i] = value; 227 ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr); 228 } 229 230 vec->state += 2; 231 232 return 0; 233 } 234 235 /** 236 @brief Sync the CeedVector to a specified memtype 237 238 @param vec CeedVector 239 @param mtype Memtype to be synced 240 241 @return An error code: 0 - success, otherwise - failure 242 243 @ref User 244 **/ 245 int CeedVectorSyncArray(CeedVector vec, CeedMemType mtype) { 246 int ierr; 247 248 if (vec->state % 2 == 1) 249 return CeedError(vec->ceed, 1, "Cannot sync CeedVector, the access lock is " 250 "already in use"); 251 252 if (vec->SyncArray) { 253 ierr = vec->SyncArray(vec, mtype); CeedChk(ierr); 254 } else { 255 const CeedScalar *array; 256 ierr = CeedVectorGetArrayRead(vec, mtype, &array); CeedChk(ierr); 257 ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr); 258 } 259 260 return 0; 261 } 262 263 /** 264 @brief Get read/write access to a CeedVector via the specified memory type 265 266 @param vec CeedVector to access 267 @param mtype Memory type on which to access the array. If the backend 268 uses a different memory type, this will perform a copy and 269 CeedVectorRestoreArray() will copy back. 270 @param[out] array Array on memory type mtype 271 272 @note The CeedVectorGetArray* and CeedVectorRestoreArray* functions provide 273 access to array pointers in the desired memory space. Pairing get/restore 274 allows the Vector to track access, thus knowing if norms or other 275 operations may need to be recomputed. 276 277 @return An error code: 0 - success, otherwise - failure 278 279 @ref User 280 **/ 281 int CeedVectorGetArray(CeedVector vec, CeedMemType mtype, CeedScalar **array) { 282 int ierr; 283 284 if (!vec->GetArray) 285 // LCOV_EXCL_START 286 return CeedError(vec->ceed, 1, "Backend does not support GetArray"); 287 // LCOV_EXCL_STOP 288 289 if (vec->state % 2 == 1) 290 return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, the " 291 "access lock is already in use"); 292 293 if (vec->numreaders > 0) 294 return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, a " 295 "process has read access"); 296 297 ierr = vec->GetArray(vec, mtype, array); CeedChk(ierr); 298 vec->state += 1; 299 300 return 0; 301 } 302 303 /** 304 @brief Get read-only access to a CeedVector via the specified memory type 305 306 @param vec CeedVector to access 307 @param mtype Memory type on which to access the array. If the backend 308 uses a different memory type, this will perform a copy 309 (possibly cached). 310 @param[out] array Array on memory type mtype 311 312 @return An error code: 0 - success, otherwise - failure 313 314 @ref User 315 **/ 316 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mtype, 317 const CeedScalar **array) { 318 int ierr; 319 320 if (!vec->GetArrayRead) 321 // LCOV_EXCL_START 322 return CeedError(vec->ceed, 1, "Backend does not support GetArrayRead"); 323 // LCOV_EXCL_STOP 324 325 if (vec->state % 2 == 1) 326 return CeedError(vec->ceed, 1, "Cannot grant CeedVector read-only array " 327 "access, the access lock is already in use"); 328 329 ierr = vec->GetArrayRead(vec, mtype, array); CeedChk(ierr); 330 vec->numreaders++; 331 332 return 0; 333 } 334 335 /** 336 @brief Restore an array obtained using CeedVectorGetArray() 337 338 @param vec CeedVector to restore 339 @param array Array of vector data 340 341 @return An error code: 0 - success, otherwise - failure 342 343 @ref User 344 **/ 345 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) { 346 int ierr; 347 348 if (!vec->RestoreArray) 349 // LCOV_EXCL_START 350 return CeedError(vec->ceed, 1, "Backend does not support RestoreArray"); 351 // LCOV_EXCL_STOP 352 353 if (vec->state % 2 != 1) 354 return CeedError(vec->ceed, 1, "Cannot restore CeedVector array access, " 355 "access was not granted"); 356 357 ierr = vec->RestoreArray(vec); CeedChk(ierr); 358 *array = NULL; 359 vec->state += 1; 360 361 return 0; 362 } 363 364 /** 365 @brief Restore an array obtained using CeedVectorGetArrayRead() 366 367 @param vec CeedVector to restore 368 @param array Array of vector data 369 370 @return An error code: 0 - success, otherwise - failure 371 372 @ref User 373 **/ 374 int CeedVectorRestoreArrayRead(CeedVector vec, const CeedScalar **array) { 375 int ierr; 376 377 if (!vec->RestoreArrayRead) 378 // LCOV_EXCL_START 379 return CeedError(vec->ceed, 1, "Backend does not support RestoreArrayRead"); 380 // LCOV_EXCL_STOP 381 382 ierr = vec->RestoreArrayRead(vec); CeedChk(ierr); 383 *array = NULL; 384 vec->numreaders--; 385 386 return 0; 387 } 388 389 /** 390 @brief Get the norm of a CeedVector. 391 392 Note: This operation is local to the CeedVector. This function will likely 393 not provide the desired results for the norm of the libCEED portion 394 of a parallel vector or a CeedVector with duplicated or hanging nodes. 395 396 @param vec CeedVector to retrieve maximum value 397 @param type Norm type CEED_NORM_1, CEED_NORM_2, or CEED_NORM_MAX 398 @param[out] norm Variable to store norm value 399 400 @return An error code: 0 - success, otherwise - failure 401 402 @ref User 403 **/ 404 int CeedVectorNorm(CeedVector vec, CeedNormType type, CeedScalar *norm) { 405 int ierr; 406 407 // Backend impl for GPU, if added 408 if (vec->Norm) { 409 ierr = vec->Norm(vec, type, norm); CeedChk(ierr); 410 return 0; 411 } 412 413 const CeedScalar *array; 414 ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 415 416 *norm = 0.; 417 switch (type) { 418 case CEED_NORM_1: 419 for (int i=0; i<vec->length; i++) { 420 *norm += fabs(array[i]); 421 } 422 break; 423 case CEED_NORM_2: 424 for (int i=0; i<vec->length; i++) { 425 *norm += fabs(array[i])*fabs(array[i]); 426 } 427 break; 428 case CEED_NORM_MAX: 429 for (int i=0; i<vec->length; i++) { 430 const CeedScalar absi = fabs(array[i]); 431 *norm = *norm > absi ? *norm : absi; 432 } 433 } 434 if (type == CEED_NORM_2) 435 *norm = sqrt(*norm); 436 437 ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr); 438 439 return 0; 440 } 441 442 /** 443 @brief View a CeedVector 444 445 @param[in] vec CeedVector to view 446 @param[in] fpfmt Printing format 447 @param[in] stream Filestream to write to 448 449 @return An error code: 0 - success, otherwise - failure 450 451 @ref User 452 **/ 453 int CeedVectorView(CeedVector vec, const char *fpfmt, FILE *stream) { 454 const CeedScalar *x; 455 456 int ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x); CeedChk(ierr); 457 458 char fmt[1024]; 459 fprintf(stream, "CeedVector length %ld\n", (long)vec->length); 460 snprintf(fmt, sizeof fmt, " %s\n", fpfmt ? fpfmt : "%g"); 461 for (CeedInt i=0; i<vec->length; i++) 462 fprintf(stream, fmt, x[i]); 463 464 ierr = CeedVectorRestoreArrayRead(vec, &x); CeedChk(ierr); 465 466 return 0; 467 } 468 469 /** 470 @brief Get the length of a CeedVector 471 472 @param vec CeedVector to retrieve length 473 @param[out] length Variable to store length 474 475 @return An error code: 0 - success, otherwise - failure 476 477 @ref User 478 **/ 479 int CeedVectorGetLength(CeedVector vec, CeedInt *length) { 480 *length = vec->length; 481 return 0; 482 } 483 484 /** 485 @brief Destroy a CeedVector 486 487 @param vec CeedVector to destroy 488 489 @return An error code: 0 - success, otherwise - failure 490 491 @ref User 492 **/ 493 int CeedVectorDestroy(CeedVector *vec) { 494 int ierr; 495 496 if (!*vec || --(*vec)->refcount > 0) 497 return 0; 498 499 if ((*vec) && ((*vec)->state % 2) == 1) 500 return CeedError((*vec)->ceed, 1, "Cannot destroy CeedVector, the access " 501 "lock is in use"); 502 503 if ((*vec)->Destroy) { 504 ierr = (*vec)->Destroy(*vec); CeedChk(ierr); 505 } 506 507 ierr = CeedDestroy(&(*vec)->ceed); CeedChk(ierr); 508 ierr = CeedFree(vec); CeedChk(ierr); 509 510 return 0; 511 } 512 513 /// @} 514