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