xref: /libCEED/interface/ceed-vector.c (revision 3d8e882215d238700cdceb37404f76ca7fa24eaa)
1*3d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
2*3d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
30436c2adSjeremylt //
4*3d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
50436c2adSjeremylt //
6*3d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
70436c2adSjeremylt 
8ec3da8bcSJed Brown #include <ceed/ceed.h>
9ec3da8bcSJed Brown #include <ceed/backend.h>
103d576824SJeremy L Thompson #include <ceed-impl.h>
1173380422SJeremy L Thompson #include <assert.h>
12547d9b97Sjeremylt #include <math.h>
133d576824SJeremy L Thompson #include <stdint.h>
143d576824SJeremy L Thompson #include <stdio.h>
150436c2adSjeremylt 
167a982d89SJeremy L. Thompson /// @file
177a982d89SJeremy L. Thompson /// Implementation of public CeedVector interfaces
187a982d89SJeremy L. Thompson 
190436c2adSjeremylt /// @cond DOXYGEN_SKIP
200436c2adSjeremylt static struct CeedVector_private ceed_vector_active;
210436c2adSjeremylt static struct CeedVector_private ceed_vector_none;
220436c2adSjeremylt /// @endcond
230436c2adSjeremylt 
247a982d89SJeremy L. Thompson /// @addtogroup CeedVectorUser
257a982d89SJeremy L. Thompson /// @{
267a982d89SJeremy L. Thompson 
277a982d89SJeremy L. Thompson /// Indicate that vector will be provided as an explicit argument to
287a982d89SJeremy L. Thompson ///   CeedOperatorApply().
297a982d89SJeremy L. Thompson const CeedVector CEED_VECTOR_ACTIVE = &ceed_vector_active;
307a982d89SJeremy L. Thompson 
3196b902e2Sjeremylt /// Indicate that no vector is applicable (i.e., for @ref CEED_EVAL_WEIGHT).
327a982d89SJeremy L. Thompson const CeedVector CEED_VECTOR_NONE = &ceed_vector_none;
337a982d89SJeremy L. Thompson 
347a982d89SJeremy L. Thompson /// @}
357a982d89SJeremy L. Thompson 
367a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
377a982d89SJeremy L. Thompson /// CeedVector Backend API
387a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
397a982d89SJeremy L. Thompson /// @addtogroup CeedVectorBackend
407a982d89SJeremy L. Thompson /// @{
417a982d89SJeremy L. Thompson 
427a982d89SJeremy L. Thompson /**
439c774eddSJeremy L Thompson   @brief Check for valid data in a CeedVector
449c774eddSJeremy L Thompson 
459c774eddSJeremy L Thompson   @param vec                   CeedVector to check validity
469c774eddSJeremy L Thompson   @param[out] has_valid_array  Variable to store validity
479c774eddSJeremy L Thompson 
489c774eddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
499c774eddSJeremy L Thompson 
509c774eddSJeremy L Thompson   @ref Backend
519c774eddSJeremy L Thompson **/
529c774eddSJeremy L Thompson int CeedVectorHasValidArray(CeedVector vec, bool *has_valid_array) {
539c774eddSJeremy L Thompson   int ierr;
549c774eddSJeremy L Thompson 
559c774eddSJeremy L Thompson   if (!vec->HasValidArray)
569c774eddSJeremy L Thompson     // LCOV_EXCL_START
579c774eddSJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
589c774eddSJeremy L Thompson                      "Backend does not support HasValidArray");
599c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
609c774eddSJeremy L Thompson 
619c774eddSJeremy L Thompson   ierr = vec->HasValidArray(vec, has_valid_array); CeedChk(ierr);
629c774eddSJeremy L Thompson 
639c774eddSJeremy L Thompson   return CEED_ERROR_SUCCESS;
649c774eddSJeremy L Thompson }
659c774eddSJeremy L Thompson 
669c774eddSJeremy L Thompson /**
679c774eddSJeremy L Thompson   @brief Check for borrowed array of a specific CeedMemType in a CeedVector
689c774eddSJeremy L Thompson 
699c774eddSJeremy L Thompson   @param vec                              CeedVector to check
709c774eddSJeremy L Thompson   @param mem_type                         Memory type to check
719c774eddSJeremy L Thompson   @param[out] has_borrowed_array_of_type  Variable to store result
729c774eddSJeremy L Thompson 
739c774eddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
749c774eddSJeremy L Thompson 
759c774eddSJeremy L Thompson   @ref Backend
769c774eddSJeremy L Thompson **/
779c774eddSJeremy L Thompson int CeedVectorHasBorrowedArrayOfType(CeedVector vec, CeedMemType mem_type,
789c774eddSJeremy L Thompson                                      bool *has_borrowed_array_of_type) {
799c774eddSJeremy L Thompson   int ierr;
809c774eddSJeremy L Thompson 
819c774eddSJeremy L Thompson   if (!vec->HasBorrowedArrayOfType)
829c774eddSJeremy L Thompson     // LCOV_EXCL_START
839c774eddSJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
849c774eddSJeremy L Thompson                      "Backend does not support HasBorrowedArrayOfType");
859c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
869c774eddSJeremy L Thompson 
879c774eddSJeremy L Thompson   ierr = vec->HasBorrowedArrayOfType(vec, mem_type, has_borrowed_array_of_type);
889c774eddSJeremy L Thompson   CeedChk(ierr);
899c774eddSJeremy L Thompson 
909c774eddSJeremy L Thompson   return CEED_ERROR_SUCCESS;
919c774eddSJeremy L Thompson }
929c774eddSJeremy L Thompson 
939c774eddSJeremy L Thompson /**
947a982d89SJeremy L. Thompson   @brief Get the state of a CeedVector
957a982d89SJeremy L. Thompson 
967a982d89SJeremy L. Thompson   @param vec         CeedVector to retrieve state
977a982d89SJeremy L. Thompson   @param[out] state  Variable to store state
987a982d89SJeremy L. Thompson 
997a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1007a982d89SJeremy L. Thompson 
1017a982d89SJeremy L. Thompson   @ref Backend
1027a982d89SJeremy L. Thompson **/
1037a982d89SJeremy L. Thompson int CeedVectorGetState(CeedVector vec, uint64_t *state) {
1047a982d89SJeremy L. Thompson   *state = vec->state;
105e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1067a982d89SJeremy L. Thompson }
1077a982d89SJeremy L. Thompson 
1087a982d89SJeremy L. Thompson /**
10927312b0fSJed Brown   @brief Add a reference to a CeedVector
1107a982d89SJeremy L. Thompson 
1115f67fadeSJeremy L Thompson   @param[out] vec  CeedVector to increment reference counter
1127a982d89SJeremy L. Thompson 
1137a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1147a982d89SJeremy L. Thompson 
1157a982d89SJeremy L. Thompson   @ref Backend
1167a982d89SJeremy L. Thompson **/
1177a982d89SJeremy L. Thompson int CeedVectorAddReference(CeedVector vec) {
118d1d35e2fSjeremylt   vec->ref_count++;
119e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1207a982d89SJeremy L. Thompson }
1217a982d89SJeremy L. Thompson 
1227a982d89SJeremy L. Thompson /**
1237a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedVector
1247a982d89SJeremy L. Thompson 
1257a982d89SJeremy L. Thompson   @param vec        CeedVector to retrieve state
1267a982d89SJeremy L. Thompson   @param[out] data  Variable to store data
1277a982d89SJeremy L. Thompson 
1287a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1297a982d89SJeremy L. Thompson 
1307a982d89SJeremy L. Thompson   @ref Backend
1317a982d89SJeremy L. Thompson **/
132777ff853SJeremy L Thompson int CeedVectorGetData(CeedVector vec, void *data) {
133777ff853SJeremy L Thompson   *(void **)data = vec->data;
134e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1357a982d89SJeremy L. Thompson }
1367a982d89SJeremy L. Thompson 
1377a982d89SJeremy L. Thompson /**
1387a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedVector
1397a982d89SJeremy L. Thompson 
1407a982d89SJeremy L. Thompson   @param[out] vec  CeedVector to retrieve state
1417a982d89SJeremy L. Thompson   @param data      Data to set
1427a982d89SJeremy L. Thompson 
1437a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1447a982d89SJeremy L. Thompson 
1457a982d89SJeremy L. Thompson   @ref Backend
1467a982d89SJeremy L. Thompson **/
147777ff853SJeremy L Thompson int CeedVectorSetData(CeedVector vec, void *data) {
148777ff853SJeremy L Thompson   vec->data = data;
149e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1507a982d89SJeremy L. Thompson }
1517a982d89SJeremy L. Thompson 
15234359f16Sjeremylt /**
15334359f16Sjeremylt   @brief Increment the reference counter for a CeedVector
15434359f16Sjeremylt 
15534359f16Sjeremylt   @param vec  CeedVector to increment the reference counter
15634359f16Sjeremylt 
15734359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
15834359f16Sjeremylt 
15934359f16Sjeremylt   @ref Backend
16034359f16Sjeremylt **/
1619560d06aSjeremylt int CeedVectorReference(CeedVector vec) {
16234359f16Sjeremylt   vec->ref_count++;
16334359f16Sjeremylt   return CEED_ERROR_SUCCESS;
16434359f16Sjeremylt }
16534359f16Sjeremylt 
1667a982d89SJeremy L. Thompson /// @}
1677a982d89SJeremy L. Thompson 
1687a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1697a982d89SJeremy L. Thompson /// CeedVector Public API
1707a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1717a982d89SJeremy L. Thompson /// @addtogroup CeedVectorUser
1720436c2adSjeremylt /// @{
1730436c2adSjeremylt 
1740436c2adSjeremylt /**
1750436c2adSjeremylt   @brief Create a CeedVector of the specified length (does not allocate memory)
1760436c2adSjeremylt 
1770436c2adSjeremylt   @param ceed      Ceed object where the CeedVector will be created
1780436c2adSjeremylt   @param length    Length of vector
1790436c2adSjeremylt   @param[out] vec  Address of the variable where the newly created
1800436c2adSjeremylt                      CeedVector will be stored
1810436c2adSjeremylt 
1820436c2adSjeremylt   @return An error code: 0 - success, otherwise - failure
1830436c2adSjeremylt 
1847a982d89SJeremy L. Thompson   @ref User
1850436c2adSjeremylt **/
1861f9221feSJeremy L Thompson int CeedVectorCreate(Ceed ceed, CeedSize length, CeedVector *vec) {
1870436c2adSjeremylt   int ierr;
1880436c2adSjeremylt 
1890436c2adSjeremylt   if (!ceed->VectorCreate) {
1900436c2adSjeremylt     Ceed delegate;
1910436c2adSjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Vector"); CeedChk(ierr);
1920436c2adSjeremylt 
1930436c2adSjeremylt     if (!delegate)
1940436c2adSjeremylt       // LCOV_EXCL_START
195e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
196e15f9bd0SJeremy L Thompson                        "Backend does not support VectorCreate");
1970436c2adSjeremylt     // LCOV_EXCL_STOP
1980436c2adSjeremylt 
1990436c2adSjeremylt     ierr = CeedVectorCreate(delegate, length, vec); CeedChk(ierr);
200e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
2010436c2adSjeremylt   }
2020436c2adSjeremylt 
2030436c2adSjeremylt   ierr = CeedCalloc(1, vec); CeedChk(ierr);
2040436c2adSjeremylt   (*vec)->ceed = ceed;
2059560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
206d1d35e2fSjeremylt   (*vec)->ref_count = 1;
2070436c2adSjeremylt   (*vec)->length = length;
2080436c2adSjeremylt   (*vec)->state = 0;
2090436c2adSjeremylt   ierr = ceed->VectorCreate(length, *vec); CeedChk(ierr);
210e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2110436c2adSjeremylt }
2120436c2adSjeremylt 
2130436c2adSjeremylt /**
2149560d06aSjeremylt   @brief Copy the pointer to a CeedVector. Both pointers should
2159560d06aSjeremylt            be destroyed with `CeedVectorDestroy()`;
2169560d06aSjeremylt            Note: If `*vec_copy` is non-NULL, then it is assumed that
2179560d06aSjeremylt            `*vec_copy` is a pointer to a CeedVector. This
2189560d06aSjeremylt            CeedVector will be destroyed if `*vec_copy` is the only
2199560d06aSjeremylt            reference to this CeedVector.
2209560d06aSjeremylt 
2219560d06aSjeremylt   @param vec            CeedVector to copy reference to
2229560d06aSjeremylt   @param[out] vec_copy  Variable to store copied reference
2239560d06aSjeremylt 
2249560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
2259560d06aSjeremylt 
2269560d06aSjeremylt   @ref User
2279560d06aSjeremylt **/
2289560d06aSjeremylt int CeedVectorReferenceCopy(CeedVector vec, CeedVector *vec_copy) {
2299560d06aSjeremylt   int ierr;
2309560d06aSjeremylt 
2319560d06aSjeremylt   ierr = CeedVectorReference(vec); CeedChk(ierr);
2329560d06aSjeremylt   ierr = CeedVectorDestroy(vec_copy); CeedChk(ierr);
2339560d06aSjeremylt   *vec_copy = vec;
2349560d06aSjeremylt   return CEED_ERROR_SUCCESS;
2359560d06aSjeremylt }
2369560d06aSjeremylt 
2379560d06aSjeremylt /**
2380436c2adSjeremylt   @brief Set the array used by a CeedVector, freeing any previously allocated
239b3cf021fSjeremylt            array if applicable. The backend may copy values to a different
240b3cf021fSjeremylt            memtype, such as during @ref CeedOperatorApply().
2416a6c615bSJeremy L Thompson            See also @ref CeedVectorSyncArray() and @ref CeedVectorTakeArray().
2420436c2adSjeremylt 
2430436c2adSjeremylt   @param vec        CeedVector
244d1d35e2fSjeremylt   @param mem_type   Memory type of the array being passed
245d1d35e2fSjeremylt   @param copy_mode  Copy mode for the array
2464cc79fe7SJed Brown   @param array      Array to be used, or NULL with @ref CEED_COPY_VALUES to have the
2470436c2adSjeremylt                       library allocate
2480436c2adSjeremylt 
2490436c2adSjeremylt   @return An error code: 0 - success, otherwise - failure
2500436c2adSjeremylt 
2517a982d89SJeremy L. Thompson   @ref User
2520436c2adSjeremylt **/
253d1d35e2fSjeremylt int CeedVectorSetArray(CeedVector vec, CeedMemType mem_type,
254d1d35e2fSjeremylt                        CeedCopyMode copy_mode,
2550436c2adSjeremylt                        CeedScalar *array) {
2560436c2adSjeremylt   int ierr;
2570436c2adSjeremylt 
2580436c2adSjeremylt   if (!vec->SetArray)
2590436c2adSjeremylt     // LCOV_EXCL_START
260e15f9bd0SJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
261e15f9bd0SJeremy L Thompson                      "Backend does not support VectorSetArray");
2620436c2adSjeremylt   // LCOV_EXCL_STOP
2630436c2adSjeremylt 
2640436c2adSjeremylt   if (vec->state % 2 == 1)
265e15f9bd0SJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
266e15f9bd0SJeremy L Thompson                      "Cannot grant CeedVector array access, the "
2670436c2adSjeremylt                      "access lock is already in use");
2680436c2adSjeremylt 
269d1d35e2fSjeremylt   if (vec->num_readers > 0)
270e15f9bd0SJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
271e15f9bd0SJeremy L Thompson                      "Cannot grant CeedVector array access, a "
2720436c2adSjeremylt                      "process has read access");
2730436c2adSjeremylt 
274d1d35e2fSjeremylt   ierr = vec->SetArray(vec, mem_type, copy_mode, array); CeedChk(ierr);
2750436c2adSjeremylt   vec->state += 2;
276e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2770436c2adSjeremylt }
2780436c2adSjeremylt 
2790436c2adSjeremylt /**
2800436c2adSjeremylt   @brief Set the CeedVector to a constant value
2810436c2adSjeremylt 
2820436c2adSjeremylt   @param vec        CeedVector
2830436c2adSjeremylt   @param[in] value  Value to be used
2840436c2adSjeremylt 
2850436c2adSjeremylt   @return An error code: 0 - success, otherwise - failure
2860436c2adSjeremylt 
2877a982d89SJeremy L. Thompson   @ref User
2880436c2adSjeremylt **/
2890436c2adSjeremylt int CeedVectorSetValue(CeedVector vec, CeedScalar value) {
2900436c2adSjeremylt   int ierr;
2910436c2adSjeremylt 
2920436c2adSjeremylt   if (vec->state % 2 == 1)
2939c774eddSJeremy L Thompson     // LCOV_EXCL_START
294e15f9bd0SJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
295e15f9bd0SJeremy L Thompson                      "Cannot grant CeedVector array access, the "
2960436c2adSjeremylt                      "access lock is already in use");
2979c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
2989c774eddSJeremy L Thompson 
2999c774eddSJeremy L Thompson   if (vec->num_readers > 0)
3009c774eddSJeremy L Thompson     // LCOV_EXCL_START
3019c774eddSJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
3029c774eddSJeremy L Thompson                      "Cannot grant CeedVector array access, a "
3039c774eddSJeremy L Thompson                      "process has read access");
3049c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
3050436c2adSjeremylt 
3060436c2adSjeremylt   if (vec->SetValue) {
3070436c2adSjeremylt     ierr = vec->SetValue(vec, value); CeedChk(ierr);
3080436c2adSjeremylt   } else {
3090436c2adSjeremylt     CeedScalar *array;
3109c774eddSJeremy L Thompson     ierr = CeedVectorGetArrayWrite(vec, CEED_MEM_HOST, &array); CeedChk(ierr);
3110436c2adSjeremylt     for (int i=0; i<vec->length; i++) array[i] = value;
3120436c2adSjeremylt     ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr);
3130436c2adSjeremylt   }
3140436c2adSjeremylt   vec->state += 2;
315e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3160436c2adSjeremylt }
3170436c2adSjeremylt 
3180436c2adSjeremylt /**
319b3cf021fSjeremylt   @brief Sync the CeedVector to a specified memtype. This function is used to
320b3cf021fSjeremylt            force synchronization of arrays set with @ref CeedVectorSetArray().
321b3cf021fSjeremylt            If the requested memtype is already synchronized, this function
322b3cf021fSjeremylt            results in a no-op.
3230436c2adSjeremylt 
3240436c2adSjeremylt   @param vec       CeedVector
325d1d35e2fSjeremylt   @param mem_type  Memtype to be synced
3260436c2adSjeremylt 
3270436c2adSjeremylt   @return An error code: 0 - success, otherwise - failure
3280436c2adSjeremylt 
3297a982d89SJeremy L. Thompson   @ref User
3300436c2adSjeremylt **/
331d1d35e2fSjeremylt int CeedVectorSyncArray(CeedVector vec, CeedMemType mem_type) {
3320436c2adSjeremylt   int ierr;
3330436c2adSjeremylt 
3340436c2adSjeremylt   if (vec->state % 2 == 1)
335e15f9bd0SJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
336e15f9bd0SJeremy L Thompson                      "Cannot sync CeedVector, the access lock is "
3370436c2adSjeremylt                      "already in use");
3380436c2adSjeremylt 
3390436c2adSjeremylt   if (vec->SyncArray) {
340d1d35e2fSjeremylt     ierr = vec->SyncArray(vec, mem_type); CeedChk(ierr);
3410436c2adSjeremylt   } else {
3420436c2adSjeremylt     const CeedScalar *array;
343d1d35e2fSjeremylt     ierr = CeedVectorGetArrayRead(vec, mem_type, &array); CeedChk(ierr);
3440436c2adSjeremylt     ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr);
3450436c2adSjeremylt   }
346e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3470436c2adSjeremylt }
3480436c2adSjeremylt 
3490436c2adSjeremylt /**
3509c774eddSJeremy L Thompson   @brief Take ownership of the CeedVector array set by @ref CeedVectorSetArray()
3519c774eddSJeremy L Thompson            with @ref CEED_USE_POINTER and remove the array from the CeedVector.
3529c774eddSJeremy L Thompson            The caller is responsible for managing and freeing the array.
3539c774eddSJeremy L Thompson            This function will error if @ref CeedVectorSetArray() was not previously
3549c774eddSJeremy L Thompson            called with @ref CEED_USE_POINTER for the corresponding mem_type.
3556a6c615bSJeremy L Thompson 
3566a6c615bSJeremy L Thompson   @param vec         CeedVector
357d1d35e2fSjeremylt   @param mem_type    Memory type on which to take the array. If the backend
3586a6c615bSJeremy L Thompson                        uses a different memory type, this will perform a copy.
359d1d35e2fSjeremylt   @param[out] array  Array on memory type mem_type, or NULL if array pointer is
3606a6c615bSJeremy L Thompson                        not required
3616a6c615bSJeremy L Thompson 
3626a6c615bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
3636a6c615bSJeremy L Thompson 
3646a6c615bSJeremy L Thompson   @ref User
3656a6c615bSJeremy L Thompson **/
366d1d35e2fSjeremylt int CeedVectorTakeArray(CeedVector vec, CeedMemType mem_type,
367d1d35e2fSjeremylt                         CeedScalar **array) {
3686a6c615bSJeremy L Thompson   int ierr;
3696a6c615bSJeremy L Thompson 
3706a6c615bSJeremy L Thompson   if (vec->state % 2 == 1)
3716a6c615bSJeremy L Thompson     // LCOV_EXCL_START
372e15f9bd0SJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
373e15f9bd0SJeremy L Thompson                      "Cannot take CeedVector array, the access "
3746a6c615bSJeremy L Thompson                      "lock is already in use");
3756a6c615bSJeremy L Thompson   // LCOV_EXCL_STOP
376d1d35e2fSjeremylt   if (vec->num_readers > 0)
3776a6c615bSJeremy L Thompson     // LCOV_EXCL_START
378e15f9bd0SJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
379e15f9bd0SJeremy L Thompson                      "Cannot take CeedVector array, a process "
3806a6c615bSJeremy L Thompson                      "has read access");
3816a6c615bSJeremy L Thompson   // LCOV_EXCL_STOP
38250c643e1SJed Brown   CeedScalar *temp_array = NULL;
38350c643e1SJed Brown   if (vec->length > 0) {
3849c774eddSJeremy L Thompson     bool has_borrowed_array_of_type = true;
3859c774eddSJeremy L Thompson     ierr = CeedVectorHasBorrowedArrayOfType(vec, mem_type,
3869c774eddSJeremy L Thompson                                             &has_borrowed_array_of_type);
3879c774eddSJeremy L Thompson     CeedChk(ierr);
3889c774eddSJeremy L Thompson     if (!has_borrowed_array_of_type)
3899c774eddSJeremy L Thompson       // LCOV_EXCL_START
3909c774eddSJeremy L Thompson       return CeedError(vec->ceed, CEED_ERROR_BACKEND,
3919c774eddSJeremy L Thompson                        "CeedVector has no borrowed %s array, "
3929c774eddSJeremy L Thompson                        "must set array with CeedVectorSetArray", CeedMemTypes[mem_type]);
3939c774eddSJeremy L Thompson     // LCOV_EXCL_STOP
3949c774eddSJeremy L Thompson 
3959c774eddSJeremy L Thompson     bool has_valid_array = true;
3969c774eddSJeremy L Thompson     ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
3979c774eddSJeremy L Thompson     if (!has_valid_array)
3989c774eddSJeremy L Thompson       // LCOV_EXCL_START
3999c774eddSJeremy L Thompson       return CeedError(vec->ceed, CEED_ERROR_BACKEND,
4009c774eddSJeremy L Thompson                        "CeedVector has no valid data to take, "
4019c774eddSJeremy L Thompson                        "must set data with CeedVectorSetValue or CeedVectorSetArray");
4029c774eddSJeremy L Thompson     // LCOV_EXCL_STOP
4039c774eddSJeremy L Thompson 
404d1d35e2fSjeremylt     ierr = vec->TakeArray(vec, mem_type, &temp_array); CeedChk(ierr);
40550c643e1SJed Brown   }
406d1d35e2fSjeremylt   if (array) (*array) = temp_array;
407e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4086a6c615bSJeremy L Thompson }
4096a6c615bSJeremy L Thompson 
4106a6c615bSJeremy L Thompson /**
411b3cf021fSjeremylt   @brief Get read/write access to a CeedVector via the specified memory type.
412b3cf021fSjeremylt            Restore access with @ref CeedVectorRestoreArray().
4130436c2adSjeremylt 
4140436c2adSjeremylt   @param vec         CeedVector to access
415d1d35e2fSjeremylt   @param mem_type    Memory type on which to access the array. If the backend
416b3cf021fSjeremylt                        uses a different memory type, this will perform a copy.
417d1d35e2fSjeremylt   @param[out] array  Array on memory type mem_type
4180436c2adSjeremylt 
4190436c2adSjeremylt   @note The CeedVectorGetArray* and CeedVectorRestoreArray* functions provide
4200436c2adSjeremylt     access to array pointers in the desired memory space. Pairing get/restore
4210436c2adSjeremylt     allows the Vector to track access, thus knowing if norms or other
4220436c2adSjeremylt     operations may need to be recomputed.
4230436c2adSjeremylt 
4240436c2adSjeremylt   @return An error code: 0 - success, otherwise - failure
4250436c2adSjeremylt 
4267a982d89SJeremy L. Thompson   @ref User
4270436c2adSjeremylt **/
428d1d35e2fSjeremylt int CeedVectorGetArray(CeedVector vec, CeedMemType mem_type,
429d1d35e2fSjeremylt                        CeedScalar **array) {
4300436c2adSjeremylt   int ierr;
4310436c2adSjeremylt 
4320436c2adSjeremylt   if (!vec->GetArray)
4330436c2adSjeremylt     // LCOV_EXCL_START
434e15f9bd0SJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
435e15f9bd0SJeremy L Thompson                      "Backend does not support GetArray");
4360436c2adSjeremylt   // LCOV_EXCL_STOP
4370436c2adSjeremylt 
4380436c2adSjeremylt   if (vec->state % 2 == 1)
439e15f9bd0SJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
440e15f9bd0SJeremy L Thompson                      "Cannot grant CeedVector array access, the "
4410436c2adSjeremylt                      "access lock is already in use");
4420436c2adSjeremylt 
443d1d35e2fSjeremylt   if (vec->num_readers > 0)
444e15f9bd0SJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
445e15f9bd0SJeremy L Thompson                      "Cannot grant CeedVector array access, a "
4460436c2adSjeremylt                      "process has read access");
4470436c2adSjeremylt 
4489c774eddSJeremy L Thompson   bool has_valid_array = true;
4499c774eddSJeremy L Thompson   ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
4509c774eddSJeremy L Thompson   if (!has_valid_array)
4519c774eddSJeremy L Thompson     // LCOV_EXCL_START
4529c774eddSJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
4539c774eddSJeremy L Thompson                      "CeedVector has no valid data to read, "
4549c774eddSJeremy L Thompson                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
4559c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
4569c774eddSJeremy L Thompson 
457d1d35e2fSjeremylt   ierr = vec->GetArray(vec, mem_type, array); CeedChk(ierr);
45828bfd0b7SJeremy L Thompson   vec->state++;
459e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4600436c2adSjeremylt }
4610436c2adSjeremylt 
4620436c2adSjeremylt /**
463b3cf021fSjeremylt   @brief Get read-only access to a CeedVector via the specified memory type.
464b3cf021fSjeremylt            Restore access with @ref CeedVectorRestoreArrayRead().
4650436c2adSjeremylt 
4660436c2adSjeremylt   @param vec         CeedVector to access
467d1d35e2fSjeremylt   @param mem_type    Memory type on which to access the array.  If the backend
4680436c2adSjeremylt                        uses a different memory type, this will perform a copy
4690436c2adSjeremylt                        (possibly cached).
470d1d35e2fSjeremylt   @param[out] array  Array on memory type mem_type
4710436c2adSjeremylt 
4720436c2adSjeremylt   @return An error code: 0 - success, otherwise - failure
4730436c2adSjeremylt 
4747a982d89SJeremy L. Thompson   @ref User
4750436c2adSjeremylt **/
476d1d35e2fSjeremylt int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mem_type,
4770436c2adSjeremylt                            const CeedScalar **array) {
4780436c2adSjeremylt   int ierr;
4790436c2adSjeremylt 
4800436c2adSjeremylt   if (!vec->GetArrayRead)
4810436c2adSjeremylt     // LCOV_EXCL_START
482e15f9bd0SJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
483e15f9bd0SJeremy L Thompson                      "Backend does not support GetArrayRead");
4840436c2adSjeremylt   // LCOV_EXCL_STOP
4850436c2adSjeremylt 
4860436c2adSjeremylt   if (vec->state % 2 == 1)
487e15f9bd0SJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
488e15f9bd0SJeremy L Thompson                      "Cannot grant CeedVector read-only array "
4890436c2adSjeremylt                      "access, the access lock is already in use");
4900436c2adSjeremylt 
49150c643e1SJed Brown   if (vec->length > 0) {
4929c774eddSJeremy L Thompson     bool has_valid_array = true;
4939c774eddSJeremy L Thompson     ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
4949c774eddSJeremy L Thompson     if (!has_valid_array)
4959c774eddSJeremy L Thompson       // LCOV_EXCL_START
4969c774eddSJeremy L Thompson       return CeedError(vec->ceed, CEED_ERROR_BACKEND,
4979c774eddSJeremy L Thompson                        "CeedVector has no valid data to read, "
4989c774eddSJeremy L Thompson                        "must set data with CeedVectorSetValue or CeedVectorSetArray");
4999c774eddSJeremy L Thompson     // LCOV_EXCL_STOP
5009c774eddSJeremy L Thompson 
501d1d35e2fSjeremylt     ierr = vec->GetArrayRead(vec, mem_type, array); CeedChk(ierr);
50250c643e1SJed Brown   } else {
50350c643e1SJed Brown     *array = NULL;
50450c643e1SJed Brown   }
505d1d35e2fSjeremylt   vec->num_readers++;
506e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5070436c2adSjeremylt }
5080436c2adSjeremylt 
5090436c2adSjeremylt /**
5109c774eddSJeremy L Thompson   @brief Get write access to a CeedVector via the specified memory type.
5119c774eddSJeremy L Thompson            Restore access with @ref CeedVectorRestoreArray(). All old
5129c774eddSJeremy L Thompson            values should be assumed to be invalid.
5139c774eddSJeremy L Thompson 
5149c774eddSJeremy L Thompson   @param vec         CeedVector to access
5159c774eddSJeremy L Thompson   @param mem_type    Memory type on which to access the array.
5169c774eddSJeremy L Thompson   @param[out] array  Array on memory type mem_type
5179c774eddSJeremy L Thompson 
5189c774eddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
5199c774eddSJeremy L Thompson 
5209c774eddSJeremy L Thompson   @ref User
5219c774eddSJeremy L Thompson **/
5229c774eddSJeremy L Thompson int CeedVectorGetArrayWrite(CeedVector vec, CeedMemType mem_type,
5239c774eddSJeremy L Thompson                             CeedScalar **array) {
5249c774eddSJeremy L Thompson   int ierr;
5259c774eddSJeremy L Thompson 
5269c774eddSJeremy L Thompson   if (!vec->GetArrayWrite)
5279c774eddSJeremy L Thompson     // LCOV_EXCL_START
5289c774eddSJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
5299c774eddSJeremy L Thompson                      "Backend does not support GetArrayWrite");
5309c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
5319c774eddSJeremy L Thompson 
5329c774eddSJeremy L Thompson   if (vec->state % 2 == 1)
5339c774eddSJeremy L Thompson     // LCOV_EXCL_START
5349c774eddSJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
5359c774eddSJeremy L Thompson                      "Cannot grant CeedVector array access, the "
5369c774eddSJeremy L Thompson                      "access lock is already in use");
5379c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
5389c774eddSJeremy L Thompson 
5399c774eddSJeremy L Thompson   if (vec->num_readers > 0)
5409c774eddSJeremy L Thompson     // LCOV_EXCL_START
5419c774eddSJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
5429c774eddSJeremy L Thompson                      "Cannot grant CeedVector array access, a "
5439c774eddSJeremy L Thompson                      "process has read access");
5449c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
5459c774eddSJeremy L Thompson 
5469c774eddSJeremy L Thompson   ierr = vec->GetArrayWrite(vec, mem_type, array); CeedChk(ierr);
54728bfd0b7SJeremy L Thompson   vec->state++;
5489c774eddSJeremy L Thompson   return CEED_ERROR_SUCCESS;
5499c774eddSJeremy L Thompson }
5509c774eddSJeremy L Thompson 
5519c774eddSJeremy L Thompson /**
552b3cf021fSjeremylt   @brief Restore an array obtained using @ref CeedVectorGetArray()
5530436c2adSjeremylt 
5540436c2adSjeremylt   @param vec    CeedVector to restore
5550436c2adSjeremylt   @param array  Array of vector data
5560436c2adSjeremylt 
5570436c2adSjeremylt   @return An error code: 0 - success, otherwise - failure
5580436c2adSjeremylt 
5597a982d89SJeremy L. Thompson   @ref User
5600436c2adSjeremylt **/
5610436c2adSjeremylt int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) {
5620436c2adSjeremylt   int ierr;
5630436c2adSjeremylt 
5640436c2adSjeremylt   if (vec->state % 2 != 1)
565e15f9bd0SJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
566e15f9bd0SJeremy L Thompson                      "Cannot restore CeedVector array access, "
5670436c2adSjeremylt                      "access was not granted");
568706efda3SJeremy L Thompson   if (vec->RestoreArray) {
5690436c2adSjeremylt     ierr = vec->RestoreArray(vec); CeedChk(ierr);
570706efda3SJeremy L Thompson   }
5710436c2adSjeremylt   *array = NULL;
57228bfd0b7SJeremy L Thompson   vec->state++;
573e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5740436c2adSjeremylt }
5750436c2adSjeremylt 
5760436c2adSjeremylt /**
577b3cf021fSjeremylt   @brief Restore an array obtained using @ref CeedVectorGetArrayRead()
5780436c2adSjeremylt 
5790436c2adSjeremylt   @param vec    CeedVector to restore
5800436c2adSjeremylt   @param array  Array of vector data
5810436c2adSjeremylt 
5820436c2adSjeremylt   @return An error code: 0 - success, otherwise - failure
5830436c2adSjeremylt 
5847a982d89SJeremy L. Thompson   @ref User
5850436c2adSjeremylt **/
5860436c2adSjeremylt int CeedVectorRestoreArrayRead(CeedVector vec, const CeedScalar **array) {
5870436c2adSjeremylt   int ierr;
5880436c2adSjeremylt 
5899c774eddSJeremy L Thompson   if (vec->num_readers == 0)
5909c774eddSJeremy L Thompson     // LCOV_EXCL_START
5919c774eddSJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
5929c774eddSJeremy L Thompson                      "Cannot restore CeedVector array read access, "
5939c774eddSJeremy L Thompson                      "access was not granted");
5949c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
5959c774eddSJeremy L Thompson 
596706efda3SJeremy L Thompson   if (vec->RestoreArrayRead) {
5970436c2adSjeremylt     ierr = vec->RestoreArrayRead(vec); CeedChk(ierr);
598706efda3SJeremy L Thompson   }
5990436c2adSjeremylt   *array = NULL;
600d1d35e2fSjeremylt   vec->num_readers--;
601e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6020436c2adSjeremylt }
6030436c2adSjeremylt 
6040436c2adSjeremylt /**
605171f8ca9Sjeremylt   @brief Get the norm of a CeedVector.
606171f8ca9Sjeremylt 
607171f8ca9Sjeremylt   Note: This operation is local to the CeedVector. This function will likely
608171f8ca9Sjeremylt           not provide the desired results for the norm of the libCEED portion
609171f8ca9Sjeremylt           of a parallel vector or a CeedVector with duplicated or hanging nodes.
610547d9b97Sjeremylt 
611547d9b97Sjeremylt   @param vec        CeedVector to retrieve maximum value
612d1d35e2fSjeremylt   @param norm_type  Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX
613547d9b97Sjeremylt   @param[out] norm  Variable to store norm value
614547d9b97Sjeremylt 
615547d9b97Sjeremylt   @return An error code: 0 - success, otherwise - failure
616547d9b97Sjeremylt 
6177a982d89SJeremy L. Thompson   @ref User
618547d9b97Sjeremylt **/
619d1d35e2fSjeremylt int CeedVectorNorm(CeedVector vec, CeedNormType norm_type, CeedScalar *norm) {
620547d9b97Sjeremylt   int ierr;
621547d9b97Sjeremylt 
6229c774eddSJeremy L Thompson   bool has_valid_array = true;
6239c774eddSJeremy L Thompson   ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
6249c774eddSJeremy L Thompson   if (!has_valid_array)
6259c774eddSJeremy L Thompson     // LCOV_EXCL_START
6269c774eddSJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
6279c774eddSJeremy L Thompson                      "CeedVector has no valid data to compute norm, "
6289c774eddSJeremy L Thompson                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
6299c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
6309c774eddSJeremy L Thompson 
631547d9b97Sjeremylt   // Backend impl for GPU, if added
632547d9b97Sjeremylt   if (vec->Norm) {
633d1d35e2fSjeremylt     ierr = vec->Norm(vec, norm_type, norm); CeedChk(ierr);
634e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
635547d9b97Sjeremylt   }
636547d9b97Sjeremylt 
637547d9b97Sjeremylt   const CeedScalar *array;
638547d9b97Sjeremylt   ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array); CeedChk(ierr);
639547d9b97Sjeremylt 
640547d9b97Sjeremylt   *norm = 0.;
641d1d35e2fSjeremylt   switch (norm_type) {
642547d9b97Sjeremylt   case CEED_NORM_1:
643547d9b97Sjeremylt     for (int i=0; i<vec->length; i++) {
644547d9b97Sjeremylt       *norm += fabs(array[i]);
645547d9b97Sjeremylt     }
646547d9b97Sjeremylt     break;
647547d9b97Sjeremylt   case CEED_NORM_2:
648547d9b97Sjeremylt     for (int i=0; i<vec->length; i++) {
649547d9b97Sjeremylt       *norm += fabs(array[i])*fabs(array[i]);
650547d9b97Sjeremylt     }
651547d9b97Sjeremylt     break;
652547d9b97Sjeremylt   case CEED_NORM_MAX:
653547d9b97Sjeremylt     for (int i=0; i<vec->length; i++) {
654d1d35e2fSjeremylt       const CeedScalar abs_v_i = fabs(array[i]);
655d1d35e2fSjeremylt       *norm = *norm > abs_v_i ? *norm : abs_v_i;
656547d9b97Sjeremylt     }
657547d9b97Sjeremylt   }
658d1d35e2fSjeremylt   if (norm_type == CEED_NORM_2)
659547d9b97Sjeremylt     *norm = sqrt(*norm);
660547d9b97Sjeremylt 
661547d9b97Sjeremylt   ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr);
662e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
663547d9b97Sjeremylt }
664547d9b97Sjeremylt 
665547d9b97Sjeremylt /**
666e0dd3b27Sjeremylt   @brief Compute x = alpha x
667e0dd3b27Sjeremylt 
66896b902e2Sjeremylt   @param[in,out] x  vector for scaling
66996b902e2Sjeremylt   @param[in] alpha  scaling factor
670e0dd3b27Sjeremylt 
671e0dd3b27Sjeremylt   @return An error code: 0 - success, otherwise - failure
672e0dd3b27Sjeremylt 
673e0dd3b27Sjeremylt   @ref User
674e0dd3b27Sjeremylt **/
675e0dd3b27Sjeremylt int CeedVectorScale(CeedVector x, CeedScalar alpha) {
676e0dd3b27Sjeremylt   int ierr;
67773380422SJeremy L Thompson   CeedScalar *x_array = NULL;
6781f9221feSJeremy L Thompson   CeedSize n_x;
679e0dd3b27Sjeremylt 
6809c774eddSJeremy L Thompson   bool has_valid_array = true;
6819c774eddSJeremy L Thompson   ierr = CeedVectorHasValidArray(x, &has_valid_array); CeedChk(ierr);
6829c774eddSJeremy L Thompson   if (!has_valid_array)
6839c774eddSJeremy L Thompson     // LCOV_EXCL_START
6849c774eddSJeremy L Thompson     return CeedError(x->ceed, CEED_ERROR_BACKEND,
6859c774eddSJeremy L Thompson                      "CeedVector has no valid data to scale, "
6869c774eddSJeremy L Thompson                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
6879c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
6889c774eddSJeremy L Thompson 
689e0dd3b27Sjeremylt   ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr);
690e0dd3b27Sjeremylt 
691e0dd3b27Sjeremylt   // Backend implementation
692e0dd3b27Sjeremylt   if (x->Scale)
693e0dd3b27Sjeremylt     return x->Scale(x, alpha);
694e0dd3b27Sjeremylt 
695e0dd3b27Sjeremylt   // Default implementation
6969c774eddSJeremy L Thompson   ierr = CeedVectorGetArrayWrite(x, CEED_MEM_HOST, &x_array); CeedChk(ierr);
697e0dd3b27Sjeremylt   for (CeedInt i=0; i<n_x; i++)
698e0dd3b27Sjeremylt     x_array[i] *= alpha;
699e0dd3b27Sjeremylt   ierr = CeedVectorRestoreArray(x, &x_array); CeedChk(ierr);
700e0dd3b27Sjeremylt 
701e0dd3b27Sjeremylt   return CEED_ERROR_SUCCESS;
702e0dd3b27Sjeremylt }
703e0dd3b27Sjeremylt 
704e0dd3b27Sjeremylt /**
7050f7fd0f8Sjeremylt   @brief Compute y = alpha x + y
7060f7fd0f8Sjeremylt 
70796b902e2Sjeremylt   @param[in,out] y  target vector for sum
70896b902e2Sjeremylt   @param[in] alpha  scaling factor
70996b902e2Sjeremylt   @param[in] x      second vector, must be different than y
7100f7fd0f8Sjeremylt 
7110f7fd0f8Sjeremylt   @return An error code: 0 - success, otherwise - failure
7120f7fd0f8Sjeremylt 
7130f7fd0f8Sjeremylt   @ref User
7140f7fd0f8Sjeremylt **/
7150f7fd0f8Sjeremylt int CeedVectorAXPY(CeedVector y, CeedScalar alpha, CeedVector x) {
7160f7fd0f8Sjeremylt   int ierr;
71773380422SJeremy L Thompson   CeedScalar *y_array = NULL;
71873380422SJeremy L Thompson   CeedScalar const *x_array = NULL;
7191f9221feSJeremy L Thompson   CeedSize n_x, n_y;
7200f7fd0f8Sjeremylt 
7210f7fd0f8Sjeremylt   ierr = CeedVectorGetLength(y, &n_y); CeedChk(ierr);
7220f7fd0f8Sjeremylt   ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr);
7230f7fd0f8Sjeremylt   if (n_x != n_y)
7240f7fd0f8Sjeremylt     // LCOV_EXCL_START
7250f7fd0f8Sjeremylt     return CeedError(y->ceed, CEED_ERROR_UNSUPPORTED,
7260f7fd0f8Sjeremylt                      "Cannot add vector of different lengths");
7270f7fd0f8Sjeremylt   // LCOV_EXCL_STOP
7280f7fd0f8Sjeremylt   if (x == y)
7290f7fd0f8Sjeremylt     // LCOV_EXCL_START
7300f7fd0f8Sjeremylt     return CeedError(y->ceed, CEED_ERROR_UNSUPPORTED,
7310f7fd0f8Sjeremylt                      "Cannot use same vector for x and y in CeedVectorAXPY");
7320f7fd0f8Sjeremylt   // LCOV_EXCL_STOP
7330f7fd0f8Sjeremylt 
7349c774eddSJeremy L Thompson   bool has_valid_array_x = true, has_valid_array_y = true;
7359c774eddSJeremy L Thompson   ierr = CeedVectorHasValidArray(x, &has_valid_array_x); CeedChk(ierr);
7369c774eddSJeremy L Thompson   if (!has_valid_array_x)
7379c774eddSJeremy L Thompson     // LCOV_EXCL_START
7389c774eddSJeremy L Thompson     return CeedError(x->ceed, CEED_ERROR_BACKEND,
7399c774eddSJeremy L Thompson                      "CeedVector x has no valid data, "
7409c774eddSJeremy L Thompson                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
7419c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
7429c774eddSJeremy L Thompson   ierr = CeedVectorHasValidArray(y, &has_valid_array_y); CeedChk(ierr);
7439c774eddSJeremy L Thompson   if (!has_valid_array_y)
7449c774eddSJeremy L Thompson     // LCOV_EXCL_START
7459c774eddSJeremy L Thompson     return CeedError(y->ceed, CEED_ERROR_BACKEND,
7469c774eddSJeremy L Thompson                      "CeedVector y has no valid data, "
7479c774eddSJeremy L Thompson                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
7489c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
7499c774eddSJeremy L Thompson 
7502d04630dSjeremylt   Ceed ceed_parent_x, ceed_parent_y;
7512d04630dSjeremylt   ierr = CeedGetParent(x->ceed, &ceed_parent_x); CeedChk(ierr);
7522d04630dSjeremylt   ierr = CeedGetParent(y->ceed, &ceed_parent_y); CeedChk(ierr);
7532d04630dSjeremylt   if (ceed_parent_x != ceed_parent_y)
7542d04630dSjeremylt     // LCOV_EXCL_START
7552d04630dSjeremylt     return CeedError(y->ceed, CEED_ERROR_INCOMPATIBLE,
7562d04630dSjeremylt                      "Vectors x and y must be created by the same Ceed context");
7572d04630dSjeremylt   // LCOV_EXCL_STOP
7582d04630dSjeremylt 
7590f7fd0f8Sjeremylt   // Backend implementation
760eaf62fffSJeremy L Thompson   if (y->AXPY) {
761eaf62fffSJeremy L Thompson     ierr = y->AXPY(y, alpha, x); CeedChk(ierr);
762eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
763eaf62fffSJeremy L Thompson   }
7640f7fd0f8Sjeremylt 
7650f7fd0f8Sjeremylt   // Default implementation
7669c774eddSJeremy L Thompson   ierr = CeedVectorGetArrayWrite(y, CEED_MEM_HOST, &y_array); CeedChk(ierr);
7670f7fd0f8Sjeremylt   ierr = CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array); CeedChk(ierr);
7680f7fd0f8Sjeremylt 
76973380422SJeremy L Thompson   assert(x_array); assert(y_array);
77073380422SJeremy L Thompson 
7710f7fd0f8Sjeremylt   for (CeedInt i=0; i<n_y; i++)
7720f7fd0f8Sjeremylt     y_array[i] += alpha * x_array[i];
7730f7fd0f8Sjeremylt 
7740f7fd0f8Sjeremylt   ierr = CeedVectorRestoreArray(y, &y_array); CeedChk(ierr);
7750f7fd0f8Sjeremylt   ierr = CeedVectorRestoreArrayRead(x, &x_array); CeedChk(ierr);
7760f7fd0f8Sjeremylt 
7770f7fd0f8Sjeremylt   return CEED_ERROR_SUCCESS;
7780f7fd0f8Sjeremylt }
7790f7fd0f8Sjeremylt 
7800f7fd0f8Sjeremylt /**
7810c1bc3c2Sjeremylt   @brief Compute the pointwise multiplication w = x .* y. Any
7820f7fd0f8Sjeremylt            subset of x, y, and w may be the same vector.
7830f7fd0f8Sjeremylt 
78496b902e2Sjeremylt   @param[out] w  target vector for the product
78596b902e2Sjeremylt   @param[in] x   first vector for product
78696b902e2Sjeremylt   @param[in] y   second vector for the product
7870f7fd0f8Sjeremylt 
7880f7fd0f8Sjeremylt   @return An error code: 0 - success, otherwise - failure
7890f7fd0f8Sjeremylt 
7900f7fd0f8Sjeremylt   @ ref User
7910f7fd0f8Sjeremylt **/
7920f7fd0f8Sjeremylt int CeedVectorPointwiseMult(CeedVector w, CeedVector x, CeedVector y) {
7930f7fd0f8Sjeremylt   int ierr;
79473380422SJeremy L Thompson   CeedScalar *w_array = NULL;
79573380422SJeremy L Thompson   CeedScalar const *x_array = NULL, *y_array = NULL;
7961f9221feSJeremy L Thompson   CeedSize n_w, n_x, n_y;
7970f7fd0f8Sjeremylt 
7980f7fd0f8Sjeremylt   ierr = CeedVectorGetLength(w, &n_w); CeedChk(ierr);
7990f7fd0f8Sjeremylt   ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr);
8000f7fd0f8Sjeremylt   ierr = CeedVectorGetLength(y, &n_y); CeedChk(ierr);
8010f7fd0f8Sjeremylt   if (n_w != n_x || n_w != n_y)
8020f7fd0f8Sjeremylt     // LCOV_EXCL_START
8030f7fd0f8Sjeremylt     return CeedError(w->ceed, CEED_ERROR_UNSUPPORTED,
8040f7fd0f8Sjeremylt                      "Cannot multiply vectors of different lengths");
8050f7fd0f8Sjeremylt   // LCOV_EXCL_STOP
8060f7fd0f8Sjeremylt 
8072d04630dSjeremylt   Ceed ceed_parent_w, ceed_parent_x, ceed_parent_y;
8082d04630dSjeremylt   ierr = CeedGetParent(w->ceed, &ceed_parent_w); CeedChk(ierr);
8092d04630dSjeremylt   ierr = CeedGetParent(x->ceed, &ceed_parent_x); CeedChk(ierr);
8102d04630dSjeremylt   ierr = CeedGetParent(y->ceed, &ceed_parent_y); CeedChk(ierr);
8119c774eddSJeremy L Thompson   if ((ceed_parent_w != ceed_parent_x) ||
8122d04630dSjeremylt       (ceed_parent_w != ceed_parent_y))
8132d04630dSjeremylt     // LCOV_EXCL_START
8142d04630dSjeremylt     return CeedError(w->ceed, CEED_ERROR_INCOMPATIBLE,
8152d04630dSjeremylt                      "Vectors w, x, and y must be created by the same Ceed context");
8162d04630dSjeremylt   // LCOV_EXCL_STOP
8172d04630dSjeremylt 
8189c774eddSJeremy L Thompson   bool has_valid_array_x = true, has_valid_array_y = true;
8199c774eddSJeremy L Thompson   ierr = CeedVectorHasValidArray(x, &has_valid_array_x); CeedChk(ierr);
8209c774eddSJeremy L Thompson   if (!has_valid_array_x)
8219c774eddSJeremy L Thompson     // LCOV_EXCL_START
8229c774eddSJeremy L Thompson     return CeedError(x->ceed, CEED_ERROR_BACKEND,
8239c774eddSJeremy L Thompson                      "CeedVector x has no valid data, "
8249c774eddSJeremy L Thompson                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
8259c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
8269c774eddSJeremy L Thompson   ierr = CeedVectorHasValidArray(y, &has_valid_array_y); CeedChk(ierr);
8279c774eddSJeremy L Thompson   if (!has_valid_array_y)
8289c774eddSJeremy L Thompson     // LCOV_EXCL_START
8299c774eddSJeremy L Thompson     return CeedError(y->ceed, CEED_ERROR_BACKEND,
8309c774eddSJeremy L Thompson                      "CeedVector y has no valid data, "
8319c774eddSJeremy L Thompson                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
8329c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
8339c774eddSJeremy L Thompson 
8340f7fd0f8Sjeremylt   // Backend implementation
835eaf62fffSJeremy L Thompson   if (w->PointwiseMult) {
836eaf62fffSJeremy L Thompson     ierr = w->PointwiseMult(w, x, y); CeedChk(ierr);
837eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
838eaf62fffSJeremy L Thompson   }
8390f7fd0f8Sjeremylt 
8400f7fd0f8Sjeremylt   // Default implementation
8419c774eddSJeremy L Thompson   ierr = CeedVectorGetArrayWrite(w, CEED_MEM_HOST, &w_array); CeedChk(ierr);
8420f7fd0f8Sjeremylt   if (x != w) {
8430f7fd0f8Sjeremylt     ierr = CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array); CeedChk(ierr);
8440f7fd0f8Sjeremylt   } else {
8450f7fd0f8Sjeremylt     x_array = w_array;
8460f7fd0f8Sjeremylt   }
8470f7fd0f8Sjeremylt   if (y != w && y != x) {
8480f7fd0f8Sjeremylt     ierr = CeedVectorGetArrayRead(y, CEED_MEM_HOST, &y_array); CeedChk(ierr);
8490f7fd0f8Sjeremylt   } else if (y != x) {
8500f7fd0f8Sjeremylt     y_array = w_array;
8510f7fd0f8Sjeremylt   } else {
8520f7fd0f8Sjeremylt     y_array = x_array;
8530f7fd0f8Sjeremylt   }
8540f7fd0f8Sjeremylt 
85573380422SJeremy L Thompson   assert(w_array); assert(x_array); assert(y_array);
85673380422SJeremy L Thompson 
8570f7fd0f8Sjeremylt   for (CeedInt i=0; i<n_w; i++)
8580f7fd0f8Sjeremylt     w_array[i] = x_array[i] * y_array[i];
8590f7fd0f8Sjeremylt 
8600f7fd0f8Sjeremylt   if (y != w && y != x) {
8610f7fd0f8Sjeremylt     ierr = CeedVectorRestoreArrayRead(y, &y_array); CeedChk(ierr);
8620f7fd0f8Sjeremylt   }
8630f7fd0f8Sjeremylt   if (x != w) {
8640f7fd0f8Sjeremylt     ierr = CeedVectorRestoreArrayRead(x, &x_array); CeedChk(ierr);
8650f7fd0f8Sjeremylt   }
8660f7fd0f8Sjeremylt   ierr = CeedVectorRestoreArray(w, &w_array); CeedChk(ierr);
8670f7fd0f8Sjeremylt   return CEED_ERROR_SUCCESS;
8680f7fd0f8Sjeremylt }
8690f7fd0f8Sjeremylt 
8700f7fd0f8Sjeremylt /**
871d99fa3c5SJeremy L Thompson   @brief Take the reciprocal of a CeedVector.
872d99fa3c5SJeremy L Thompson 
873d99fa3c5SJeremy L Thompson   @param vec  CeedVector to take reciprocal
874d99fa3c5SJeremy L Thompson 
875d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
876d99fa3c5SJeremy L Thompson 
877d99fa3c5SJeremy L Thompson   @ref User
878d99fa3c5SJeremy L Thompson **/
879d99fa3c5SJeremy L Thompson int CeedVectorReciprocal(CeedVector vec) {
880d99fa3c5SJeremy L Thompson   int ierr;
881d99fa3c5SJeremy L Thompson 
8829c774eddSJeremy L Thompson   bool has_valid_array = true;
8839c774eddSJeremy L Thompson   ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
8849c774eddSJeremy L Thompson   if (!has_valid_array)
8859c774eddSJeremy L Thompson     // LCOV_EXCL_START
8869c774eddSJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
8879c774eddSJeremy L Thompson                      "CeedVector has no valid data to compute reciprocal, "
8889c774eddSJeremy L Thompson                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
8899c774eddSJeremy L Thompson   // LCOV_EXCL_STOP
8909c774eddSJeremy L Thompson 
891d99fa3c5SJeremy L Thompson   // Check if vector data set
892d99fa3c5SJeremy L Thompson   if (!vec->state)
893d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
894e15f9bd0SJeremy L Thompson     return CeedError(vec->ceed, CEED_ERROR_INCOMPLETE,
895d99fa3c5SJeremy L Thompson                      "CeedVector must have data set to take reciprocal");
896d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
897d99fa3c5SJeremy L Thompson 
898d99fa3c5SJeremy L Thompson   // Backend impl for GPU, if added
899d99fa3c5SJeremy L Thompson   if (vec->Reciprocal) {
900d99fa3c5SJeremy L Thompson     ierr = vec->Reciprocal(vec); CeedChk(ierr);
901e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
902d99fa3c5SJeremy L Thompson   }
903d99fa3c5SJeremy L Thompson 
9041f9221feSJeremy L Thompson   CeedSize len;
905d99fa3c5SJeremy L Thompson   ierr = CeedVectorGetLength(vec, &len); CeedChk(ierr);
906d99fa3c5SJeremy L Thompson   CeedScalar *array;
9079c774eddSJeremy L Thompson   ierr = CeedVectorGetArrayWrite(vec, CEED_MEM_HOST, &array); CeedChk(ierr);
908d99fa3c5SJeremy L Thompson   for (CeedInt i=0; i<len; i++)
909d99fa3c5SJeremy L Thompson     if (fabs(array[i]) > CEED_EPSILON)
910d99fa3c5SJeremy L Thompson       array[i] = 1./array[i];
911d99fa3c5SJeremy L Thompson 
912e15f9bd0SJeremy L Thompson   ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr);
913e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
914d99fa3c5SJeremy L Thompson }
915d99fa3c5SJeremy L Thompson 
916d99fa3c5SJeremy L Thompson /**
9177a982d89SJeremy L. Thompson   @brief View a CeedVector
9180436c2adSjeremylt 
9190a0da059Sjeremylt   @param[in] vec     CeedVector to view
920d1d35e2fSjeremylt   @param[in] fp_fmt  Printing format
9210a0da059Sjeremylt   @param[in] stream  Filestream to write to
9220a0da059Sjeremylt 
9230436c2adSjeremylt   @return An error code: 0 - success, otherwise - failure
9240436c2adSjeremylt 
9257a982d89SJeremy L. Thompson   @ref User
9260436c2adSjeremylt **/
927d1d35e2fSjeremylt int CeedVectorView(CeedVector vec, const char *fp_fmt, FILE *stream) {
9287a982d89SJeremy L. Thompson   const CeedScalar *x;
9297a982d89SJeremy L. Thompson 
9307a982d89SJeremy L. Thompson   int ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x); CeedChk(ierr);
9317a982d89SJeremy L. Thompson 
9327a982d89SJeremy L. Thompson   char fmt[1024];
9337a982d89SJeremy L. Thompson   fprintf(stream, "CeedVector length %ld\n", (long)vec->length);
934d1d35e2fSjeremylt   snprintf(fmt, sizeof fmt, "  %s\n", fp_fmt ? fp_fmt : "%g");
9357a982d89SJeremy L. Thompson   for (CeedInt i=0; i<vec->length; i++)
9367a982d89SJeremy L. Thompson     fprintf(stream, fmt, x[i]);
9377a982d89SJeremy L. Thompson 
9387a982d89SJeremy L. Thompson   ierr = CeedVectorRestoreArrayRead(vec, &x); CeedChk(ierr);
939e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9400436c2adSjeremylt }
9410436c2adSjeremylt 
9420436c2adSjeremylt /**
943b7c9bbdaSJeremy L Thompson   @brief Get the Ceed associated with a CeedVector
944b7c9bbdaSJeremy L Thompson 
945b7c9bbdaSJeremy L Thompson   @param vec        CeedVector to retrieve state
946b7c9bbdaSJeremy L Thompson   @param[out] ceed  Variable to store ceed
947b7c9bbdaSJeremy L Thompson 
948b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
949b7c9bbdaSJeremy L Thompson 
950b7c9bbdaSJeremy L Thompson   @ref Advanced
951b7c9bbdaSJeremy L Thompson **/
952b7c9bbdaSJeremy L Thompson int CeedVectorGetCeed(CeedVector vec, Ceed *ceed) {
953b7c9bbdaSJeremy L Thompson   *ceed = vec->ceed;
954b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
955b7c9bbdaSJeremy L Thompson }
956b7c9bbdaSJeremy L Thompson 
957b7c9bbdaSJeremy L Thompson /**
9587a982d89SJeremy L. Thompson   @brief Get the length of a CeedVector
9590436c2adSjeremylt 
9607a982d89SJeremy L. Thompson   @param vec          CeedVector to retrieve length
9617a982d89SJeremy L. Thompson   @param[out] length  Variable to store length
9620436c2adSjeremylt 
9630436c2adSjeremylt   @return An error code: 0 - success, otherwise - failure
9640436c2adSjeremylt 
9657a982d89SJeremy L. Thompson   @ref User
9660436c2adSjeremylt **/
9671f9221feSJeremy L Thompson int CeedVectorGetLength(CeedVector vec, CeedSize *length) {
9687a982d89SJeremy L. Thompson   *length = vec->length;
969e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9700436c2adSjeremylt }
9710436c2adSjeremylt 
9720436c2adSjeremylt /**
9730436c2adSjeremylt   @brief Destroy a CeedVector
9740436c2adSjeremylt 
9750436c2adSjeremylt   @param vec  CeedVector to destroy
9760436c2adSjeremylt 
9770436c2adSjeremylt   @return An error code: 0 - success, otherwise - failure
9780436c2adSjeremylt 
9797a982d89SJeremy L. Thompson   @ref User
9800436c2adSjeremylt **/
9810436c2adSjeremylt int CeedVectorDestroy(CeedVector *vec) {
9820436c2adSjeremylt   int ierr;
9830436c2adSjeremylt 
984d1d35e2fSjeremylt   if (!*vec || --(*vec)->ref_count > 0) return CEED_ERROR_SUCCESS;
9850436c2adSjeremylt 
986187168c7SJeremy L Thompson   if (((*vec)->state % 2) == 1)
987e15f9bd0SJeremy L Thompson     return CeedError((*vec)->ceed, CEED_ERROR_ACCESS,
988187168c7SJeremy L Thompson                      "Cannot destroy CeedVector, the writable access "
9890436c2adSjeremylt                      "lock is in use");
9900436c2adSjeremylt 
991d1d35e2fSjeremylt   if ((*vec)->num_readers > 0)
992e92b641fSJeremy L Thompson     // LCOV_EXCL_START
993e15f9bd0SJeremy L Thompson     return CeedError((*vec)->ceed, CEED_ERROR_ACCESS,
994e15f9bd0SJeremy L Thompson                      "Cannot destroy CeedVector, a process has "
995187168c7SJeremy L Thompson                      "read access");
996e92b641fSJeremy L Thompson   // LCOV_EXCL_STOP
997187168c7SJeremy L Thompson 
9980436c2adSjeremylt   if ((*vec)->Destroy) {
9990436c2adSjeremylt     ierr = (*vec)->Destroy(*vec); CeedChk(ierr);
10000436c2adSjeremylt   }
10010436c2adSjeremylt 
10020436c2adSjeremylt   ierr = CeedDestroy(&(*vec)->ceed); CeedChk(ierr);
10030436c2adSjeremylt   ierr = CeedFree(vec); CeedChk(ierr);
1004e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10050436c2adSjeremylt }
10060436c2adSjeremylt 
10070436c2adSjeremylt /// @}
1008