xref: /libCEED/interface/ceed-vector.c (revision bd4df46207a63b48a485389a63848eb7a2477f6b)
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