xref: /libCEED/interface/ceed-vector.c (revision 7fcac03628df7c326a56de618266f195cb34c506)
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 
391   bool has_borrowed_array_of_type = true;
392   ierr = CeedVectorHasBorrowedArrayOfType(vec, mem_type,
393                                           &has_borrowed_array_of_type);
394   CeedChk(ierr);
395   if (!has_borrowed_array_of_type)
396     // LCOV_EXCL_START
397     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
398                      "CeedVector has no borrowed %s array, "
399                      "must set array with CeedVectorSetArray", CeedMemTypes[mem_type]);
400   // LCOV_EXCL_STOP
401 
402   bool has_valid_array = true;
403   ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
404   if (!has_valid_array)
405     // LCOV_EXCL_START
406     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
407                      "CeedVector has no valid data to take, "
408                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
409   // LCOV_EXCL_STOP
410 
411   CeedScalar *temp_array = NULL;
412   ierr = vec->TakeArray(vec, mem_type, &temp_array); CeedChk(ierr);
413   if (array) (*array) = temp_array;
414   return CEED_ERROR_SUCCESS;
415 }
416 
417 /**
418   @brief Get read/write access to a CeedVector via the specified memory type.
419            Restore access with @ref CeedVectorRestoreArray().
420 
421   @param vec         CeedVector to access
422   @param mem_type    Memory type on which to access the array. If the backend
423                        uses a different memory type, this will perform a copy.
424   @param[out] array  Array on memory type mem_type
425 
426   @note The CeedVectorGetArray* and CeedVectorRestoreArray* functions provide
427     access to array pointers in the desired memory space. Pairing get/restore
428     allows the Vector to track access, thus knowing if norms or other
429     operations may need to be recomputed.
430 
431   @return An error code: 0 - success, otherwise - failure
432 
433   @ref User
434 **/
435 int CeedVectorGetArray(CeedVector vec, CeedMemType mem_type,
436                        CeedScalar **array) {
437   int ierr;
438 
439   if (!vec->GetArray)
440     // LCOV_EXCL_START
441     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
442                      "Backend does not support GetArray");
443   // LCOV_EXCL_STOP
444 
445   if (vec->state % 2 == 1)
446     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
447                      "Cannot grant CeedVector array access, the "
448                      "access lock is already in use");
449 
450   if (vec->num_readers > 0)
451     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
452                      "Cannot grant CeedVector array access, a "
453                      "process has read access");
454 
455   bool has_valid_array = true;
456   ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
457   if (!has_valid_array)
458     // LCOV_EXCL_START
459     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
460                      "CeedVector has no valid data to read, "
461                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
462   // LCOV_EXCL_STOP
463 
464   ierr = vec->GetArray(vec, mem_type, array); CeedChk(ierr);
465   vec->state += 1;
466   return CEED_ERROR_SUCCESS;
467 }
468 
469 /**
470   @brief Get read-only access to a CeedVector via the specified memory type.
471            Restore access with @ref CeedVectorRestoreArrayRead().
472 
473   @param vec         CeedVector to access
474   @param mem_type    Memory type on which to access the array.  If the backend
475                        uses a different memory type, this will perform a copy
476                        (possibly cached).
477   @param[out] array  Array on memory type mem_type
478 
479   @return An error code: 0 - success, otherwise - failure
480 
481   @ref User
482 **/
483 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mem_type,
484                            const CeedScalar **array) {
485   int ierr;
486 
487   if (!vec->GetArrayRead)
488     // LCOV_EXCL_START
489     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
490                      "Backend does not support GetArrayRead");
491   // LCOV_EXCL_STOP
492 
493   if (vec->state % 2 == 1)
494     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
495                      "Cannot grant CeedVector read-only array "
496                      "access, the access lock is already in use");
497 
498   bool has_valid_array = true;
499   ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
500   if (!has_valid_array)
501     // LCOV_EXCL_START
502     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
503                      "CeedVector has no valid data to read, "
504                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
505   // LCOV_EXCL_STOP
506 
507   ierr = vec->GetArrayRead(vec, mem_type, array); CeedChk(ierr);
508   vec->num_readers++;
509   return CEED_ERROR_SUCCESS;
510 }
511 
512 /**
513   @brief Get write access to a CeedVector via the specified memory type.
514            Restore access with @ref CeedVectorRestoreArray(). All old
515            values should be assumed to be invalid.
516 
517   @param vec         CeedVector to access
518   @param mem_type    Memory type on which to access the array.
519   @param[out] array  Array on memory type mem_type
520 
521   @return An error code: 0 - success, otherwise - failure
522 
523   @ref User
524 **/
525 int CeedVectorGetArrayWrite(CeedVector vec, CeedMemType mem_type,
526                             CeedScalar **array) {
527   int ierr;
528 
529   if (!vec->GetArrayWrite)
530     // LCOV_EXCL_START
531     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
532                      "Backend does not support GetArrayWrite");
533   // LCOV_EXCL_STOP
534 
535   if (vec->state % 2 == 1)
536     // LCOV_EXCL_START
537     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
538                      "Cannot grant CeedVector array access, the "
539                      "access lock is already in use");
540   // LCOV_EXCL_STOP
541 
542   if (vec->num_readers > 0)
543     // LCOV_EXCL_START
544     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
545                      "Cannot grant CeedVector array access, a "
546                      "process has read access");
547   // LCOV_EXCL_STOP
548 
549   ierr = vec->GetArrayWrite(vec, mem_type, array); CeedChk(ierr);
550   vec->state += 1;
551   return CEED_ERROR_SUCCESS;
552 }
553 
554 /**
555   @brief Restore an array obtained using @ref CeedVectorGetArray()
556 
557   @param vec    CeedVector to restore
558   @param array  Array of vector data
559 
560   @return An error code: 0 - success, otherwise - failure
561 
562   @ref User
563 **/
564 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) {
565   int ierr;
566 
567   if (!vec->RestoreArray)
568     // LCOV_EXCL_START
569     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
570                      "Backend does not support RestoreArray");
571   // LCOV_EXCL_STOP
572 
573   if (vec->state % 2 != 1)
574     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
575                      "Cannot restore CeedVector array access, "
576                      "access was not granted");
577 
578   ierr = vec->RestoreArray(vec); CeedChk(ierr);
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->RestoreArrayRead)
598     // LCOV_EXCL_START
599     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
600                      "Backend does not support RestoreArrayRead");
601   // LCOV_EXCL_STOP
602 
603   if (vec->num_readers == 0)
604     // LCOV_EXCL_START
605     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
606                      "Cannot restore CeedVector array read access, "
607                      "access was not granted");
608   // LCOV_EXCL_STOP
609 
610   ierr = vec->RestoreArrayRead(vec); CeedChk(ierr);
611   *array = NULL;
612   vec->num_readers--;
613   return CEED_ERROR_SUCCESS;
614 }
615 
616 /**
617   @brief Get the norm of a CeedVector.
618 
619   Note: This operation is local to the CeedVector. This function will likely
620           not provide the desired results for the norm of the libCEED portion
621           of a parallel vector or a CeedVector with duplicated or hanging nodes.
622 
623   @param vec        CeedVector to retrieve maximum value
624   @param norm_type  Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX
625   @param[out] norm  Variable to store norm value
626 
627   @return An error code: 0 - success, otherwise - failure
628 
629   @ref User
630 **/
631 int CeedVectorNorm(CeedVector vec, CeedNormType norm_type, CeedScalar *norm) {
632   int ierr;
633 
634   bool has_valid_array = true;
635   ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
636   if (!has_valid_array)
637     // LCOV_EXCL_START
638     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
639                      "CeedVector has no valid data to compute norm, "
640                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
641   // LCOV_EXCL_STOP
642 
643   // Backend impl for GPU, if added
644   if (vec->Norm) {
645     ierr = vec->Norm(vec, norm_type, norm); CeedChk(ierr);
646     return CEED_ERROR_SUCCESS;
647   }
648 
649   const CeedScalar *array;
650   ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array); CeedChk(ierr);
651 
652   *norm = 0.;
653   switch (norm_type) {
654   case CEED_NORM_1:
655     for (int i=0; i<vec->length; i++) {
656       *norm += fabs(array[i]);
657     }
658     break;
659   case CEED_NORM_2:
660     for (int i=0; i<vec->length; i++) {
661       *norm += fabs(array[i])*fabs(array[i]);
662     }
663     break;
664   case CEED_NORM_MAX:
665     for (int i=0; i<vec->length; i++) {
666       const CeedScalar abs_v_i = fabs(array[i]);
667       *norm = *norm > abs_v_i ? *norm : abs_v_i;
668     }
669   }
670   if (norm_type == CEED_NORM_2)
671     *norm = sqrt(*norm);
672 
673   ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr);
674   return CEED_ERROR_SUCCESS;
675 }
676 
677 /**
678   @brief Compute x = alpha x
679 
680   @param[in,out] x  vector for scaling
681   @param[in] alpha  scaling factor
682 
683   @return An error code: 0 - success, otherwise - failure
684 
685   @ref User
686 **/
687 int CeedVectorScale(CeedVector x, CeedScalar alpha) {
688   int ierr;
689   CeedScalar *x_array;
690   CeedInt n_x;
691 
692   bool has_valid_array = true;
693   ierr = CeedVectorHasValidArray(x, &has_valid_array); CeedChk(ierr);
694   if (!has_valid_array)
695     // LCOV_EXCL_START
696     return CeedError(x->ceed, CEED_ERROR_BACKEND,
697                      "CeedVector has no valid data to scale, "
698                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
699   // LCOV_EXCL_STOP
700 
701   ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr);
702 
703   // Backend implementation
704   if (x->Scale)
705     return x->Scale(x, alpha);
706 
707   // Default implementation
708   ierr = CeedVectorGetArrayWrite(x, CEED_MEM_HOST, &x_array); CeedChk(ierr);
709   for (CeedInt i=0; i<n_x; i++)
710     x_array[i] *= alpha;
711   ierr = CeedVectorRestoreArray(x, &x_array); CeedChk(ierr);
712 
713   return CEED_ERROR_SUCCESS;
714 }
715 
716 /**
717   @brief Compute y = alpha x + y
718 
719   @param[in,out] y  target vector for sum
720   @param[in] alpha  scaling factor
721   @param[in] x      second vector, must be different than y
722 
723   @return An error code: 0 - success, otherwise - failure
724 
725   @ref User
726 **/
727 int CeedVectorAXPY(CeedVector y, CeedScalar alpha, CeedVector x) {
728   int ierr;
729   CeedScalar *y_array;
730   CeedScalar const *x_array;
731   CeedInt n_x, n_y;
732 
733   ierr = CeedVectorGetLength(y, &n_y); CeedChk(ierr);
734   ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr);
735   if (n_x != n_y)
736     // LCOV_EXCL_START
737     return CeedError(y->ceed, CEED_ERROR_UNSUPPORTED,
738                      "Cannot add vector of different lengths");
739   // LCOV_EXCL_STOP
740   if (x == y)
741     // LCOV_EXCL_START
742     return CeedError(y->ceed, CEED_ERROR_UNSUPPORTED,
743                      "Cannot use same vector for x and y in CeedVectorAXPY");
744   // LCOV_EXCL_STOP
745 
746   bool has_valid_array_x = true, has_valid_array_y = true;
747   ierr = CeedVectorHasValidArray(x, &has_valid_array_x); CeedChk(ierr);
748   if (!has_valid_array_x)
749     // LCOV_EXCL_START
750     return CeedError(x->ceed, CEED_ERROR_BACKEND,
751                      "CeedVector x has no valid data, "
752                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
753   // LCOV_EXCL_STOP
754   ierr = CeedVectorHasValidArray(y, &has_valid_array_y); CeedChk(ierr);
755   if (!has_valid_array_y)
756     // LCOV_EXCL_START
757     return CeedError(y->ceed, CEED_ERROR_BACKEND,
758                      "CeedVector y has no valid data, "
759                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
760   // LCOV_EXCL_STOP
761 
762   Ceed ceed_parent_x, ceed_parent_y;
763   ierr = CeedGetParent(x->ceed, &ceed_parent_x); CeedChk(ierr);
764   ierr = CeedGetParent(y->ceed, &ceed_parent_y); CeedChk(ierr);
765   if (ceed_parent_x != ceed_parent_y)
766     // LCOV_EXCL_START
767     return CeedError(y->ceed, CEED_ERROR_INCOMPATIBLE,
768                      "Vectors x and y must be created by the same Ceed context");
769   // LCOV_EXCL_STOP
770 
771   // Backend implementation
772   if (y->AXPY) {
773     ierr = y->AXPY(y, alpha, x); CeedChk(ierr);
774     return CEED_ERROR_SUCCESS;
775   }
776 
777   // Default implementation
778   ierr = CeedVectorGetArrayWrite(y, CEED_MEM_HOST, &y_array); CeedChk(ierr);
779   ierr = CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array); CeedChk(ierr);
780 
781   for (CeedInt i=0; i<n_y; i++)
782     y_array[i] += alpha * x_array[i];
783 
784   ierr = CeedVectorRestoreArray(y, &y_array); CeedChk(ierr);
785   ierr = CeedVectorRestoreArrayRead(x, &x_array); CeedChk(ierr);
786 
787   return CEED_ERROR_SUCCESS;
788 }
789 
790 /**
791   @brief Compute the pointwise multiplication w = x .* y. Any
792            subset of x, y, and w may be the same vector.
793 
794   @param[out] w  target vector for the product
795   @param[in] x   first vector for product
796   @param[in] y   second vector for the product
797 
798   @return An error code: 0 - success, otherwise - failure
799 
800   @ ref User
801 **/
802 int CeedVectorPointwiseMult(CeedVector w, CeedVector x, CeedVector y) {
803   int ierr;
804   CeedScalar *w_array;
805   CeedScalar const *x_array, *y_array;
806   CeedInt n_w, n_x, n_y;
807 
808   ierr = CeedVectorGetLength(w, &n_w); CeedChk(ierr);
809   ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr);
810   ierr = CeedVectorGetLength(y, &n_y); CeedChk(ierr);
811   if (n_w != n_x || n_w != n_y)
812     // LCOV_EXCL_START
813     return CeedError(w->ceed, CEED_ERROR_UNSUPPORTED,
814                      "Cannot multiply vectors of different lengths");
815   // LCOV_EXCL_STOP
816 
817   Ceed ceed_parent_w, ceed_parent_x, ceed_parent_y;
818   ierr = CeedGetParent(w->ceed, &ceed_parent_w); CeedChk(ierr);
819   ierr = CeedGetParent(x->ceed, &ceed_parent_x); CeedChk(ierr);
820   ierr = CeedGetParent(y->ceed, &ceed_parent_y); CeedChk(ierr);
821   if ((ceed_parent_w != ceed_parent_x) ||
822       (ceed_parent_w != ceed_parent_y))
823     // LCOV_EXCL_START
824     return CeedError(w->ceed, CEED_ERROR_INCOMPATIBLE,
825                      "Vectors w, x, and y must be created by the same Ceed context");
826   // LCOV_EXCL_STOP
827 
828   bool has_valid_array_x = true, has_valid_array_y = true;
829   ierr = CeedVectorHasValidArray(x, &has_valid_array_x); CeedChk(ierr);
830   if (!has_valid_array_x)
831     // LCOV_EXCL_START
832     return CeedError(x->ceed, CEED_ERROR_BACKEND,
833                      "CeedVector x has no valid data, "
834                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
835   // LCOV_EXCL_STOP
836   ierr = CeedVectorHasValidArray(y, &has_valid_array_y); CeedChk(ierr);
837   if (!has_valid_array_y)
838     // LCOV_EXCL_START
839     return CeedError(y->ceed, CEED_ERROR_BACKEND,
840                      "CeedVector y has no valid data, "
841                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
842   // LCOV_EXCL_STOP
843 
844   // Backend implementation
845   if (w->PointwiseMult) {
846     ierr = w->PointwiseMult(w, x, y); CeedChk(ierr);
847     return CEED_ERROR_SUCCESS;
848   }
849 
850   // Default implementation
851   ierr = CeedVectorGetArrayWrite(w, CEED_MEM_HOST, &w_array); CeedChk(ierr);
852   if (x != w) {
853     ierr = CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array); CeedChk(ierr);
854   } else {
855     x_array = w_array;
856   }
857   if (y != w && y != x) {
858     ierr = CeedVectorGetArrayRead(y, CEED_MEM_HOST, &y_array); CeedChk(ierr);
859   } else if (y != x) {
860     y_array = w_array;
861   } else {
862     y_array = x_array;
863   }
864 
865   for (CeedInt i=0; i<n_w; i++)
866     w_array[i] = x_array[i] * y_array[i];
867 
868   if (y != w && y != x) {
869     ierr = CeedVectorRestoreArrayRead(y, &y_array); CeedChk(ierr);
870   }
871   if (x != w) {
872     ierr = CeedVectorRestoreArrayRead(x, &x_array); CeedChk(ierr);
873   }
874   ierr = CeedVectorRestoreArray(w, &w_array); CeedChk(ierr);
875   return CEED_ERROR_SUCCESS;
876 }
877 
878 /**
879   @brief Take the reciprocal of a CeedVector.
880 
881   @param vec  CeedVector to take reciprocal
882 
883   @return An error code: 0 - success, otherwise - failure
884 
885   @ref User
886 **/
887 int CeedVectorReciprocal(CeedVector vec) {
888   int ierr;
889 
890   bool has_valid_array = true;
891   ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
892   if (!has_valid_array)
893     // LCOV_EXCL_START
894     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
895                      "CeedVector has no valid data to compute reciprocal, "
896                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
897   // LCOV_EXCL_STOP
898 
899   // Check if vector data set
900   if (!vec->state)
901     // LCOV_EXCL_START
902     return CeedError(vec->ceed, CEED_ERROR_INCOMPLETE,
903                      "CeedVector must have data set to take reciprocal");
904   // LCOV_EXCL_STOP
905 
906   // Backend impl for GPU, if added
907   if (vec->Reciprocal) {
908     ierr = vec->Reciprocal(vec); CeedChk(ierr);
909     return CEED_ERROR_SUCCESS;
910   }
911 
912   CeedInt len;
913   ierr = CeedVectorGetLength(vec, &len); CeedChk(ierr);
914   CeedScalar *array;
915   ierr = CeedVectorGetArrayWrite(vec, CEED_MEM_HOST, &array); CeedChk(ierr);
916   for (CeedInt i=0; i<len; i++)
917     if (fabs(array[i]) > CEED_EPSILON)
918       array[i] = 1./array[i];
919 
920   ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr);
921   return CEED_ERROR_SUCCESS;
922 }
923 
924 /**
925   @brief View a CeedVector
926 
927   @param[in] vec     CeedVector to view
928   @param[in] fp_fmt  Printing format
929   @param[in] stream  Filestream to write to
930 
931   @return An error code: 0 - success, otherwise - failure
932 
933   @ref User
934 **/
935 int CeedVectorView(CeedVector vec, const char *fp_fmt, FILE *stream) {
936   const CeedScalar *x;
937 
938   int ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x); CeedChk(ierr);
939 
940   char fmt[1024];
941   fprintf(stream, "CeedVector length %ld\n", (long)vec->length);
942   snprintf(fmt, sizeof fmt, "  %s\n", fp_fmt ? fp_fmt : "%g");
943   for (CeedInt i=0; i<vec->length; i++)
944     fprintf(stream, fmt, x[i]);
945 
946   ierr = CeedVectorRestoreArrayRead(vec, &x); CeedChk(ierr);
947   return CEED_ERROR_SUCCESS;
948 }
949 
950 /**
951   @brief Get the Ceed associated with a CeedVector
952 
953   @param vec        CeedVector to retrieve state
954   @param[out] ceed  Variable to store ceed
955 
956   @return An error code: 0 - success, otherwise - failure
957 
958   @ref Advanced
959 **/
960 int CeedVectorGetCeed(CeedVector vec, Ceed *ceed) {
961   *ceed = vec->ceed;
962   return CEED_ERROR_SUCCESS;
963 }
964 
965 /**
966   @brief Get the length of a CeedVector
967 
968   @param vec          CeedVector to retrieve length
969   @param[out] length  Variable to store length
970 
971   @return An error code: 0 - success, otherwise - failure
972 
973   @ref User
974 **/
975 int CeedVectorGetLength(CeedVector vec, CeedInt *length) {
976   *length = vec->length;
977   return CEED_ERROR_SUCCESS;
978 }
979 
980 /**
981   @brief Destroy a CeedVector
982 
983   @param vec  CeedVector to destroy
984 
985   @return An error code: 0 - success, otherwise - failure
986 
987   @ref User
988 **/
989 int CeedVectorDestroy(CeedVector *vec) {
990   int ierr;
991 
992   if (!*vec || --(*vec)->ref_count > 0) return CEED_ERROR_SUCCESS;
993 
994   if (((*vec)->state % 2) == 1)
995     return CeedError((*vec)->ceed, CEED_ERROR_ACCESS,
996                      "Cannot destroy CeedVector, the writable access "
997                      "lock is in use");
998 
999   if ((*vec)->num_readers > 0)
1000     // LCOV_EXCL_START
1001     return CeedError((*vec)->ceed, CEED_ERROR_ACCESS,
1002                      "Cannot destroy CeedVector, a process has "
1003                      "read access");
1004   // LCOV_EXCL_STOP
1005 
1006   if ((*vec)->Destroy) {
1007     ierr = (*vec)->Destroy(*vec); CeedChk(ierr);
1008   }
1009 
1010   ierr = CeedDestroy(&(*vec)->ceed); CeedChk(ierr);
1011   ierr = CeedFree(vec); CeedChk(ierr);
1012   return CEED_ERROR_SUCCESS;
1013 }
1014 
1015 /// @}
1016