xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-vector.c (revision 8d000c77f4c8a05a3c1d7f8fbc4a30c9dd7770b6)
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_WEIGHT).
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 Check for valid data in a CeedVector
52 
53   @param vec                   CeedVector to check validity
54   @param[out] has_valid_array  Variable to store validity
55 
56   @return An error code: 0 - success, otherwise - failure
57 
58   @ref Backend
59 **/
60 int CeedVectorHasValidArray(CeedVector vec, bool *has_valid_array) {
61   int ierr;
62 
63   if (!vec->HasValidArray)
64     // LCOV_EXCL_START
65     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
66                      "Backend does not support HasValidArray");
67   // LCOV_EXCL_STOP
68 
69   ierr = vec->HasValidArray(vec, has_valid_array); CeedChk(ierr);
70 
71   return CEED_ERROR_SUCCESS;
72 }
73 
74 /**
75   @brief Check for borrowed array of a specific CeedMemType in a CeedVector
76 
77   @param vec                              CeedVector to check
78   @param mem_type                         Memory type to check
79   @param[out] has_borrowed_array_of_type  Variable to store result
80 
81   @return An error code: 0 - success, otherwise - failure
82 
83   @ref Backend
84 **/
85 int CeedVectorHasBorrowedArrayOfType(CeedVector vec, CeedMemType mem_type,
86                                      bool *has_borrowed_array_of_type) {
87   int ierr;
88 
89   if (!vec->HasBorrowedArrayOfType)
90     // LCOV_EXCL_START
91     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
92                      "Backend does not support HasBorrowedArrayOfType");
93   // LCOV_EXCL_STOP
94 
95   ierr = vec->HasBorrowedArrayOfType(vec, mem_type, has_borrowed_array_of_type);
96   CeedChk(ierr);
97 
98   return CEED_ERROR_SUCCESS;
99 }
100 
101 /**
102   @brief Get the state of a CeedVector
103 
104   @param vec         CeedVector to retrieve state
105   @param[out] state  Variable to store state
106 
107   @return An error code: 0 - success, otherwise - failure
108 
109   @ref Backend
110 **/
111 int CeedVectorGetState(CeedVector vec, uint64_t *state) {
112   *state = vec->state;
113   return CEED_ERROR_SUCCESS;
114 }
115 
116 /**
117   @brief Add a reference to a CeedVector
118 
119   @param[out] vec  CeedVector to increment reference counter
120 
121   @return An error code: 0 - success, otherwise - failure
122 
123   @ref Backend
124 **/
125 int CeedVectorAddReference(CeedVector vec) {
126   vec->ref_count++;
127   return CEED_ERROR_SUCCESS;
128 }
129 
130 /**
131   @brief Get the backend data of a CeedVector
132 
133   @param vec        CeedVector to retrieve state
134   @param[out] data  Variable to store data
135 
136   @return An error code: 0 - success, otherwise - failure
137 
138   @ref Backend
139 **/
140 int CeedVectorGetData(CeedVector vec, void *data) {
141   *(void **)data = vec->data;
142   return CEED_ERROR_SUCCESS;
143 }
144 
145 /**
146   @brief Set the backend data of a CeedVector
147 
148   @param[out] vec  CeedVector to retrieve state
149   @param data      Data to set
150 
151   @return An error code: 0 - success, otherwise - failure
152 
153   @ref Backend
154 **/
155 int CeedVectorSetData(CeedVector vec, void *data) {
156   vec->data = data;
157   return CEED_ERROR_SUCCESS;
158 }
159 
160 /**
161   @brief Increment the reference counter for a CeedVector
162 
163   @param vec  CeedVector to increment the reference counter
164 
165   @return An error code: 0 - success, otherwise - failure
166 
167   @ref Backend
168 **/
169 int CeedVectorReference(CeedVector vec) {
170   vec->ref_count++;
171   return CEED_ERROR_SUCCESS;
172 }
173 
174 /// @}
175 
176 /// ----------------------------------------------------------------------------
177 /// CeedVector Public API
178 /// ----------------------------------------------------------------------------
179 /// @addtogroup CeedVectorUser
180 /// @{
181 
182 /**
183   @brief Create a CeedVector of the specified length (does not allocate memory)
184 
185   @param ceed      Ceed object where the CeedVector will be created
186   @param length    Length of vector
187   @param[out] vec  Address of the variable where the newly created
188                      CeedVector will be stored
189 
190   @return An error code: 0 - success, otherwise - failure
191 
192   @ref User
193 **/
194 int CeedVectorCreate(Ceed ceed, CeedInt length, CeedVector *vec) {
195   int ierr;
196 
197   if (!ceed->VectorCreate) {
198     Ceed delegate;
199     ierr = CeedGetObjectDelegate(ceed, &delegate, "Vector"); CeedChk(ierr);
200 
201     if (!delegate)
202       // LCOV_EXCL_START
203       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
204                        "Backend does not support VectorCreate");
205     // LCOV_EXCL_STOP
206 
207     ierr = CeedVectorCreate(delegate, length, vec); CeedChk(ierr);
208     return CEED_ERROR_SUCCESS;
209   }
210 
211   ierr = CeedCalloc(1, vec); CeedChk(ierr);
212   (*vec)->ceed = ceed;
213   ierr = CeedReference(ceed); CeedChk(ierr);
214   (*vec)->ref_count = 1;
215   (*vec)->length = length;
216   (*vec)->state = 0;
217   ierr = ceed->VectorCreate(length, *vec); CeedChk(ierr);
218   return CEED_ERROR_SUCCESS;
219 }
220 
221 /**
222   @brief Copy the pointer to a CeedVector. Both pointers should
223            be destroyed with `CeedVectorDestroy()`;
224            Note: If `*vec_copy` is non-NULL, then it is assumed that
225            `*vec_copy` is a pointer to a CeedVector. This
226            CeedVector will be destroyed if `*vec_copy` is the only
227            reference to this CeedVector.
228 
229   @param vec            CeedVector to copy reference to
230   @param[out] vec_copy  Variable to store copied reference
231 
232   @return An error code: 0 - success, otherwise - failure
233 
234   @ref User
235 **/
236 int CeedVectorReferenceCopy(CeedVector vec, CeedVector *vec_copy) {
237   int ierr;
238 
239   ierr = CeedVectorReference(vec); CeedChk(ierr);
240   ierr = CeedVectorDestroy(vec_copy); CeedChk(ierr);
241   *vec_copy = vec;
242   return CEED_ERROR_SUCCESS;
243 }
244 
245 /**
246   @brief Set the array used by a CeedVector, freeing any previously allocated
247            array if applicable. The backend may copy values to a different
248            memtype, such as during @ref CeedOperatorApply().
249            See also @ref CeedVectorSyncArray() and @ref CeedVectorTakeArray().
250 
251   @param vec        CeedVector
252   @param mem_type   Memory type of the array being passed
253   @param copy_mode  Copy mode for the array
254   @param array      Array to be used, or NULL with @ref CEED_COPY_VALUES to have the
255                       library allocate
256 
257   @return An error code: 0 - success, otherwise - failure
258 
259   @ref User
260 **/
261 int CeedVectorSetArray(CeedVector vec, CeedMemType mem_type,
262                        CeedCopyMode copy_mode,
263                        CeedScalar *array) {
264   int ierr;
265 
266   if (!vec->SetArray)
267     // LCOV_EXCL_START
268     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
269                      "Backend does not support VectorSetArray");
270   // LCOV_EXCL_STOP
271 
272   if (vec->state % 2 == 1)
273     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
274                      "Cannot grant CeedVector array access, the "
275                      "access lock is already in use");
276 
277   if (vec->num_readers > 0)
278     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
279                      "Cannot grant CeedVector array access, a "
280                      "process has read access");
281 
282   ierr = vec->SetArray(vec, mem_type, copy_mode, array); CeedChk(ierr);
283   vec->state += 2;
284   return CEED_ERROR_SUCCESS;
285 }
286 
287 /**
288   @brief Set the CeedVector to a constant value
289 
290   @param vec        CeedVector
291   @param[in] value  Value to be used
292 
293   @return An error code: 0 - success, otherwise - failure
294 
295   @ref User
296 **/
297 int CeedVectorSetValue(CeedVector vec, CeedScalar value) {
298   int ierr;
299 
300   if (vec->state % 2 == 1)
301     // LCOV_EXCL_START
302     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
303                      "Cannot grant CeedVector array access, the "
304                      "access lock is already in use");
305   // LCOV_EXCL_STOP
306 
307   if (vec->num_readers > 0)
308     // LCOV_EXCL_START
309     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
310                      "Cannot grant CeedVector array access, a "
311                      "process has read access");
312   // LCOV_EXCL_STOP
313 
314   if (vec->SetValue) {
315     ierr = vec->SetValue(vec, value); CeedChk(ierr);
316   } else {
317     CeedScalar *array;
318     ierr = CeedVectorGetArrayWrite(vec, CEED_MEM_HOST, &array); CeedChk(ierr);
319     for (int i=0; i<vec->length; i++) array[i] = value;
320     ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr);
321   }
322   vec->state += 2;
323   return CEED_ERROR_SUCCESS;
324 }
325 
326 /**
327   @brief Sync the CeedVector to a specified memtype. This function is used to
328            force synchronization of arrays set with @ref CeedVectorSetArray().
329            If the requested memtype is already synchronized, this function
330            results in a no-op.
331 
332   @param vec       CeedVector
333   @param mem_type  Memtype to be synced
334 
335   @return An error code: 0 - success, otherwise - failure
336 
337   @ref User
338 **/
339 int CeedVectorSyncArray(CeedVector vec, CeedMemType mem_type) {
340   int ierr;
341 
342   if (vec->state % 2 == 1)
343     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
344                      "Cannot sync CeedVector, the access lock is "
345                      "already in use");
346 
347   if (vec->SyncArray) {
348     ierr = vec->SyncArray(vec, mem_type); CeedChk(ierr);
349   } else {
350     const CeedScalar *array;
351     ierr = CeedVectorGetArrayRead(vec, mem_type, &array); CeedChk(ierr);
352     ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr);
353   }
354   return CEED_ERROR_SUCCESS;
355 }
356 
357 /**
358   @brief Take ownership of the CeedVector array set by @ref CeedVectorSetArray()
359            with @ref CEED_USE_POINTER and remove the array from the CeedVector.
360            The caller is responsible for managing and freeing the array.
361            This function will error if @ref CeedVectorSetArray() was not previously
362            called with @ref CEED_USE_POINTER for the corresponding mem_type.
363 
364   @param vec         CeedVector
365   @param mem_type    Memory type on which to take the array. If the backend
366                        uses a different memory type, this will perform a copy.
367   @param[out] array  Array on memory type mem_type, or NULL if array pointer is
368                        not required
369 
370   @return An error code: 0 - success, otherwise - failure
371 
372   @ref User
373 **/
374 int CeedVectorTakeArray(CeedVector vec, CeedMemType mem_type,
375                         CeedScalar **array) {
376   int ierr;
377 
378   if (vec->state % 2 == 1)
379     // LCOV_EXCL_START
380     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
381                      "Cannot take CeedVector array, the access "
382                      "lock is already in use");
383   // LCOV_EXCL_STOP
384   if (vec->num_readers > 0)
385     // LCOV_EXCL_START
386     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
387                      "Cannot take CeedVector array, a process "
388                      "has read access");
389   // LCOV_EXCL_STOP
390   CeedScalar *temp_array = NULL;
391   if (vec->length > 0) {
392     bool has_borrowed_array_of_type = true;
393     ierr = CeedVectorHasBorrowedArrayOfType(vec, mem_type,
394                                             &has_borrowed_array_of_type);
395     CeedChk(ierr);
396     if (!has_borrowed_array_of_type)
397       // LCOV_EXCL_START
398       return CeedError(vec->ceed, CEED_ERROR_BACKEND,
399                        "CeedVector has no borrowed %s array, "
400                        "must set array with CeedVectorSetArray", CeedMemTypes[mem_type]);
401     // LCOV_EXCL_STOP
402 
403     bool has_valid_array = true;
404     ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
405     if (!has_valid_array)
406       // LCOV_EXCL_START
407       return CeedError(vec->ceed, CEED_ERROR_BACKEND,
408                        "CeedVector has no valid data to take, "
409                        "must set data with CeedVectorSetValue or CeedVectorSetArray");
410     // LCOV_EXCL_STOP
411 
412     ierr = vec->TakeArray(vec, mem_type, &temp_array); CeedChk(ierr);
413   }
414   if (array) (*array) = temp_array;
415   return CEED_ERROR_SUCCESS;
416 }
417 
418 /**
419   @brief Get read/write access to a CeedVector via the specified memory type.
420            Restore access with @ref CeedVectorRestoreArray().
421 
422   @param vec         CeedVector to access
423   @param mem_type    Memory type on which to access the array. If the backend
424                        uses a different memory type, this will perform a copy.
425   @param[out] array  Array on memory type mem_type
426 
427   @note The CeedVectorGetArray* and CeedVectorRestoreArray* functions provide
428     access to array pointers in the desired memory space. Pairing get/restore
429     allows the Vector to track access, thus knowing if norms or other
430     operations may need to be recomputed.
431 
432   @return An error code: 0 - success, otherwise - failure
433 
434   @ref User
435 **/
436 int CeedVectorGetArray(CeedVector vec, CeedMemType mem_type,
437                        CeedScalar **array) {
438   int ierr;
439 
440   if (!vec->GetArray)
441     // LCOV_EXCL_START
442     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
443                      "Backend does not support GetArray");
444   // LCOV_EXCL_STOP
445 
446   if (vec->state % 2 == 1)
447     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
448                      "Cannot grant CeedVector array access, the "
449                      "access lock is already in use");
450 
451   if (vec->num_readers > 0)
452     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
453                      "Cannot grant CeedVector array access, a "
454                      "process has read access");
455 
456   bool has_valid_array = true;
457   ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
458   if (!has_valid_array)
459     // LCOV_EXCL_START
460     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
461                      "CeedVector has no valid data to read, "
462                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
463   // LCOV_EXCL_STOP
464 
465   ierr = vec->GetArray(vec, mem_type, array); CeedChk(ierr);
466   vec->state += 1;
467   return CEED_ERROR_SUCCESS;
468 }
469 
470 /**
471   @brief Get read-only access to a CeedVector via the specified memory type.
472            Restore access with @ref CeedVectorRestoreArrayRead().
473 
474   @param vec         CeedVector to access
475   @param mem_type    Memory type on which to access the array.  If the backend
476                        uses a different memory type, this will perform a copy
477                        (possibly cached).
478   @param[out] array  Array on memory type mem_type
479 
480   @return An error code: 0 - success, otherwise - failure
481 
482   @ref User
483 **/
484 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mem_type,
485                            const CeedScalar **array) {
486   int ierr;
487 
488   if (!vec->GetArrayRead)
489     // LCOV_EXCL_START
490     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
491                      "Backend does not support GetArrayRead");
492   // LCOV_EXCL_STOP
493 
494   if (vec->state % 2 == 1)
495     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
496                      "Cannot grant CeedVector read-only array "
497                      "access, the access lock is already in use");
498 
499   if (vec->length > 0) {
500     bool has_valid_array = true;
501     ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
502     if (!has_valid_array)
503       // LCOV_EXCL_START
504       return CeedError(vec->ceed, CEED_ERROR_BACKEND,
505                        "CeedVector has no valid data to read, "
506                        "must set data with CeedVectorSetValue or CeedVectorSetArray");
507     // LCOV_EXCL_STOP
508 
509     ierr = vec->GetArrayRead(vec, mem_type, array); CeedChk(ierr);
510   } else {
511     *array = NULL;
512   }
513   vec->num_readers++;
514   return CEED_ERROR_SUCCESS;
515 }
516 
517 /**
518   @brief Get write access to a CeedVector via the specified memory type.
519            Restore access with @ref CeedVectorRestoreArray(). All old
520            values should be assumed to be invalid.
521 
522   @param vec         CeedVector to access
523   @param mem_type    Memory type on which to access the array.
524   @param[out] array  Array on memory type mem_type
525 
526   @return An error code: 0 - success, otherwise - failure
527 
528   @ref User
529 **/
530 int CeedVectorGetArrayWrite(CeedVector vec, CeedMemType mem_type,
531                             CeedScalar **array) {
532   int ierr;
533 
534   if (!vec->GetArrayWrite)
535     // LCOV_EXCL_START
536     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
537                      "Backend does not support GetArrayWrite");
538   // LCOV_EXCL_STOP
539 
540   if (vec->state % 2 == 1)
541     // LCOV_EXCL_START
542     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
543                      "Cannot grant CeedVector array access, the "
544                      "access lock is already in use");
545   // LCOV_EXCL_STOP
546 
547   if (vec->num_readers > 0)
548     // LCOV_EXCL_START
549     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
550                      "Cannot grant CeedVector array access, a "
551                      "process has read access");
552   // LCOV_EXCL_STOP
553 
554   ierr = vec->GetArrayWrite(vec, mem_type, array); CeedChk(ierr);
555   vec->state += 1;
556   return CEED_ERROR_SUCCESS;
557 }
558 
559 /**
560   @brief Restore an array obtained using @ref CeedVectorGetArray()
561 
562   @param vec    CeedVector to restore
563   @param array  Array of vector data
564 
565   @return An error code: 0 - success, otherwise - failure
566 
567   @ref User
568 **/
569 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) {
570   int ierr;
571 
572   if (vec->state % 2 != 1)
573     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
574                      "Cannot restore CeedVector array access, "
575                      "access was not granted");
576   if (vec->RestoreArray) {
577     ierr = vec->RestoreArray(vec); CeedChk(ierr);
578   }
579   *array = NULL;
580   vec->state += 1;
581   return CEED_ERROR_SUCCESS;
582 }
583 
584 /**
585   @brief Restore an array obtained using @ref CeedVectorGetArrayRead()
586 
587   @param vec    CeedVector to restore
588   @param array  Array of vector data
589 
590   @return An error code: 0 - success, otherwise - failure
591 
592   @ref User
593 **/
594 int CeedVectorRestoreArrayRead(CeedVector vec, const CeedScalar **array) {
595   int ierr;
596 
597   if (vec->num_readers == 0)
598     // LCOV_EXCL_START
599     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
600                      "Cannot restore CeedVector array read access, "
601                      "access was not granted");
602   // LCOV_EXCL_STOP
603 
604   if (vec->RestoreArrayRead) {
605     ierr = vec->RestoreArrayRead(vec); CeedChk(ierr);
606   }
607   *array = NULL;
608   vec->num_readers--;
609   return CEED_ERROR_SUCCESS;
610 }
611 
612 /**
613   @brief Get the norm of a CeedVector.
614 
615   Note: This operation is local to the CeedVector. This function will likely
616           not provide the desired results for the norm of the libCEED portion
617           of a parallel vector or a CeedVector with duplicated or hanging nodes.
618 
619   @param vec        CeedVector to retrieve maximum value
620   @param norm_type  Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX
621   @param[out] norm  Variable to store norm value
622 
623   @return An error code: 0 - success, otherwise - failure
624 
625   @ref User
626 **/
627 int CeedVectorNorm(CeedVector vec, CeedNormType norm_type, CeedScalar *norm) {
628   int ierr;
629 
630   bool has_valid_array = true;
631   ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
632   if (!has_valid_array)
633     // LCOV_EXCL_START
634     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
635                      "CeedVector has no valid data to compute norm, "
636                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
637   // LCOV_EXCL_STOP
638 
639   // Backend impl for GPU, if added
640   if (vec->Norm) {
641     ierr = vec->Norm(vec, norm_type, norm); CeedChk(ierr);
642     return CEED_ERROR_SUCCESS;
643   }
644 
645   const CeedScalar *array;
646   ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array); CeedChk(ierr);
647 
648   *norm = 0.;
649   switch (norm_type) {
650   case CEED_NORM_1:
651     for (int i=0; i<vec->length; i++) {
652       *norm += fabs(array[i]);
653     }
654     break;
655   case CEED_NORM_2:
656     for (int i=0; i<vec->length; i++) {
657       *norm += fabs(array[i])*fabs(array[i]);
658     }
659     break;
660   case CEED_NORM_MAX:
661     for (int i=0; i<vec->length; i++) {
662       const CeedScalar abs_v_i = fabs(array[i]);
663       *norm = *norm > abs_v_i ? *norm : abs_v_i;
664     }
665   }
666   if (norm_type == CEED_NORM_2)
667     *norm = sqrt(*norm);
668 
669   ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr);
670   return CEED_ERROR_SUCCESS;
671 }
672 
673 /**
674   @brief Compute x = alpha x
675 
676   @param[in,out] x  vector for scaling
677   @param[in] alpha  scaling factor
678 
679   @return An error code: 0 - success, otherwise - failure
680 
681   @ref User
682 **/
683 int CeedVectorScale(CeedVector x, CeedScalar alpha) {
684   int ierr;
685   CeedScalar *x_array;
686   CeedInt n_x;
687 
688   bool has_valid_array = true;
689   ierr = CeedVectorHasValidArray(x, &has_valid_array); CeedChk(ierr);
690   if (!has_valid_array)
691     // LCOV_EXCL_START
692     return CeedError(x->ceed, CEED_ERROR_BACKEND,
693                      "CeedVector has no valid data to scale, "
694                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
695   // LCOV_EXCL_STOP
696 
697   ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr);
698 
699   // Backend implementation
700   if (x->Scale)
701     return x->Scale(x, alpha);
702 
703   // Default implementation
704   ierr = CeedVectorGetArrayWrite(x, CEED_MEM_HOST, &x_array); CeedChk(ierr);
705   for (CeedInt i=0; i<n_x; i++)
706     x_array[i] *= alpha;
707   ierr = CeedVectorRestoreArray(x, &x_array); CeedChk(ierr);
708 
709   return CEED_ERROR_SUCCESS;
710 }
711 
712 /**
713   @brief Compute y = alpha x + y
714 
715   @param[in,out] y  target vector for sum
716   @param[in] alpha  scaling factor
717   @param[in] x      second vector, must be different than y
718 
719   @return An error code: 0 - success, otherwise - failure
720 
721   @ref User
722 **/
723 int CeedVectorAXPY(CeedVector y, CeedScalar alpha, CeedVector x) {
724   int ierr;
725   CeedScalar *y_array;
726   CeedScalar const *x_array;
727   CeedInt n_x, n_y;
728 
729   ierr = CeedVectorGetLength(y, &n_y); CeedChk(ierr);
730   ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr);
731   if (n_x != n_y)
732     // LCOV_EXCL_START
733     return CeedError(y->ceed, CEED_ERROR_UNSUPPORTED,
734                      "Cannot add vector of different lengths");
735   // LCOV_EXCL_STOP
736   if (x == y)
737     // LCOV_EXCL_START
738     return CeedError(y->ceed, CEED_ERROR_UNSUPPORTED,
739                      "Cannot use same vector for x and y in CeedVectorAXPY");
740   // LCOV_EXCL_STOP
741 
742   bool has_valid_array_x = true, has_valid_array_y = true;
743   ierr = CeedVectorHasValidArray(x, &has_valid_array_x); CeedChk(ierr);
744   if (!has_valid_array_x)
745     // LCOV_EXCL_START
746     return CeedError(x->ceed, CEED_ERROR_BACKEND,
747                      "CeedVector x has no valid data, "
748                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
749   // LCOV_EXCL_STOP
750   ierr = CeedVectorHasValidArray(y, &has_valid_array_y); CeedChk(ierr);
751   if (!has_valid_array_y)
752     // LCOV_EXCL_START
753     return CeedError(y->ceed, CEED_ERROR_BACKEND,
754                      "CeedVector y has no valid data, "
755                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
756   // LCOV_EXCL_STOP
757 
758   Ceed ceed_parent_x, ceed_parent_y;
759   ierr = CeedGetParent(x->ceed, &ceed_parent_x); CeedChk(ierr);
760   ierr = CeedGetParent(y->ceed, &ceed_parent_y); CeedChk(ierr);
761   if (ceed_parent_x != ceed_parent_y)
762     // LCOV_EXCL_START
763     return CeedError(y->ceed, CEED_ERROR_INCOMPATIBLE,
764                      "Vectors x and y must be created by the same Ceed context");
765   // LCOV_EXCL_STOP
766 
767   // Backend implementation
768   if (y->AXPY) {
769     ierr = y->AXPY(y, alpha, x); CeedChk(ierr);
770     return CEED_ERROR_SUCCESS;
771   }
772 
773   // Default implementation
774   ierr = CeedVectorGetArrayWrite(y, CEED_MEM_HOST, &y_array); CeedChk(ierr);
775   ierr = CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array); CeedChk(ierr);
776 
777   for (CeedInt i=0; i<n_y; i++)
778     y_array[i] += alpha * x_array[i];
779 
780   ierr = CeedVectorRestoreArray(y, &y_array); CeedChk(ierr);
781   ierr = CeedVectorRestoreArrayRead(x, &x_array); CeedChk(ierr);
782 
783   return CEED_ERROR_SUCCESS;
784 }
785 
786 /**
787   @brief Compute the pointwise multiplication w = x .* y. Any
788            subset of x, y, and w may be the same vector.
789 
790   @param[out] w  target vector for the product
791   @param[in] x   first vector for product
792   @param[in] y   second vector for the product
793 
794   @return An error code: 0 - success, otherwise - failure
795 
796   @ ref User
797 **/
798 int CeedVectorPointwiseMult(CeedVector w, CeedVector x, CeedVector y) {
799   int ierr;
800   CeedScalar *w_array;
801   CeedScalar const *x_array, *y_array;
802   CeedInt n_w, n_x, n_y;
803 
804   ierr = CeedVectorGetLength(w, &n_w); CeedChk(ierr);
805   ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr);
806   ierr = CeedVectorGetLength(y, &n_y); CeedChk(ierr);
807   if (n_w != n_x || n_w != n_y)
808     // LCOV_EXCL_START
809     return CeedError(w->ceed, CEED_ERROR_UNSUPPORTED,
810                      "Cannot multiply vectors of different lengths");
811   // LCOV_EXCL_STOP
812 
813   Ceed ceed_parent_w, ceed_parent_x, ceed_parent_y;
814   ierr = CeedGetParent(w->ceed, &ceed_parent_w); CeedChk(ierr);
815   ierr = CeedGetParent(x->ceed, &ceed_parent_x); CeedChk(ierr);
816   ierr = CeedGetParent(y->ceed, &ceed_parent_y); CeedChk(ierr);
817   if ((ceed_parent_w != ceed_parent_x) ||
818       (ceed_parent_w != ceed_parent_y))
819     // LCOV_EXCL_START
820     return CeedError(w->ceed, CEED_ERROR_INCOMPATIBLE,
821                      "Vectors w, x, and y must be created by the same Ceed context");
822   // LCOV_EXCL_STOP
823 
824   bool has_valid_array_x = true, has_valid_array_y = true;
825   ierr = CeedVectorHasValidArray(x, &has_valid_array_x); CeedChk(ierr);
826   if (!has_valid_array_x)
827     // LCOV_EXCL_START
828     return CeedError(x->ceed, CEED_ERROR_BACKEND,
829                      "CeedVector x has no valid data, "
830                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
831   // LCOV_EXCL_STOP
832   ierr = CeedVectorHasValidArray(y, &has_valid_array_y); CeedChk(ierr);
833   if (!has_valid_array_y)
834     // LCOV_EXCL_START
835     return CeedError(y->ceed, CEED_ERROR_BACKEND,
836                      "CeedVector y has no valid data, "
837                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
838   // LCOV_EXCL_STOP
839 
840   // Backend implementation
841   if (w->PointwiseMult) {
842     ierr = w->PointwiseMult(w, x, y); CeedChk(ierr);
843     return CEED_ERROR_SUCCESS;
844   }
845 
846   // Default implementation
847   ierr = CeedVectorGetArrayWrite(w, CEED_MEM_HOST, &w_array); CeedChk(ierr);
848   if (x != w) {
849     ierr = CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array); CeedChk(ierr);
850   } else {
851     x_array = w_array;
852   }
853   if (y != w && y != x) {
854     ierr = CeedVectorGetArrayRead(y, CEED_MEM_HOST, &y_array); CeedChk(ierr);
855   } else if (y != x) {
856     y_array = w_array;
857   } else {
858     y_array = x_array;
859   }
860 
861   for (CeedInt i=0; i<n_w; i++)
862     w_array[i] = x_array[i] * y_array[i];
863 
864   if (y != w && y != x) {
865     ierr = CeedVectorRestoreArrayRead(y, &y_array); CeedChk(ierr);
866   }
867   if (x != w) {
868     ierr = CeedVectorRestoreArrayRead(x, &x_array); CeedChk(ierr);
869   }
870   ierr = CeedVectorRestoreArray(w, &w_array); CeedChk(ierr);
871   return CEED_ERROR_SUCCESS;
872 }
873 
874 /**
875   @brief Take the reciprocal of a CeedVector.
876 
877   @param vec  CeedVector to take reciprocal
878 
879   @return An error code: 0 - success, otherwise - failure
880 
881   @ref User
882 **/
883 int CeedVectorReciprocal(CeedVector vec) {
884   int ierr;
885 
886   bool has_valid_array = true;
887   ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
888   if (!has_valid_array)
889     // LCOV_EXCL_START
890     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
891                      "CeedVector has no valid data to compute reciprocal, "
892                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
893   // LCOV_EXCL_STOP
894 
895   // Check if vector data set
896   if (!vec->state)
897     // LCOV_EXCL_START
898     return CeedError(vec->ceed, CEED_ERROR_INCOMPLETE,
899                      "CeedVector must have data set to take reciprocal");
900   // LCOV_EXCL_STOP
901 
902   // Backend impl for GPU, if added
903   if (vec->Reciprocal) {
904     ierr = vec->Reciprocal(vec); CeedChk(ierr);
905     return CEED_ERROR_SUCCESS;
906   }
907 
908   CeedInt len;
909   ierr = CeedVectorGetLength(vec, &len); CeedChk(ierr);
910   CeedScalar *array;
911   ierr = CeedVectorGetArrayWrite(vec, CEED_MEM_HOST, &array); CeedChk(ierr);
912   for (CeedInt i=0; i<len; i++)
913     if (fabs(array[i]) > CEED_EPSILON)
914       array[i] = 1./array[i];
915 
916   ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr);
917   return CEED_ERROR_SUCCESS;
918 }
919 
920 /**
921   @brief View a CeedVector
922 
923   @param[in] vec     CeedVector to view
924   @param[in] fp_fmt  Printing format
925   @param[in] stream  Filestream to write to
926 
927   @return An error code: 0 - success, otherwise - failure
928 
929   @ref User
930 **/
931 int CeedVectorView(CeedVector vec, const char *fp_fmt, FILE *stream) {
932   const CeedScalar *x;
933 
934   int ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x); CeedChk(ierr);
935 
936   char fmt[1024];
937   fprintf(stream, "CeedVector length %ld\n", (long)vec->length);
938   snprintf(fmt, sizeof fmt, "  %s\n", fp_fmt ? fp_fmt : "%g");
939   for (CeedInt i=0; i<vec->length; i++)
940     fprintf(stream, fmt, x[i]);
941 
942   ierr = CeedVectorRestoreArrayRead(vec, &x); CeedChk(ierr);
943   return CEED_ERROR_SUCCESS;
944 }
945 
946 /**
947   @brief Get the Ceed associated with a CeedVector
948 
949   @param vec        CeedVector to retrieve state
950   @param[out] ceed  Variable to store ceed
951 
952   @return An error code: 0 - success, otherwise - failure
953 
954   @ref Advanced
955 **/
956 int CeedVectorGetCeed(CeedVector vec, Ceed *ceed) {
957   *ceed = vec->ceed;
958   return CEED_ERROR_SUCCESS;
959 }
960 
961 /**
962   @brief Get the length of a CeedVector
963 
964   @param vec          CeedVector to retrieve length
965   @param[out] length  Variable to store length
966 
967   @return An error code: 0 - success, otherwise - failure
968 
969   @ref User
970 **/
971 int CeedVectorGetLength(CeedVector vec, CeedInt *length) {
972   *length = vec->length;
973   return CEED_ERROR_SUCCESS;
974 }
975 
976 /**
977   @brief Destroy a CeedVector
978 
979   @param vec  CeedVector to destroy
980 
981   @return An error code: 0 - success, otherwise - failure
982 
983   @ref User
984 **/
985 int CeedVectorDestroy(CeedVector *vec) {
986   int ierr;
987 
988   if (!*vec || --(*vec)->ref_count > 0) return CEED_ERROR_SUCCESS;
989 
990   if (((*vec)->state % 2) == 1)
991     return CeedError((*vec)->ceed, CEED_ERROR_ACCESS,
992                      "Cannot destroy CeedVector, the writable access "
993                      "lock is in use");
994 
995   if ((*vec)->num_readers > 0)
996     // LCOV_EXCL_START
997     return CeedError((*vec)->ceed, CEED_ERROR_ACCESS,
998                      "Cannot destroy CeedVector, a process has "
999                      "read access");
1000   // LCOV_EXCL_STOP
1001 
1002   if ((*vec)->Destroy) {
1003     ierr = (*vec)->Destroy(*vec); CeedChk(ierr);
1004   }
1005 
1006   ierr = CeedDestroy(&(*vec)->ceed); CeedChk(ierr);
1007   ierr = CeedFree(vec); CeedChk(ierr);
1008   return CEED_ERROR_SUCCESS;
1009 }
1010 
1011 /// @}
1012