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