xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-preconditioning.c (revision 9c774eddf8c0b4f5416196d32c5355c9591a7190)
1eaf62fffSJeremy L Thompson // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2eaf62fffSJeremy L Thompson // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3eaf62fffSJeremy L Thompson // reserved. See files LICENSE and NOTICE for details.
4eaf62fffSJeremy L Thompson //
5eaf62fffSJeremy L Thompson // This file is part of CEED, a collection of benchmarks, miniapps, software
6eaf62fffSJeremy L Thompson // libraries and APIs for efficient high-order finite element and spectral
7eaf62fffSJeremy L Thompson // element discretizations for exascale applications. For more information and
8eaf62fffSJeremy L Thompson // source code availability see http://github.com/ceed.
9eaf62fffSJeremy L Thompson //
10eaf62fffSJeremy L Thompson // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11eaf62fffSJeremy L Thompson // a collaborative effort of two U.S. Department of Energy organizations (Office
12eaf62fffSJeremy L Thompson // of Science and the National Nuclear Security Administration) responsible for
13eaf62fffSJeremy L Thompson // the planning and preparation of a capable exascale ecosystem, including
14eaf62fffSJeremy L Thompson // software, applications, hardware, advanced system engineering and early
15eaf62fffSJeremy L Thompson // testbed platforms, in support of the nation's exascale computing imperative.
16eaf62fffSJeremy L Thompson 
17eaf62fffSJeremy L Thompson #include <ceed/ceed.h>
18eaf62fffSJeremy L Thompson #include <ceed/backend.h>
19eaf62fffSJeremy L Thompson #include <ceed-impl.h>
20eaf62fffSJeremy L Thompson #include <math.h>
21eaf62fffSJeremy L Thompson #include <stdbool.h>
22eaf62fffSJeremy L Thompson #include <stdio.h>
23eaf62fffSJeremy L Thompson #include <string.h>
24eaf62fffSJeremy L Thompson 
25eaf62fffSJeremy L Thompson /// @file
26eaf62fffSJeremy L Thompson /// Implementation of CeedOperator preconditioning interfaces
27eaf62fffSJeremy L Thompson 
28eaf62fffSJeremy L Thompson /// ----------------------------------------------------------------------------
29eaf62fffSJeremy L Thompson /// CeedOperator Library Internal Preconditioning Functions
30eaf62fffSJeremy L Thompson /// ----------------------------------------------------------------------------
31eaf62fffSJeremy L Thompson /// @addtogroup CeedOperatorDeveloper
32eaf62fffSJeremy L Thompson /// @{
33eaf62fffSJeremy L Thompson 
34eaf62fffSJeremy L Thompson /**
35eaf62fffSJeremy L Thompson   @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced
36eaf62fffSJeremy L Thompson          CeedOperator functionality
37eaf62fffSJeremy L Thompson 
38eaf62fffSJeremy L Thompson   @param op  CeedOperator to create fallback for
39eaf62fffSJeremy L Thompson 
40eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
41eaf62fffSJeremy L Thompson 
42eaf62fffSJeremy L Thompson   @ref Developer
43eaf62fffSJeremy L Thompson **/
44eaf62fffSJeremy L Thompson int CeedOperatorCreateFallback(CeedOperator op) {
45eaf62fffSJeremy L Thompson   int ierr;
46eaf62fffSJeremy L Thompson 
47eaf62fffSJeremy L Thompson   // Fallback Ceed
48eaf62fffSJeremy L Thompson   const char *resource, *fallback_resource;
49eaf62fffSJeremy L Thompson   ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
50eaf62fffSJeremy L Thompson   ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
51eaf62fffSJeremy L Thompson   CeedChk(ierr);
52eaf62fffSJeremy L Thompson   if (!strcmp(resource, fallback_resource))
53eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
54eaf62fffSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
55eaf62fffSJeremy L Thompson                      "Backend %s cannot create an operator"
56eaf62fffSJeremy L Thompson                      "fallback to resource %s", resource, fallback_resource);
57eaf62fffSJeremy L Thompson   // LCOV_EXCL_STOP
58eaf62fffSJeremy L Thompson 
59eaf62fffSJeremy L Thompson   // Fallback Ceed
60eaf62fffSJeremy L Thompson   Ceed ceed_ref;
61eaf62fffSJeremy L Thompson   if (!op->ceed->op_fallback_ceed) {
62eaf62fffSJeremy L Thompson     ierr = CeedInit(fallback_resource, &ceed_ref); CeedChk(ierr);
63eaf62fffSJeremy L Thompson     ceed_ref->op_fallback_parent = op->ceed;
64eaf62fffSJeremy L Thompson     ceed_ref->Error = op->ceed->Error;
65eaf62fffSJeremy L Thompson     op->ceed->op_fallback_ceed = ceed_ref;
66eaf62fffSJeremy L Thompson   }
67eaf62fffSJeremy L Thompson   ceed_ref = op->ceed->op_fallback_ceed;
68eaf62fffSJeremy L Thompson 
69eaf62fffSJeremy L Thompson   // Clone Op
70eaf62fffSJeremy L Thompson   CeedOperator op_ref;
71eaf62fffSJeremy L Thompson   ierr = CeedCalloc(1, &op_ref); CeedChk(ierr);
72eaf62fffSJeremy L Thompson   memcpy(op_ref, op, sizeof(*op_ref));
73eaf62fffSJeremy L Thompson   op_ref->data = NULL;
74f04ea552SJeremy L Thompson   op_ref->is_interface_setup = false;
75f04ea552SJeremy L Thompson   op_ref->is_backend_setup = false;
76eaf62fffSJeremy L Thompson   op_ref->ceed = ceed_ref;
77eaf62fffSJeremy L Thompson   ierr = ceed_ref->OperatorCreate(op_ref); CeedChk(ierr);
78eaf62fffSJeremy L Thompson   op->op_fallback = op_ref;
79eaf62fffSJeremy L Thompson 
80eaf62fffSJeremy L Thompson   // Clone QF
81eaf62fffSJeremy L Thompson   CeedQFunction qf_ref;
82eaf62fffSJeremy L Thompson   ierr = CeedCalloc(1, &qf_ref); CeedChk(ierr);
83eaf62fffSJeremy L Thompson   memcpy(qf_ref, (op->qf), sizeof(*qf_ref));
84eaf62fffSJeremy L Thompson   qf_ref->data = NULL;
85eaf62fffSJeremy L Thompson   qf_ref->ceed = ceed_ref;
86eaf62fffSJeremy L Thompson   ierr = ceed_ref->QFunctionCreate(qf_ref); CeedChk(ierr);
87eaf62fffSJeremy L Thompson   op_ref->qf = qf_ref;
88eaf62fffSJeremy L Thompson   op->qf_fallback = qf_ref;
89eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
90eaf62fffSJeremy L Thompson }
91eaf62fffSJeremy L Thompson 
92eaf62fffSJeremy L Thompson /**
93eaf62fffSJeremy L Thompson   @brief Select correct basis matrix pointer based on CeedEvalMode
94eaf62fffSJeremy L Thompson 
95eaf62fffSJeremy L Thompson   @param[in] eval_mode   Current basis evaluation mode
96eaf62fffSJeremy L Thompson   @param[in] identity    Pointer to identity matrix
97eaf62fffSJeremy L Thompson   @param[in] interp      Pointer to interpolation matrix
98eaf62fffSJeremy L Thompson   @param[in] grad        Pointer to gradient matrix
99eaf62fffSJeremy L Thompson   @param[out] basis_ptr  Basis pointer to set
100eaf62fffSJeremy L Thompson 
101eaf62fffSJeremy L Thompson   @return none
102eaf62fffSJeremy L Thompson 
103eaf62fffSJeremy L Thompson   @ref Developer
104eaf62fffSJeremy L Thompson **/
105eaf62fffSJeremy L Thompson static inline void CeedOperatorGetBasisPointer(CeedEvalMode eval_mode,
106eaf62fffSJeremy L Thompson     const CeedScalar *identity, const CeedScalar *interp,
107eaf62fffSJeremy L Thompson     const CeedScalar *grad, const CeedScalar **basis_ptr) {
108eaf62fffSJeremy L Thompson   switch (eval_mode) {
109eaf62fffSJeremy L Thompson   case CEED_EVAL_NONE:
110eaf62fffSJeremy L Thompson     *basis_ptr = identity;
111eaf62fffSJeremy L Thompson     break;
112eaf62fffSJeremy L Thompson   case CEED_EVAL_INTERP:
113eaf62fffSJeremy L Thompson     *basis_ptr = interp;
114eaf62fffSJeremy L Thompson     break;
115eaf62fffSJeremy L Thompson   case CEED_EVAL_GRAD:
116eaf62fffSJeremy L Thompson     *basis_ptr = grad;
117eaf62fffSJeremy L Thompson     break;
118eaf62fffSJeremy L Thompson   case CEED_EVAL_WEIGHT:
119eaf62fffSJeremy L Thompson   case CEED_EVAL_DIV:
120eaf62fffSJeremy L Thompson   case CEED_EVAL_CURL:
121eaf62fffSJeremy L Thompson     break; // Caught by QF Assembly
122eaf62fffSJeremy L Thompson   }
123eaf62fffSJeremy L Thompson }
124eaf62fffSJeremy L Thompson 
125eaf62fffSJeremy L Thompson /**
126eaf62fffSJeremy L Thompson   @brief Create point block restriction for active operator field
127eaf62fffSJeremy L Thompson 
128eaf62fffSJeremy L Thompson   @param[in] rstr              Original CeedElemRestriction for active field
129eaf62fffSJeremy L Thompson   @param[out] pointblock_rstr  Address of the variable where the newly created
130eaf62fffSJeremy L Thompson                                  CeedElemRestriction will be stored
131eaf62fffSJeremy L Thompson 
132eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
133eaf62fffSJeremy L Thompson 
134eaf62fffSJeremy L Thompson   @ref Developer
135eaf62fffSJeremy L Thompson **/
136eaf62fffSJeremy L Thompson static int CeedOperatorCreateActivePointBlockRestriction(
137eaf62fffSJeremy L Thompson   CeedElemRestriction rstr,
138eaf62fffSJeremy L Thompson   CeedElemRestriction *pointblock_rstr) {
139eaf62fffSJeremy L Thompson   int ierr;
140eaf62fffSJeremy L Thompson   Ceed ceed;
141eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetCeed(rstr, &ceed); CeedChk(ierr);
142eaf62fffSJeremy L Thompson   const CeedInt *offsets;
143eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets);
144eaf62fffSJeremy L Thompson   CeedChk(ierr);
145eaf62fffSJeremy L Thompson 
146eaf62fffSJeremy L Thompson   // Expand offsets
147eaf62fffSJeremy L Thompson   CeedInt num_elem, num_comp, elem_size, comp_stride, max = 1,
148eaf62fffSJeremy L Thompson                                                       *pointblock_offsets;
149eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr);
150eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetNumComponents(rstr, &num_comp); CeedChk(ierr);
151eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstr, &elem_size); CeedChk(ierr);
152eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetCompStride(rstr, &comp_stride); CeedChk(ierr);
153eaf62fffSJeremy L Thompson   CeedInt shift = num_comp;
154eaf62fffSJeremy L Thompson   if (comp_stride != 1)
155eaf62fffSJeremy L Thompson     shift *= num_comp;
156eaf62fffSJeremy L Thompson   ierr = CeedCalloc(num_elem*elem_size, &pointblock_offsets);
157eaf62fffSJeremy L Thompson   CeedChk(ierr);
158eaf62fffSJeremy L Thompson   for (CeedInt i = 0; i < num_elem*elem_size; i++) {
159eaf62fffSJeremy L Thompson     pointblock_offsets[i] = offsets[i]*shift;
160eaf62fffSJeremy L Thompson     if (pointblock_offsets[i] > max)
161eaf62fffSJeremy L Thompson       max = pointblock_offsets[i];
162eaf62fffSJeremy L Thompson   }
163eaf62fffSJeremy L Thompson 
164eaf62fffSJeremy L Thompson   // Create new restriction
165eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionCreate(ceed, num_elem, elem_size, num_comp*num_comp,
166eaf62fffSJeremy L Thompson                                    1, max + num_comp*num_comp, CEED_MEM_HOST,
167eaf62fffSJeremy L Thompson                                    CEED_OWN_POINTER, pointblock_offsets, pointblock_rstr);
168eaf62fffSJeremy L Thompson   CeedChk(ierr);
169eaf62fffSJeremy L Thompson 
170eaf62fffSJeremy L Thompson   // Cleanup
171eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionRestoreOffsets(rstr, &offsets); CeedChk(ierr);
172eaf62fffSJeremy L Thompson 
173eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
174eaf62fffSJeremy L Thompson }
175eaf62fffSJeremy L Thompson 
176eaf62fffSJeremy L Thompson /**
177eaf62fffSJeremy L Thompson   @brief Core logic for assembling operator diagonal or point block diagonal
178eaf62fffSJeremy L Thompson 
179eaf62fffSJeremy L Thompson   @param[in] op             CeedOperator to assemble point block diagonal
180eaf62fffSJeremy L Thompson   @param[in] request        Address of CeedRequest for non-blocking completion, else
181eaf62fffSJeremy L Thompson                               CEED_REQUEST_IMMEDIATE
182eaf62fffSJeremy L Thompson   @param[in] is_pointblock  Boolean flag to assemble diagonal or point block diagonal
183eaf62fffSJeremy L Thompson   @param[out] assembled     CeedVector to store assembled diagonal
184eaf62fffSJeremy L Thompson 
185eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
186eaf62fffSJeremy L Thompson 
187eaf62fffSJeremy L Thompson   @ref Developer
188eaf62fffSJeremy L Thompson **/
189eaf62fffSJeremy L Thompson static inline int CeedSingleOperatorAssembleAddDiagonal(CeedOperator op,
190eaf62fffSJeremy L Thompson     CeedRequest *request, const bool is_pointblock, CeedVector assembled) {
191eaf62fffSJeremy L Thompson   int ierr;
192eaf62fffSJeremy L Thompson   Ceed ceed;
193eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
194eaf62fffSJeremy L Thompson 
195eaf62fffSJeremy L Thompson   // Assemble QFunction
196eaf62fffSJeremy L Thompson   CeedQFunction qf;
197eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
198eaf62fffSJeremy L Thompson   CeedInt num_input_fields, num_output_fields;
199eaf62fffSJeremy L Thompson   ierr= CeedQFunctionGetNumArgs(qf, &num_input_fields, &num_output_fields);
200eaf62fffSJeremy L Thompson   CeedChk(ierr);
201eaf62fffSJeremy L Thompson   CeedVector assembled_qf;
202eaf62fffSJeremy L Thompson   CeedElemRestriction rstr;
20370a7ffb3SJeremy L Thompson   ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op,  &assembled_qf,
20470a7ffb3SJeremy L Thompson          &rstr, request); CeedChk(ierr);
205eaf62fffSJeremy L Thompson   CeedInt layout[3];
206eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetELayout(rstr, &layout); CeedChk(ierr);
207eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr);
208eaf62fffSJeremy L Thompson   CeedScalar max_norm = 0;
209eaf62fffSJeremy L Thompson   ierr = CeedVectorNorm(assembled_qf, CEED_NORM_MAX, &max_norm); CeedChk(ierr);
210eaf62fffSJeremy L Thompson 
211eaf62fffSJeremy L Thompson   // Determine active input basis
212eaf62fffSJeremy L Thompson   CeedOperatorField *op_fields;
213eaf62fffSJeremy L Thompson   CeedQFunctionField *qf_fields;
2147e7773b5SJeremy L Thompson   ierr = CeedOperatorGetFields(op, NULL, &op_fields, NULL, NULL); CeedChk(ierr);
2157e7773b5SJeremy L Thompson   ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL); CeedChk(ierr);
216eaf62fffSJeremy L Thompson   CeedInt num_eval_mode_in = 0, num_comp, dim = 1;
217eaf62fffSJeremy L Thompson   CeedEvalMode *eval_mode_in = NULL;
218eaf62fffSJeremy L Thompson   CeedBasis basis_in = NULL;
219eaf62fffSJeremy L Thompson   CeedElemRestriction rstr_in = NULL;
220eaf62fffSJeremy L Thompson   for (CeedInt i=0; i<num_input_fields; i++) {
221eaf62fffSJeremy L Thompson     CeedVector vec;
222eaf62fffSJeremy L Thompson     ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChk(ierr);
223eaf62fffSJeremy L Thompson     if (vec == CEED_VECTOR_ACTIVE) {
224eaf62fffSJeremy L Thompson       CeedElemRestriction rstr;
225eaf62fffSJeremy L Thompson       ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis_in); CeedChk(ierr);
226eaf62fffSJeremy L Thompson       ierr = CeedBasisGetNumComponents(basis_in, &num_comp); CeedChk(ierr);
227eaf62fffSJeremy L Thompson       ierr = CeedBasisGetDimension(basis_in, &dim); CeedChk(ierr);
228eaf62fffSJeremy L Thompson       ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr); CeedChk(ierr);
229eaf62fffSJeremy L Thompson       if (rstr_in && rstr_in != rstr)
230eaf62fffSJeremy L Thompson         // LCOV_EXCL_START
231eaf62fffSJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND,
232eaf62fffSJeremy L Thompson                          "Multi-field non-composite operator diagonal assembly not supported");
233eaf62fffSJeremy L Thompson       // LCOV_EXCL_STOP
234eaf62fffSJeremy L Thompson       rstr_in = rstr;
235eaf62fffSJeremy L Thompson       CeedEvalMode eval_mode;
236eaf62fffSJeremy L Thompson       ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); CeedChk(ierr);
237eaf62fffSJeremy L Thompson       switch (eval_mode) {
238eaf62fffSJeremy L Thompson       case CEED_EVAL_NONE:
239eaf62fffSJeremy L Thompson       case CEED_EVAL_INTERP:
240eaf62fffSJeremy L Thompson         ierr = CeedRealloc(num_eval_mode_in + 1, &eval_mode_in); CeedChk(ierr);
241eaf62fffSJeremy L Thompson         eval_mode_in[num_eval_mode_in] = eval_mode;
242eaf62fffSJeremy L Thompson         num_eval_mode_in += 1;
243eaf62fffSJeremy L Thompson         break;
244eaf62fffSJeremy L Thompson       case CEED_EVAL_GRAD:
245eaf62fffSJeremy L Thompson         ierr = CeedRealloc(num_eval_mode_in + dim, &eval_mode_in); CeedChk(ierr);
246eaf62fffSJeremy L Thompson         for (CeedInt d=0; d<dim; d++)
247eaf62fffSJeremy L Thompson           eval_mode_in[num_eval_mode_in+d] = eval_mode;
248eaf62fffSJeremy L Thompson         num_eval_mode_in += dim;
249eaf62fffSJeremy L Thompson         break;
250eaf62fffSJeremy L Thompson       case CEED_EVAL_WEIGHT:
251eaf62fffSJeremy L Thompson       case CEED_EVAL_DIV:
252eaf62fffSJeremy L Thompson       case CEED_EVAL_CURL:
253eaf62fffSJeremy L Thompson         break; // Caught by QF Assembly
254eaf62fffSJeremy L Thompson       }
255eaf62fffSJeremy L Thompson     }
256eaf62fffSJeremy L Thompson   }
257eaf62fffSJeremy L Thompson 
258eaf62fffSJeremy L Thompson   // Determine active output basis
2597e7773b5SJeremy L Thompson   ierr = CeedOperatorGetFields(op, NULL, NULL, NULL, &op_fields); CeedChk(ierr);
2607e7773b5SJeremy L Thompson   ierr = CeedQFunctionGetFields(qf, NULL, NULL, NULL, &qf_fields); CeedChk(ierr);
261eaf62fffSJeremy L Thompson   CeedInt num_eval_mode_out = 0;
262eaf62fffSJeremy L Thompson   CeedEvalMode *eval_mode_out = NULL;
263eaf62fffSJeremy L Thompson   CeedBasis basis_out = NULL;
264eaf62fffSJeremy L Thompson   CeedElemRestriction rstr_out = NULL;
265eaf62fffSJeremy L Thompson   for (CeedInt i=0; i<num_output_fields; i++) {
266eaf62fffSJeremy L Thompson     CeedVector vec;
267eaf62fffSJeremy L Thompson     ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChk(ierr);
268eaf62fffSJeremy L Thompson     if (vec == CEED_VECTOR_ACTIVE) {
269eaf62fffSJeremy L Thompson       CeedElemRestriction rstr;
270eaf62fffSJeremy L Thompson       ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis_out); CeedChk(ierr);
271eaf62fffSJeremy L Thompson       ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr); CeedChk(ierr);
272eaf62fffSJeremy L Thompson       if (rstr_out && rstr_out != rstr)
273eaf62fffSJeremy L Thompson         // LCOV_EXCL_START
274eaf62fffSJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND,
275eaf62fffSJeremy L Thompson                          "Multi-field non-composite operator diagonal assembly not supported");
276eaf62fffSJeremy L Thompson       // LCOV_EXCL_STOP
277eaf62fffSJeremy L Thompson       rstr_out = rstr;
278eaf62fffSJeremy L Thompson       CeedEvalMode eval_mode;
279eaf62fffSJeremy L Thompson       ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); CeedChk(ierr);
280eaf62fffSJeremy L Thompson       switch (eval_mode) {
281eaf62fffSJeremy L Thompson       case CEED_EVAL_NONE:
282eaf62fffSJeremy L Thompson       case CEED_EVAL_INTERP:
283eaf62fffSJeremy L Thompson         ierr = CeedRealloc(num_eval_mode_out + 1, &eval_mode_out); CeedChk(ierr);
284eaf62fffSJeremy L Thompson         eval_mode_out[num_eval_mode_out] = eval_mode;
285eaf62fffSJeremy L Thompson         num_eval_mode_out += 1;
286eaf62fffSJeremy L Thompson         break;
287eaf62fffSJeremy L Thompson       case CEED_EVAL_GRAD:
288eaf62fffSJeremy L Thompson         ierr = CeedRealloc(num_eval_mode_out + dim, &eval_mode_out); CeedChk(ierr);
289eaf62fffSJeremy L Thompson         for (CeedInt d=0; d<dim; d++)
290eaf62fffSJeremy L Thompson           eval_mode_out[num_eval_mode_out+d] = eval_mode;
291eaf62fffSJeremy L Thompson         num_eval_mode_out += dim;
292eaf62fffSJeremy L Thompson         break;
293eaf62fffSJeremy L Thompson       case CEED_EVAL_WEIGHT:
294eaf62fffSJeremy L Thompson       case CEED_EVAL_DIV:
295eaf62fffSJeremy L Thompson       case CEED_EVAL_CURL:
296eaf62fffSJeremy L Thompson         break; // Caught by QF Assembly
297eaf62fffSJeremy L Thompson       }
298eaf62fffSJeremy L Thompson     }
299eaf62fffSJeremy L Thompson   }
300eaf62fffSJeremy L Thompson 
301eaf62fffSJeremy L Thompson   // Assemble point block diagonal restriction, if needed
302eaf62fffSJeremy L Thompson   CeedElemRestriction diag_rstr = rstr_out;
303eaf62fffSJeremy L Thompson   if (is_pointblock) {
304eaf62fffSJeremy L Thompson     ierr = CeedOperatorCreateActivePointBlockRestriction(rstr_out, &diag_rstr);
305eaf62fffSJeremy L Thompson     CeedChk(ierr);
306eaf62fffSJeremy L Thompson   }
307eaf62fffSJeremy L Thompson 
308eaf62fffSJeremy L Thompson   // Create diagonal vector
309eaf62fffSJeremy L Thompson   CeedVector elem_diag;
310eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionCreateVector(diag_rstr, NULL, &elem_diag);
311eaf62fffSJeremy L Thompson   CeedChk(ierr);
312eaf62fffSJeremy L Thompson 
313eaf62fffSJeremy L Thompson   // Assemble element operator diagonals
314*9c774eddSJeremy L Thompson   CeedScalar *elem_diag_array;
315*9c774eddSJeremy L Thompson   const CeedScalar *assembled_qf_array;
316eaf62fffSJeremy L Thompson   ierr = CeedVectorSetValue(elem_diag, 0.0); CeedChk(ierr);
317eaf62fffSJeremy L Thompson   ierr = CeedVectorGetArray(elem_diag, CEED_MEM_HOST, &elem_diag_array);
318eaf62fffSJeremy L Thompson   CeedChk(ierr);
319*9c774eddSJeremy L Thompson   ierr = CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array);
320eaf62fffSJeremy L Thompson   CeedChk(ierr);
321eaf62fffSJeremy L Thompson   CeedInt num_elem, num_nodes, num_qpts;
322eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetNumElements(diag_rstr, &num_elem); CeedChk(ierr);
323eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumNodes(basis_in, &num_nodes); CeedChk(ierr);
324eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts); CeedChk(ierr);
325eaf62fffSJeremy L Thompson   // Basis matrices
326eaf62fffSJeremy L Thompson   const CeedScalar *interp_in, *interp_out, *grad_in, *grad_out;
327eaf62fffSJeremy L Thompson   CeedScalar *identity = NULL;
328eaf62fffSJeremy L Thompson   bool evalNone = false;
329eaf62fffSJeremy L Thompson   for (CeedInt i=0; i<num_eval_mode_in; i++)
330eaf62fffSJeremy L Thompson     evalNone = evalNone || (eval_mode_in[i] == CEED_EVAL_NONE);
331eaf62fffSJeremy L Thompson   for (CeedInt i=0; i<num_eval_mode_out; i++)
332eaf62fffSJeremy L Thompson     evalNone = evalNone || (eval_mode_out[i] == CEED_EVAL_NONE);
333eaf62fffSJeremy L Thompson   if (evalNone) {
334eaf62fffSJeremy L Thompson     ierr = CeedCalloc(num_qpts*num_nodes, &identity); CeedChk(ierr);
335eaf62fffSJeremy L Thompson     for (CeedInt i=0; i<(num_nodes<num_qpts?num_nodes:num_qpts); i++)
336eaf62fffSJeremy L Thompson       identity[i*num_nodes+i] = 1.0;
337eaf62fffSJeremy L Thompson   }
338eaf62fffSJeremy L Thompson   ierr = CeedBasisGetInterp(basis_in, &interp_in); CeedChk(ierr);
339eaf62fffSJeremy L Thompson   ierr = CeedBasisGetInterp(basis_out, &interp_out); CeedChk(ierr);
340eaf62fffSJeremy L Thompson   ierr = CeedBasisGetGrad(basis_in, &grad_in); CeedChk(ierr);
341eaf62fffSJeremy L Thompson   ierr = CeedBasisGetGrad(basis_out, &grad_out); CeedChk(ierr);
342eaf62fffSJeremy L Thompson   // Compute the diagonal of B^T D B
343eaf62fffSJeremy L Thompson   // Each element
344eaf62fffSJeremy L Thompson   const CeedScalar qf_value_bound = max_norm*100*CEED_EPSILON;
345eaf62fffSJeremy L Thompson   for (CeedInt e=0; e<num_elem; e++) {
346eaf62fffSJeremy L Thompson     CeedInt d_out = -1;
347eaf62fffSJeremy L Thompson     // Each basis eval mode pair
348eaf62fffSJeremy L Thompson     for (CeedInt e_out=0; e_out<num_eval_mode_out; e_out++) {
349eaf62fffSJeremy L Thompson       const CeedScalar *bt = NULL;
350eaf62fffSJeremy L Thompson       if (eval_mode_out[e_out] == CEED_EVAL_GRAD)
351eaf62fffSJeremy L Thompson         d_out += 1;
352eaf62fffSJeremy L Thompson       CeedOperatorGetBasisPointer(eval_mode_out[e_out], identity, interp_out,
353eaf62fffSJeremy L Thompson                                   &grad_out[d_out*num_qpts*num_nodes], &bt);
354eaf62fffSJeremy L Thompson       CeedInt d_in = -1;
355eaf62fffSJeremy L Thompson       for (CeedInt e_in=0; e_in<num_eval_mode_in; e_in++) {
356eaf62fffSJeremy L Thompson         const CeedScalar *b = NULL;
357eaf62fffSJeremy L Thompson         if (eval_mode_in[e_in] == CEED_EVAL_GRAD)
358eaf62fffSJeremy L Thompson           d_in += 1;
359eaf62fffSJeremy L Thompson         CeedOperatorGetBasisPointer(eval_mode_in[e_in], identity, interp_in,
360eaf62fffSJeremy L Thompson                                     &grad_in[d_in*num_qpts*num_nodes], &b);
361eaf62fffSJeremy L Thompson         // Each component
362eaf62fffSJeremy L Thompson         for (CeedInt c_out=0; c_out<num_comp; c_out++)
363eaf62fffSJeremy L Thompson           // Each qpoint/node pair
364eaf62fffSJeremy L Thompson           for (CeedInt q=0; q<num_qpts; q++)
365eaf62fffSJeremy L Thompson             if (is_pointblock) {
366eaf62fffSJeremy L Thompson               // Point Block Diagonal
367eaf62fffSJeremy L Thompson               for (CeedInt c_in=0; c_in<num_comp; c_in++) {
368eaf62fffSJeremy L Thompson                 const CeedScalar qf_value =
369eaf62fffSJeremy L Thompson                   assembled_qf_array[q*layout[0] + (((e_in*num_comp+c_in)*
370eaf62fffSJeremy L Thompson                                                      num_eval_mode_out+e_out)*num_comp+c_out)*layout[1] + e*layout[2]];
371eaf62fffSJeremy L Thompson                 if (fabs(qf_value) > qf_value_bound)
372eaf62fffSJeremy L Thompson                   for (CeedInt n=0; n<num_nodes; n++)
373eaf62fffSJeremy L Thompson                     elem_diag_array[((e*num_comp+c_out)*num_comp+c_in)*num_nodes+n] +=
374eaf62fffSJeremy L Thompson                       bt[q*num_nodes+n] * qf_value * b[q*num_nodes+n];
375eaf62fffSJeremy L Thompson               }
376eaf62fffSJeremy L Thompson             } else {
377eaf62fffSJeremy L Thompson               // Diagonal Only
378eaf62fffSJeremy L Thompson               const CeedScalar qf_value =
379eaf62fffSJeremy L Thompson                 assembled_qf_array[q*layout[0] + (((e_in*num_comp+c_out)*
380eaf62fffSJeremy L Thompson                                                    num_eval_mode_out+e_out)*num_comp+c_out)*layout[1] + e*layout[2]];
381eaf62fffSJeremy L Thompson               if (fabs(qf_value) > qf_value_bound)
382eaf62fffSJeremy L Thompson                 for (CeedInt n=0; n<num_nodes; n++)
383eaf62fffSJeremy L Thompson                   elem_diag_array[(e*num_comp+c_out)*num_nodes+n] +=
384eaf62fffSJeremy L Thompson                     bt[q*num_nodes+n] * qf_value * b[q*num_nodes+n];
385eaf62fffSJeremy L Thompson             }
386eaf62fffSJeremy L Thompson       }
387eaf62fffSJeremy L Thompson     }
388eaf62fffSJeremy L Thompson   }
389eaf62fffSJeremy L Thompson   ierr = CeedVectorRestoreArray(elem_diag, &elem_diag_array); CeedChk(ierr);
390*9c774eddSJeremy L Thompson   ierr = CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array);
391*9c774eddSJeremy L Thompson   CeedChk(ierr);
392eaf62fffSJeremy L Thompson 
393eaf62fffSJeremy L Thompson   // Assemble local operator diagonal
394eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionApply(diag_rstr, CEED_TRANSPOSE, elem_diag,
395eaf62fffSJeremy L Thompson                                   assembled, request); CeedChk(ierr);
396eaf62fffSJeremy L Thompson 
397eaf62fffSJeremy L Thompson   // Cleanup
398eaf62fffSJeremy L Thompson   if (is_pointblock) {
399eaf62fffSJeremy L Thompson     ierr = CeedElemRestrictionDestroy(&diag_rstr); CeedChk(ierr);
400eaf62fffSJeremy L Thompson   }
401eaf62fffSJeremy L Thompson   ierr = CeedVectorDestroy(&assembled_qf); CeedChk(ierr);
402eaf62fffSJeremy L Thompson   ierr = CeedVectorDestroy(&elem_diag); CeedChk(ierr);
403eaf62fffSJeremy L Thompson   ierr = CeedFree(&eval_mode_in); CeedChk(ierr);
404eaf62fffSJeremy L Thompson   ierr = CeedFree(&eval_mode_out); CeedChk(ierr);
405eaf62fffSJeremy L Thompson   ierr = CeedFree(&identity); CeedChk(ierr);
406eaf62fffSJeremy L Thompson 
407eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
408eaf62fffSJeremy L Thompson }
409eaf62fffSJeremy L Thompson 
410eaf62fffSJeremy L Thompson /**
411eaf62fffSJeremy L Thompson   @brief Core logic for assembling composite operator diagonal
412eaf62fffSJeremy L Thompson 
413eaf62fffSJeremy L Thompson   @param[in] op             CeedOperator to assemble point block diagonal
414eaf62fffSJeremy L Thompson   @param[in] request        Address of CeedRequest for non-blocking completion, else
415eaf62fffSJeremy L Thompson                             CEED_REQUEST_IMMEDIATE
416eaf62fffSJeremy L Thompson   @param[in] is_pointblock  Boolean flag to assemble diagonal or point block diagonal
417eaf62fffSJeremy L Thompson   @param[out] assembled     CeedVector to store assembled diagonal
418eaf62fffSJeremy L Thompson 
419eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
420eaf62fffSJeremy L Thompson 
421eaf62fffSJeremy L Thompson   @ref Developer
422eaf62fffSJeremy L Thompson **/
423eaf62fffSJeremy L Thompson static inline int CeedCompositeOperatorLinearAssembleAddDiagonal(
424eaf62fffSJeremy L Thompson   CeedOperator op, CeedRequest *request, const bool is_pointblock,
425eaf62fffSJeremy L Thompson   CeedVector assembled) {
426eaf62fffSJeremy L Thompson   int ierr;
427eaf62fffSJeremy L Thompson   CeedInt num_sub;
428eaf62fffSJeremy L Thompson   CeedOperator *suboperators;
429eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr);
430eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
431eaf62fffSJeremy L Thompson   for (CeedInt i = 0; i < num_sub; i++) {
432eaf62fffSJeremy L Thompson     ierr = CeedSingleOperatorAssembleAddDiagonal(suboperators[i], request,
433eaf62fffSJeremy L Thompson            is_pointblock, assembled); CeedChk(ierr);
434eaf62fffSJeremy L Thompson   }
435eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
436eaf62fffSJeremy L Thompson }
437eaf62fffSJeremy L Thompson 
438eaf62fffSJeremy L Thompson /**
439eaf62fffSJeremy L Thompson   @brief Build nonzero pattern for non-composite operator
440eaf62fffSJeremy L Thompson 
441eaf62fffSJeremy L Thompson   Users should generally use CeedOperatorLinearAssembleSymbolic()
442eaf62fffSJeremy L Thompson 
443eaf62fffSJeremy L Thompson   @param[in] op      CeedOperator to assemble nonzero pattern
444eaf62fffSJeremy L Thompson   @param[in] offset  Offset for number of entries
445eaf62fffSJeremy L Thompson   @param[out] rows   Row number for each entry
446eaf62fffSJeremy L Thompson   @param[out] cols   Column number for each entry
447eaf62fffSJeremy L Thompson 
448eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
449eaf62fffSJeremy L Thompson 
450eaf62fffSJeremy L Thompson   @ref Developer
451eaf62fffSJeremy L Thompson **/
452eaf62fffSJeremy L Thompson static int CeedSingleOperatorAssembleSymbolic(CeedOperator op, CeedInt offset,
453eaf62fffSJeremy L Thompson     CeedInt *rows, CeedInt *cols) {
454eaf62fffSJeremy L Thompson   int ierr;
455eaf62fffSJeremy L Thompson   Ceed ceed = op->ceed;
456f04ea552SJeremy L Thompson   if (op->is_composite)
457eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
458eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
459eaf62fffSJeremy L Thompson                      "Composite operator not supported");
460eaf62fffSJeremy L Thompson   // LCOV_EXCL_STOP
461eaf62fffSJeremy L Thompson 
462eaf62fffSJeremy L Thompson   CeedElemRestriction rstr_in;
463eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetActiveElemRestriction(op, &rstr_in); CeedChk(ierr);
464eaf62fffSJeremy L Thompson   CeedInt num_elem, elem_size, num_nodes, num_comp;
465eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetNumElements(rstr_in, &num_elem); CeedChk(ierr);
466eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstr_in, &elem_size); CeedChk(ierr);
467eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetLVectorSize(rstr_in, &num_nodes); CeedChk(ierr);
468eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetNumComponents(rstr_in, &num_comp); CeedChk(ierr);
469eaf62fffSJeremy L Thompson   CeedInt layout_er[3];
470eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetELayout(rstr_in, &layout_er); CeedChk(ierr);
471eaf62fffSJeremy L Thompson 
472eaf62fffSJeremy L Thompson   CeedInt local_num_entries = elem_size*num_comp * elem_size*num_comp * num_elem;
473eaf62fffSJeremy L Thompson 
474eaf62fffSJeremy L Thompson   // Determine elem_dof relation
475eaf62fffSJeremy L Thompson   CeedVector index_vec;
476eaf62fffSJeremy L Thompson   ierr = CeedVectorCreate(ceed, num_nodes, &index_vec); CeedChk(ierr);
477eaf62fffSJeremy L Thompson   CeedScalar *array;
478*9c774eddSJeremy L Thompson   ierr = CeedVectorGetArrayWrite(index_vec, CEED_MEM_HOST, &array); CeedChk(ierr);
479eaf62fffSJeremy L Thompson   for (CeedInt i = 0; i < num_nodes; ++i) {
480eaf62fffSJeremy L Thompson     array[i] = i;
481eaf62fffSJeremy L Thompson   }
482eaf62fffSJeremy L Thompson   ierr = CeedVectorRestoreArray(index_vec, &array); CeedChk(ierr);
483eaf62fffSJeremy L Thompson   CeedVector elem_dof;
484eaf62fffSJeremy L Thompson   ierr = CeedVectorCreate(ceed, num_elem * elem_size * num_comp, &elem_dof);
485eaf62fffSJeremy L Thompson   CeedChk(ierr);
486eaf62fffSJeremy L Thompson   ierr = CeedVectorSetValue(elem_dof, 0.0); CeedChk(ierr);
487eaf62fffSJeremy L Thompson   CeedElemRestrictionApply(rstr_in, CEED_NOTRANSPOSE, index_vec,
488eaf62fffSJeremy L Thompson                            elem_dof, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
489eaf62fffSJeremy L Thompson   const CeedScalar *elem_dof_a;
490eaf62fffSJeremy L Thompson   ierr = CeedVectorGetArrayRead(elem_dof, CEED_MEM_HOST, &elem_dof_a);
491eaf62fffSJeremy L Thompson   CeedChk(ierr);
492eaf62fffSJeremy L Thompson   ierr = CeedVectorDestroy(&index_vec); CeedChk(ierr);
493eaf62fffSJeremy L Thompson 
494eaf62fffSJeremy L Thompson   // Determine i, j locations for element matrices
495eaf62fffSJeremy L Thompson   CeedInt count = 0;
496eaf62fffSJeremy L Thompson   for (int e = 0; e < num_elem; ++e) {
497eaf62fffSJeremy L Thompson     for (int comp_in = 0; comp_in < num_comp; ++comp_in) {
498eaf62fffSJeremy L Thompson       for (int comp_out = 0; comp_out < num_comp; ++comp_out) {
499eaf62fffSJeremy L Thompson         for (int i = 0; i < elem_size; ++i) {
500eaf62fffSJeremy L Thompson           for (int j = 0; j < elem_size; ++j) {
501eaf62fffSJeremy L Thompson             const CeedInt elem_dof_index_row = (i)*layout_er[0] +
502eaf62fffSJeremy L Thompson                                                (comp_out)*layout_er[1] + e*layout_er[2];
503eaf62fffSJeremy L Thompson             const CeedInt elem_dof_index_col = (j)*layout_er[0] +
504eaf62fffSJeremy L Thompson                                                (comp_in)*layout_er[1] + e*layout_er[2];
505eaf62fffSJeremy L Thompson 
506eaf62fffSJeremy L Thompson             const CeedInt row = elem_dof_a[elem_dof_index_row];
507eaf62fffSJeremy L Thompson             const CeedInt col = elem_dof_a[elem_dof_index_col];
508eaf62fffSJeremy L Thompson 
509eaf62fffSJeremy L Thompson             rows[offset + count] = row;
510eaf62fffSJeremy L Thompson             cols[offset + count] = col;
511eaf62fffSJeremy L Thompson             count++;
512eaf62fffSJeremy L Thompson           }
513eaf62fffSJeremy L Thompson         }
514eaf62fffSJeremy L Thompson       }
515eaf62fffSJeremy L Thompson     }
516eaf62fffSJeremy L Thompson   }
517eaf62fffSJeremy L Thompson   if (count != local_num_entries)
518eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
519eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing assembled entries");
520eaf62fffSJeremy L Thompson   // LCOV_EXCL_STOP
521eaf62fffSJeremy L Thompson   ierr = CeedVectorRestoreArrayRead(elem_dof, &elem_dof_a); CeedChk(ierr);
522eaf62fffSJeremy L Thompson   ierr = CeedVectorDestroy(&elem_dof); CeedChk(ierr);
523eaf62fffSJeremy L Thompson 
524eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
525eaf62fffSJeremy L Thompson }
526eaf62fffSJeremy L Thompson 
527eaf62fffSJeremy L Thompson /**
528eaf62fffSJeremy L Thompson   @brief Assemble nonzero entries for non-composite operator
529eaf62fffSJeremy L Thompson 
530eaf62fffSJeremy L Thompson   Users should generally use CeedOperatorLinearAssemble()
531eaf62fffSJeremy L Thompson 
532eaf62fffSJeremy L Thompson   @param[in] op       CeedOperator to assemble
533eaf62fffSJeremy L Thompson   @param[out] offset  Offest for number of entries
534eaf62fffSJeremy L Thompson   @param[out] values  Values to assemble into matrix
535eaf62fffSJeremy L Thompson 
536eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
537eaf62fffSJeremy L Thompson 
538eaf62fffSJeremy L Thompson   @ref Developer
539eaf62fffSJeremy L Thompson **/
540eaf62fffSJeremy L Thompson static int CeedSingleOperatorAssemble(CeedOperator op, CeedInt offset,
541eaf62fffSJeremy L Thompson                                       CeedVector values) {
542eaf62fffSJeremy L Thompson   int ierr;
543eaf62fffSJeremy L Thompson   Ceed ceed = op->ceed;
544f04ea552SJeremy L Thompson   if (op->is_composite)
545eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
546eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
547eaf62fffSJeremy L Thompson                      "Composite operator not supported");
548eaf62fffSJeremy L Thompson   // LCOV_EXCL_STOP
549eaf62fffSJeremy L Thompson 
550eaf62fffSJeremy L Thompson   // Assemble QFunction
551eaf62fffSJeremy L Thompson   CeedQFunction qf;
552eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
553eaf62fffSJeremy L Thompson   CeedVector assembled_qf;
554eaf62fffSJeremy L Thompson   CeedElemRestriction rstr_q;
55570a7ffb3SJeremy L Thompson   ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate(
556eaf62fffSJeremy L Thompson            op, &assembled_qf, &rstr_q, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
557eaf62fffSJeremy L Thompson 
558eaf62fffSJeremy L Thompson   CeedInt qf_length;
559eaf62fffSJeremy L Thompson   ierr = CeedVectorGetLength(assembled_qf, &qf_length); CeedChk(ierr);
560eaf62fffSJeremy L Thompson 
5617e7773b5SJeremy L Thompson   CeedInt num_input_fields, num_output_fields;
562eaf62fffSJeremy L Thompson   CeedOperatorField *input_fields;
563eaf62fffSJeremy L Thompson   CeedOperatorField *output_fields;
5647e7773b5SJeremy L Thompson   ierr = CeedOperatorGetFields(op, &num_input_fields, &input_fields,
5657e7773b5SJeremy L Thompson                                &num_output_fields, &output_fields); CeedChk(ierr);
566eaf62fffSJeremy L Thompson 
567eaf62fffSJeremy L Thompson   // Determine active input basis
568eaf62fffSJeremy L Thompson   CeedQFunctionField *qf_fields;
5697e7773b5SJeremy L Thompson   ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL); CeedChk(ierr);
570eaf62fffSJeremy L Thompson   CeedInt num_eval_mode_in = 0, dim = 1;
571eaf62fffSJeremy L Thompson   CeedEvalMode *eval_mode_in = NULL;
572eaf62fffSJeremy L Thompson   CeedBasis basis_in = NULL;
573eaf62fffSJeremy L Thompson   CeedElemRestriction rstr_in = NULL;
574eaf62fffSJeremy L Thompson   for (CeedInt i=0; i<num_input_fields; i++) {
575eaf62fffSJeremy L Thompson     CeedVector vec;
576eaf62fffSJeremy L Thompson     ierr = CeedOperatorFieldGetVector(input_fields[i], &vec); CeedChk(ierr);
577eaf62fffSJeremy L Thompson     if (vec == CEED_VECTOR_ACTIVE) {
578eaf62fffSJeremy L Thompson       ierr = CeedOperatorFieldGetBasis(input_fields[i], &basis_in);
579eaf62fffSJeremy L Thompson       CeedChk(ierr);
580eaf62fffSJeremy L Thompson       ierr = CeedBasisGetDimension(basis_in, &dim); CeedChk(ierr);
581eaf62fffSJeremy L Thompson       ierr = CeedOperatorFieldGetElemRestriction(input_fields[i], &rstr_in);
582eaf62fffSJeremy L Thompson       CeedChk(ierr);
583eaf62fffSJeremy L Thompson       CeedEvalMode eval_mode;
584eaf62fffSJeremy L Thompson       ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode);
585eaf62fffSJeremy L Thompson       CeedChk(ierr);
586eaf62fffSJeremy L Thompson       switch (eval_mode) {
587eaf62fffSJeremy L Thompson       case CEED_EVAL_NONE:
588eaf62fffSJeremy L Thompson       case CEED_EVAL_INTERP:
589eaf62fffSJeremy L Thompson         ierr = CeedRealloc(num_eval_mode_in + 1, &eval_mode_in); CeedChk(ierr);
590eaf62fffSJeremy L Thompson         eval_mode_in[num_eval_mode_in] = eval_mode;
591eaf62fffSJeremy L Thompson         num_eval_mode_in += 1;
592eaf62fffSJeremy L Thompson         break;
593eaf62fffSJeremy L Thompson       case CEED_EVAL_GRAD:
594eaf62fffSJeremy L Thompson         ierr = CeedRealloc(num_eval_mode_in + dim, &eval_mode_in); CeedChk(ierr);
595eaf62fffSJeremy L Thompson         for (CeedInt d=0; d<dim; d++) {
596eaf62fffSJeremy L Thompson           eval_mode_in[num_eval_mode_in+d] = eval_mode;
597eaf62fffSJeremy L Thompson         }
598eaf62fffSJeremy L Thompson         num_eval_mode_in += dim;
599eaf62fffSJeremy L Thompson         break;
600eaf62fffSJeremy L Thompson       case CEED_EVAL_WEIGHT:
601eaf62fffSJeremy L Thompson       case CEED_EVAL_DIV:
602eaf62fffSJeremy L Thompson       case CEED_EVAL_CURL:
603eaf62fffSJeremy L Thompson         break; // Caught by QF Assembly
604eaf62fffSJeremy L Thompson       }
605eaf62fffSJeremy L Thompson     }
606eaf62fffSJeremy L Thompson   }
607eaf62fffSJeremy L Thompson 
608eaf62fffSJeremy L Thompson   // Determine active output basis
6097e7773b5SJeremy L Thompson   ierr = CeedQFunctionGetFields(qf, NULL, NULL, NULL, &qf_fields); CeedChk(ierr);
610eaf62fffSJeremy L Thompson   CeedInt num_eval_mode_out = 0;
611eaf62fffSJeremy L Thompson   CeedEvalMode *eval_mode_out = NULL;
612eaf62fffSJeremy L Thompson   CeedBasis basis_out = NULL;
613eaf62fffSJeremy L Thompson   CeedElemRestriction rstr_out = NULL;
614eaf62fffSJeremy L Thompson   for (CeedInt i=0; i<num_output_fields; i++) {
615eaf62fffSJeremy L Thompson     CeedVector vec;
616eaf62fffSJeremy L Thompson     ierr = CeedOperatorFieldGetVector(output_fields[i], &vec); CeedChk(ierr);
617eaf62fffSJeremy L Thompson     if (vec == CEED_VECTOR_ACTIVE) {
618eaf62fffSJeremy L Thompson       ierr = CeedOperatorFieldGetBasis(output_fields[i], &basis_out);
619eaf62fffSJeremy L Thompson       CeedChk(ierr);
620eaf62fffSJeremy L Thompson       ierr = CeedOperatorFieldGetElemRestriction(output_fields[i], &rstr_out);
621eaf62fffSJeremy L Thompson       CeedChk(ierr);
622eaf62fffSJeremy L Thompson       CeedEvalMode eval_mode;
623eaf62fffSJeremy L Thompson       ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode);
624eaf62fffSJeremy L Thompson       CeedChk(ierr);
625eaf62fffSJeremy L Thompson       switch (eval_mode) {
626eaf62fffSJeremy L Thompson       case CEED_EVAL_NONE:
627eaf62fffSJeremy L Thompson       case CEED_EVAL_INTERP:
628eaf62fffSJeremy L Thompson         ierr = CeedRealloc(num_eval_mode_out + 1, &eval_mode_out); CeedChk(ierr);
629eaf62fffSJeremy L Thompson         eval_mode_out[num_eval_mode_out] = eval_mode;
630eaf62fffSJeremy L Thompson         num_eval_mode_out += 1;
631eaf62fffSJeremy L Thompson         break;
632eaf62fffSJeremy L Thompson       case CEED_EVAL_GRAD:
633eaf62fffSJeremy L Thompson         ierr = CeedRealloc(num_eval_mode_out + dim, &eval_mode_out); CeedChk(ierr);
634eaf62fffSJeremy L Thompson         for (CeedInt d=0; d<dim; d++) {
635eaf62fffSJeremy L Thompson           eval_mode_out[num_eval_mode_out+d] = eval_mode;
636eaf62fffSJeremy L Thompson         }
637eaf62fffSJeremy L Thompson         num_eval_mode_out += dim;
638eaf62fffSJeremy L Thompson         break;
639eaf62fffSJeremy L Thompson       case CEED_EVAL_WEIGHT:
640eaf62fffSJeremy L Thompson       case CEED_EVAL_DIV:
641eaf62fffSJeremy L Thompson       case CEED_EVAL_CURL:
642eaf62fffSJeremy L Thompson         break; // Caught by QF Assembly
643eaf62fffSJeremy L Thompson       }
644eaf62fffSJeremy L Thompson     }
645eaf62fffSJeremy L Thompson   }
646eaf62fffSJeremy L Thompson 
647eaf62fffSJeremy L Thompson   if (num_eval_mode_in == 0 || num_eval_mode_out == 0)
648eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
649eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
650eaf62fffSJeremy L Thompson                      "Cannot assemble operator with out inputs/outputs");
651eaf62fffSJeremy L Thompson   // LCOV_EXCL_STOP
652eaf62fffSJeremy L Thompson 
653eaf62fffSJeremy L Thompson   CeedInt num_elem, elem_size, num_qpts, num_comp;
654eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetNumElements(rstr_in, &num_elem); CeedChk(ierr);
655eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstr_in, &elem_size); CeedChk(ierr);
656eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetNumComponents(rstr_in, &num_comp); CeedChk(ierr);
657eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts); CeedChk(ierr);
658eaf62fffSJeremy L Thompson 
659eaf62fffSJeremy L Thompson   CeedInt local_num_entries = elem_size*num_comp * elem_size*num_comp * num_elem;
660eaf62fffSJeremy L Thompson 
661eaf62fffSJeremy L Thompson   // loop over elements and put in data structure
662eaf62fffSJeremy L Thompson   const CeedScalar *interp_in, *grad_in;
663eaf62fffSJeremy L Thompson   ierr = CeedBasisGetInterp(basis_in, &interp_in); CeedChk(ierr);
664eaf62fffSJeremy L Thompson   ierr = CeedBasisGetGrad(basis_in, &grad_in); CeedChk(ierr);
665eaf62fffSJeremy L Thompson 
666eaf62fffSJeremy L Thompson   const CeedScalar *assembled_qf_array;
667eaf62fffSJeremy L Thompson   ierr = CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array);
668eaf62fffSJeremy L Thompson   CeedChk(ierr);
669eaf62fffSJeremy L Thompson 
670eaf62fffSJeremy L Thompson   CeedInt layout_qf[3];
671eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetELayout(rstr_q, &layout_qf); CeedChk(ierr);
672eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionDestroy(&rstr_q); CeedChk(ierr);
673eaf62fffSJeremy L Thompson 
674eaf62fffSJeremy L Thompson   // we store B_mat_in, B_mat_out, BTD, elem_mat in row-major order
675eaf62fffSJeremy L Thompson   CeedScalar B_mat_in[(num_qpts * num_eval_mode_in) * elem_size];
676eaf62fffSJeremy L Thompson   CeedScalar B_mat_out[(num_qpts * num_eval_mode_out) * elem_size];
677eaf62fffSJeremy L Thompson   CeedScalar D_mat[num_eval_mode_out * num_eval_mode_in *
678eaf62fffSJeremy L Thompson                                      num_qpts]; // logically 3-tensor
679eaf62fffSJeremy L Thompson   CeedScalar BTD[elem_size * num_qpts*num_eval_mode_in];
680eaf62fffSJeremy L Thompson   CeedScalar elem_mat[elem_size * elem_size];
681eaf62fffSJeremy L Thompson   int count = 0;
682eaf62fffSJeremy L Thompson   CeedScalar *vals;
683*9c774eddSJeremy L Thompson   ierr = CeedVectorGetArrayWrite(values, CEED_MEM_HOST, &vals); CeedChk(ierr);
684eaf62fffSJeremy L Thompson   for (int e = 0; e < num_elem; ++e) {
685eaf62fffSJeremy L Thompson     for (int comp_in = 0; comp_in < num_comp; ++comp_in) {
686eaf62fffSJeremy L Thompson       for (int comp_out = 0; comp_out < num_comp; ++comp_out) {
687eaf62fffSJeremy L Thompson         for (int ell = 0; ell < (num_qpts * num_eval_mode_in) * elem_size; ++ell) {
688eaf62fffSJeremy L Thompson           B_mat_in[ell] = 0.0;
689eaf62fffSJeremy L Thompson         }
690eaf62fffSJeremy L Thompson         for (int ell = 0; ell < (num_qpts * num_eval_mode_out) * elem_size; ++ell) {
691eaf62fffSJeremy L Thompson           B_mat_out[ell] = 0.0;
692eaf62fffSJeremy L Thompson         }
693eaf62fffSJeremy L Thompson         // Store block-diagonal D matrix as collection of small dense blocks
694eaf62fffSJeremy L Thompson         for (int ell = 0; ell < num_eval_mode_in*num_eval_mode_out*num_qpts; ++ell) {
695eaf62fffSJeremy L Thompson           D_mat[ell] = 0.0;
696eaf62fffSJeremy L Thompson         }
697eaf62fffSJeremy L Thompson         // form element matrix itself (for each block component)
698eaf62fffSJeremy L Thompson         for (int ell = 0; ell < elem_size*elem_size; ++ell) {
699eaf62fffSJeremy L Thompson           elem_mat[ell] = 0.0;
700eaf62fffSJeremy L Thompson         }
701eaf62fffSJeremy L Thompson         for (int q = 0; q < num_qpts; ++q) {
702eaf62fffSJeremy L Thompson           for (int n = 0; n < elem_size; ++n) {
703eaf62fffSJeremy L Thompson             CeedInt d_in = -1;
704eaf62fffSJeremy L Thompson             for (int e_in = 0; e_in < num_eval_mode_in; ++e_in) {
705eaf62fffSJeremy L Thompson               const int qq = num_eval_mode_in*q;
706eaf62fffSJeremy L Thompson               if (eval_mode_in[e_in] == CEED_EVAL_INTERP) {
707eaf62fffSJeremy L Thompson                 B_mat_in[(qq+e_in)*elem_size + n] += interp_in[q * elem_size + n];
708eaf62fffSJeremy L Thompson               } else if (eval_mode_in[e_in] == CEED_EVAL_GRAD) {
709eaf62fffSJeremy L Thompson                 d_in += 1;
710eaf62fffSJeremy L Thompson                 B_mat_in[(qq+e_in)*elem_size + n] +=
711eaf62fffSJeremy L Thompson                   grad_in[(d_in*num_qpts+q) * elem_size + n];
712eaf62fffSJeremy L Thompson               } else {
713eaf62fffSJeremy L Thompson                 // LCOV_EXCL_START
714eaf62fffSJeremy L Thompson                 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!");
715eaf62fffSJeremy L Thompson                 // LCOV_EXCL_STOP
716eaf62fffSJeremy L Thompson               }
717eaf62fffSJeremy L Thompson             }
718eaf62fffSJeremy L Thompson             CeedInt d_out = -1;
719eaf62fffSJeremy L Thompson             for (int e_out = 0; e_out < num_eval_mode_out; ++e_out) {
720eaf62fffSJeremy L Thompson               const int qq = num_eval_mode_out*q;
721eaf62fffSJeremy L Thompson               if (eval_mode_out[e_out] == CEED_EVAL_INTERP) {
722eaf62fffSJeremy L Thompson                 B_mat_out[(qq+e_out)*elem_size + n] += interp_in[q * elem_size + n];
723eaf62fffSJeremy L Thompson               } else if (eval_mode_out[e_out] == CEED_EVAL_GRAD) {
724eaf62fffSJeremy L Thompson                 d_out += 1;
725eaf62fffSJeremy L Thompson                 B_mat_out[(qq+e_out)*elem_size + n] +=
726eaf62fffSJeremy L Thompson                   grad_in[(d_out*num_qpts+q) * elem_size + n];
727eaf62fffSJeremy L Thompson               } else {
728eaf62fffSJeremy L Thompson                 // LCOV_EXCL_START
729eaf62fffSJeremy L Thompson                 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!");
730eaf62fffSJeremy L Thompson                 // LCOV_EXCL_STOP
731eaf62fffSJeremy L Thompson               }
732eaf62fffSJeremy L Thompson             }
733eaf62fffSJeremy L Thompson           }
734eaf62fffSJeremy L Thompson           for (int ei = 0; ei < num_eval_mode_out; ++ei) {
735eaf62fffSJeremy L Thompson             for (int ej = 0; ej < num_eval_mode_in; ++ej) {
736eaf62fffSJeremy L Thompson               const int eval_mode_index = ((ei*num_comp+comp_in)*num_eval_mode_in+ej)*num_comp
737eaf62fffSJeremy L Thompson                                           +comp_out;
738eaf62fffSJeremy L Thompson               const int index = q*layout_qf[0] + eval_mode_index*layout_qf[1] +
739eaf62fffSJeremy L Thompson                                 e*layout_qf[2];
740eaf62fffSJeremy L Thompson               D_mat[(ei*num_eval_mode_in+ej)*num_qpts + q] += assembled_qf_array[index];
741eaf62fffSJeremy L Thompson             }
742eaf62fffSJeremy L Thompson           }
743eaf62fffSJeremy L Thompson         }
744eaf62fffSJeremy L Thompson         // Compute B^T*D
745eaf62fffSJeremy L Thompson         for (int ell = 0; ell < elem_size*num_qpts*num_eval_mode_in; ++ell) {
746eaf62fffSJeremy L Thompson           BTD[ell] = 0.0;
747eaf62fffSJeremy L Thompson         }
748eaf62fffSJeremy L Thompson         for (int j = 0; j<elem_size; ++j) {
749eaf62fffSJeremy L Thompson           for (int q = 0; q<num_qpts; ++q) {
750eaf62fffSJeremy L Thompson             int qq = num_eval_mode_out*q;
751eaf62fffSJeremy L Thompson             for (int ei = 0; ei < num_eval_mode_in; ++ei) {
752eaf62fffSJeremy L Thompson               for (int ej = 0; ej < num_eval_mode_out; ++ej) {
753eaf62fffSJeremy L Thompson                 BTD[j*(num_qpts*num_eval_mode_in) + (qq+ei)] +=
754eaf62fffSJeremy L Thompson                   B_mat_out[(qq+ej)*elem_size + j] * D_mat[(ei*num_eval_mode_in+ej)*num_qpts + q];
755eaf62fffSJeremy L Thompson               }
756eaf62fffSJeremy L Thompson             }
757eaf62fffSJeremy L Thompson           }
758eaf62fffSJeremy L Thompson         }
759eaf62fffSJeremy L Thompson 
760eaf62fffSJeremy L Thompson         ierr = CeedMatrixMultiply(ceed, BTD, B_mat_in, elem_mat, elem_size,
761eaf62fffSJeremy L Thompson                                   elem_size, num_qpts*num_eval_mode_in); CeedChk(ierr);
762eaf62fffSJeremy L Thompson 
763eaf62fffSJeremy L Thompson         // put element matrix in coordinate data structure
764eaf62fffSJeremy L Thompson         for (int i = 0; i < elem_size; ++i) {
765eaf62fffSJeremy L Thompson           for (int j = 0; j < elem_size; ++j) {
766eaf62fffSJeremy L Thompson             vals[offset + count] = elem_mat[i*elem_size + j];
767eaf62fffSJeremy L Thompson             count++;
768eaf62fffSJeremy L Thompson           }
769eaf62fffSJeremy L Thompson         }
770eaf62fffSJeremy L Thompson       }
771eaf62fffSJeremy L Thompson     }
772eaf62fffSJeremy L Thompson   }
773eaf62fffSJeremy L Thompson   if (count != local_num_entries)
774eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
775eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing entries");
776eaf62fffSJeremy L Thompson   // LCOV_EXCL_STOP
777eaf62fffSJeremy L Thompson   ierr = CeedVectorRestoreArray(values, &vals); CeedChk(ierr);
778eaf62fffSJeremy L Thompson 
779eaf62fffSJeremy L Thompson   ierr = CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array);
780eaf62fffSJeremy L Thompson   CeedChk(ierr);
781eaf62fffSJeremy L Thompson   ierr = CeedVectorDestroy(&assembled_qf); CeedChk(ierr);
782eaf62fffSJeremy L Thompson   ierr = CeedFree(&eval_mode_in); CeedChk(ierr);
783eaf62fffSJeremy L Thompson   ierr = CeedFree(&eval_mode_out); CeedChk(ierr);
784eaf62fffSJeremy L Thompson 
785eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
786eaf62fffSJeremy L Thompson }
787eaf62fffSJeremy L Thompson 
788eaf62fffSJeremy L Thompson /**
789eaf62fffSJeremy L Thompson   @brief Count number of entries for assembled CeedOperator
790eaf62fffSJeremy L Thompson 
791eaf62fffSJeremy L Thompson   @param[in] op            CeedOperator to assemble
792eaf62fffSJeremy L Thompson   @param[out] num_entries  Number of entries in assembled representation
793eaf62fffSJeremy L Thompson 
794eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
795eaf62fffSJeremy L Thompson 
796eaf62fffSJeremy L Thompson   @ref Utility
797eaf62fffSJeremy L Thompson **/
798eaf62fffSJeremy L Thompson static int CeedSingleOperatorAssemblyCountEntries(CeedOperator op,
799eaf62fffSJeremy L Thompson     CeedInt *num_entries) {
800eaf62fffSJeremy L Thompson   int ierr;
801eaf62fffSJeremy L Thompson   CeedElemRestriction rstr;
802eaf62fffSJeremy L Thompson   CeedInt num_elem, elem_size, num_comp;
803eaf62fffSJeremy L Thompson 
804f04ea552SJeremy L Thompson   if (op->is_composite)
805eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
806eaf62fffSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
807eaf62fffSJeremy L Thompson                      "Composite operator not supported");
808eaf62fffSJeremy L Thompson   // LCOV_EXCL_STOP
809eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetActiveElemRestriction(op, &rstr); CeedChk(ierr);
810eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr);
811eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstr, &elem_size); CeedChk(ierr);
812eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetNumComponents(rstr, &num_comp); CeedChk(ierr);
813eaf62fffSJeremy L Thompson   *num_entries = elem_size*num_comp * elem_size*num_comp * num_elem;
814eaf62fffSJeremy L Thompson 
815eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
816eaf62fffSJeremy L Thompson }
817eaf62fffSJeremy L Thompson 
818eaf62fffSJeremy L Thompson /**
819eaf62fffSJeremy L Thompson   @brief Common code for creating a multigrid coarse operator and level
820eaf62fffSJeremy L Thompson            transfer operators for a CeedOperator
821eaf62fffSJeremy L Thompson 
822eaf62fffSJeremy L Thompson   @param[in] op_fine       Fine grid operator
823eaf62fffSJeremy L Thompson   @param[in] p_mult_fine   L-vector multiplicity in parallel gather/scatter
824eaf62fffSJeremy L Thompson   @param[in] rstr_coarse   Coarse grid restriction
825eaf62fffSJeremy L Thompson   @param[in] basis_coarse  Coarse grid active vector basis
826eaf62fffSJeremy L Thompson   @param[in] basis_c_to_f  Basis for coarse to fine interpolation
827eaf62fffSJeremy L Thompson   @param[out] op_coarse    Coarse grid operator
828eaf62fffSJeremy L Thompson   @param[out] op_prolong   Coarse to fine operator
829eaf62fffSJeremy L Thompson   @param[out] op_restrict  Fine to coarse operator
830eaf62fffSJeremy L Thompson 
831eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
832eaf62fffSJeremy L Thompson 
833eaf62fffSJeremy L Thompson   @ref Developer
834eaf62fffSJeremy L Thompson **/
835eaf62fffSJeremy L Thompson static int CeedSingleOperatorMultigridLevel(CeedOperator op_fine,
836eaf62fffSJeremy L Thompson     CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse,
837eaf62fffSJeremy L Thompson     CeedBasis basis_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong,
838eaf62fffSJeremy L Thompson     CeedOperator *op_restrict) {
839eaf62fffSJeremy L Thompson   int ierr;
840eaf62fffSJeremy L Thompson   Ceed ceed;
841eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
842eaf62fffSJeremy L Thompson 
843eaf62fffSJeremy L Thompson   // Check for composite operator
844eaf62fffSJeremy L Thompson   bool is_composite;
845eaf62fffSJeremy L Thompson   ierr = CeedOperatorIsComposite(op_fine, &is_composite); CeedChk(ierr);
846eaf62fffSJeremy L Thompson   if (is_composite)
847eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
848eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
849eaf62fffSJeremy L Thompson                      "Automatic multigrid setup for composite operators not supported");
850eaf62fffSJeremy L Thompson   // LCOV_EXCL_STOP
851eaf62fffSJeremy L Thompson 
852eaf62fffSJeremy L Thompson   // Coarse Grid
853eaf62fffSJeremy L Thompson   ierr = CeedOperatorCreate(ceed, op_fine->qf, op_fine->dqf, op_fine->dqfT,
854eaf62fffSJeremy L Thompson                             op_coarse); CeedChk(ierr);
855eaf62fffSJeremy L Thompson   CeedElemRestriction rstr_fine = NULL;
856eaf62fffSJeremy L Thompson   // -- Clone input fields
857eaf62fffSJeremy L Thompson   for (int i = 0; i < op_fine->qf->num_input_fields; i++) {
858eaf62fffSJeremy L Thompson     if (op_fine->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
859eaf62fffSJeremy L Thompson       rstr_fine = op_fine->input_fields[i]->elem_restr;
860eaf62fffSJeremy L Thompson       ierr = CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name,
861eaf62fffSJeremy L Thompson                                   rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE);
862eaf62fffSJeremy L Thompson       CeedChk(ierr);
863eaf62fffSJeremy L Thompson     } else {
864eaf62fffSJeremy L Thompson       ierr = CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name,
865eaf62fffSJeremy L Thompson                                   op_fine->input_fields[i]->elem_restr,
866eaf62fffSJeremy L Thompson                                   op_fine->input_fields[i]->basis,
867eaf62fffSJeremy L Thompson                                   op_fine->input_fields[i]->vec); CeedChk(ierr);
868eaf62fffSJeremy L Thompson     }
869eaf62fffSJeremy L Thompson   }
870eaf62fffSJeremy L Thompson   // -- Clone output fields
871eaf62fffSJeremy L Thompson   for (int i = 0; i < op_fine->qf->num_output_fields; i++) {
872eaf62fffSJeremy L Thompson     if (op_fine->output_fields[i]->vec == CEED_VECTOR_ACTIVE) {
873eaf62fffSJeremy L Thompson       ierr = CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name,
874eaf62fffSJeremy L Thompson                                   rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE);
875eaf62fffSJeremy L Thompson       CeedChk(ierr);
876eaf62fffSJeremy L Thompson     } else {
877eaf62fffSJeremy L Thompson       ierr = CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name,
878eaf62fffSJeremy L Thompson                                   op_fine->output_fields[i]->elem_restr,
879eaf62fffSJeremy L Thompson                                   op_fine->output_fields[i]->basis,
880eaf62fffSJeremy L Thompson                                   op_fine->output_fields[i]->vec); CeedChk(ierr);
881eaf62fffSJeremy L Thompson     }
882eaf62fffSJeremy L Thompson   }
883eaf62fffSJeremy L Thompson 
884eaf62fffSJeremy L Thompson   // Multiplicity vector
885eaf62fffSJeremy L Thompson   CeedVector mult_vec, mult_e_vec;
886eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionCreateVector(rstr_fine, &mult_vec, &mult_e_vec);
887eaf62fffSJeremy L Thompson   CeedChk(ierr);
888eaf62fffSJeremy L Thompson   ierr = CeedVectorSetValue(mult_e_vec, 0.0); CeedChk(ierr);
889eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionApply(rstr_fine, CEED_NOTRANSPOSE, p_mult_fine,
890eaf62fffSJeremy L Thompson                                   mult_e_vec, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
891eaf62fffSJeremy L Thompson   ierr = CeedVectorSetValue(mult_vec, 0.0); CeedChk(ierr);
892eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionApply(rstr_fine, CEED_TRANSPOSE, mult_e_vec, mult_vec,
893eaf62fffSJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
894eaf62fffSJeremy L Thompson   ierr = CeedVectorDestroy(&mult_e_vec); CeedChk(ierr);
895eaf62fffSJeremy L Thompson   ierr = CeedVectorReciprocal(mult_vec); CeedChk(ierr);
896eaf62fffSJeremy L Thompson 
897eaf62fffSJeremy L Thompson   // Restriction
898eaf62fffSJeremy L Thompson   CeedInt num_comp;
899eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumComponents(basis_coarse, &num_comp); CeedChk(ierr);
900eaf62fffSJeremy L Thompson   CeedQFunction qf_restrict;
901eaf62fffSJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_restrict);
902eaf62fffSJeremy L Thompson   CeedChk(ierr);
903eaf62fffSJeremy L Thompson   CeedInt *num_comp_r_data;
904eaf62fffSJeremy L Thompson   ierr = CeedCalloc(1, &num_comp_r_data); CeedChk(ierr);
905eaf62fffSJeremy L Thompson   num_comp_r_data[0] = num_comp;
906eaf62fffSJeremy L Thompson   CeedQFunctionContext ctx_r;
907eaf62fffSJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctx_r); CeedChk(ierr);
908eaf62fffSJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctx_r, CEED_MEM_HOST, CEED_OWN_POINTER,
909eaf62fffSJeremy L Thompson                                      sizeof(*num_comp_r_data), num_comp_r_data);
910eaf62fffSJeremy L Thompson   CeedChk(ierr);
911eaf62fffSJeremy L Thompson   ierr = CeedQFunctionSetContext(qf_restrict, ctx_r); CeedChk(ierr);
912eaf62fffSJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctx_r); CeedChk(ierr);
913eaf62fffSJeremy L Thompson   ierr = CeedQFunctionAddInput(qf_restrict, "input", num_comp, CEED_EVAL_NONE);
914eaf62fffSJeremy L Thompson   CeedChk(ierr);
915eaf62fffSJeremy L Thompson   ierr = CeedQFunctionAddInput(qf_restrict, "scale", num_comp, CEED_EVAL_NONE);
916eaf62fffSJeremy L Thompson   CeedChk(ierr);
917eaf62fffSJeremy L Thompson   ierr = CeedQFunctionAddOutput(qf_restrict, "output", num_comp,
918eaf62fffSJeremy L Thompson                                 CEED_EVAL_INTERP); CeedChk(ierr);
919eaf62fffSJeremy L Thompson 
920eaf62fffSJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qf_restrict, CEED_QFUNCTION_NONE,
921eaf62fffSJeremy L Thompson                             CEED_QFUNCTION_NONE, op_restrict);
922eaf62fffSJeremy L Thompson   CeedChk(ierr);
923eaf62fffSJeremy L Thompson   ierr = CeedOperatorSetField(*op_restrict, "input", rstr_fine,
924eaf62fffSJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
925eaf62fffSJeremy L Thompson   CeedChk(ierr);
926eaf62fffSJeremy L Thompson   ierr = CeedOperatorSetField(*op_restrict, "scale", rstr_fine,
927eaf62fffSJeremy L Thompson                               CEED_BASIS_COLLOCATED, mult_vec);
928eaf62fffSJeremy L Thompson   CeedChk(ierr);
929eaf62fffSJeremy L Thompson   ierr = CeedOperatorSetField(*op_restrict, "output", rstr_coarse, basis_c_to_f,
930eaf62fffSJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
931eaf62fffSJeremy L Thompson 
932eaf62fffSJeremy L Thompson   // Prolongation
933eaf62fffSJeremy L Thompson   CeedQFunction qf_prolong;
934eaf62fffSJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_prolong);
935eaf62fffSJeremy L Thompson   CeedChk(ierr);
936eaf62fffSJeremy L Thompson   CeedInt *num_comp_p_data;
937eaf62fffSJeremy L Thompson   ierr = CeedCalloc(1, &num_comp_p_data); CeedChk(ierr);
938eaf62fffSJeremy L Thompson   num_comp_p_data[0] = num_comp;
939eaf62fffSJeremy L Thompson   CeedQFunctionContext ctx_p;
940eaf62fffSJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctx_p); CeedChk(ierr);
941eaf62fffSJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctx_p, CEED_MEM_HOST, CEED_OWN_POINTER,
942eaf62fffSJeremy L Thompson                                      sizeof(*num_comp_p_data), num_comp_p_data);
943eaf62fffSJeremy L Thompson   CeedChk(ierr);
944eaf62fffSJeremy L Thompson   ierr = CeedQFunctionSetContext(qf_prolong, ctx_p); CeedChk(ierr);
945eaf62fffSJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctx_p); CeedChk(ierr);
946eaf62fffSJeremy L Thompson   ierr = CeedQFunctionAddInput(qf_prolong, "input", num_comp, CEED_EVAL_INTERP);
947eaf62fffSJeremy L Thompson   CeedChk(ierr);
948eaf62fffSJeremy L Thompson   ierr = CeedQFunctionAddInput(qf_prolong, "scale", num_comp, CEED_EVAL_NONE);
949eaf62fffSJeremy L Thompson   CeedChk(ierr);
950eaf62fffSJeremy L Thompson   ierr = CeedQFunctionAddOutput(qf_prolong, "output", num_comp, CEED_EVAL_NONE);
951eaf62fffSJeremy L Thompson   CeedChk(ierr);
952eaf62fffSJeremy L Thompson 
953eaf62fffSJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qf_prolong, CEED_QFUNCTION_NONE,
954eaf62fffSJeremy L Thompson                             CEED_QFUNCTION_NONE, op_prolong);
955eaf62fffSJeremy L Thompson   CeedChk(ierr);
956eaf62fffSJeremy L Thompson   ierr = CeedOperatorSetField(*op_prolong, "input", rstr_coarse, basis_c_to_f,
957eaf62fffSJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
958eaf62fffSJeremy L Thompson   ierr = CeedOperatorSetField(*op_prolong, "scale", rstr_fine,
959eaf62fffSJeremy L Thompson                               CEED_BASIS_COLLOCATED, mult_vec);
960eaf62fffSJeremy L Thompson   CeedChk(ierr);
961eaf62fffSJeremy L Thompson   ierr = CeedOperatorSetField(*op_prolong, "output", rstr_fine,
962eaf62fffSJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
963eaf62fffSJeremy L Thompson   CeedChk(ierr);
964eaf62fffSJeremy L Thompson 
965eaf62fffSJeremy L Thompson   // Cleanup
966eaf62fffSJeremy L Thompson   ierr = CeedVectorDestroy(&mult_vec); CeedChk(ierr);
967eaf62fffSJeremy L Thompson   ierr = CeedBasisDestroy(&basis_c_to_f); CeedChk(ierr);
968eaf62fffSJeremy L Thompson   ierr = CeedQFunctionDestroy(&qf_restrict); CeedChk(ierr);
969eaf62fffSJeremy L Thompson   ierr = CeedQFunctionDestroy(&qf_prolong); CeedChk(ierr);
970eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
971eaf62fffSJeremy L Thompson }
972eaf62fffSJeremy L Thompson 
973eaf62fffSJeremy L Thompson /**
974eaf62fffSJeremy L Thompson   @brief Build 1D mass matrix and Laplacian with perturbation
975eaf62fffSJeremy L Thompson 
976eaf62fffSJeremy L Thompson   @param[in] interp_1d    Interpolation matrix in one dimension
977eaf62fffSJeremy L Thompson   @param[in] grad_1d      Gradient matrix in one dimension
978eaf62fffSJeremy L Thompson   @param[in] q_weight_1d  Quadrature weights in one dimension
979eaf62fffSJeremy L Thompson   @param[in] P_1d         Number of basis nodes in one dimension
980eaf62fffSJeremy L Thompson   @param[in] Q_1d         Number of quadrature points in one dimension
981eaf62fffSJeremy L Thompson   @param[in] dim          Dimension of basis
982eaf62fffSJeremy L Thompson   @param[out] mass        Assembled mass matrix in one dimension
983eaf62fffSJeremy L Thompson   @param[out] laplace     Assembled perturbed Laplacian in one dimension
984eaf62fffSJeremy L Thompson 
985eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
986eaf62fffSJeremy L Thompson 
987eaf62fffSJeremy L Thompson   @ref Developer
988eaf62fffSJeremy L Thompson **/
989eaf62fffSJeremy L Thompson CeedPragmaOptimizeOff
990eaf62fffSJeremy L Thompson static int CeedBuildMassLaplace(const CeedScalar *interp_1d,
991eaf62fffSJeremy L Thompson                                 const CeedScalar *grad_1d,
992eaf62fffSJeremy L Thompson                                 const CeedScalar *q_weight_1d, CeedInt P_1d,
993eaf62fffSJeremy L Thompson                                 CeedInt Q_1d, CeedInt dim,
994eaf62fffSJeremy L Thompson                                 CeedScalar *mass, CeedScalar *laplace) {
995eaf62fffSJeremy L Thompson 
996eaf62fffSJeremy L Thompson   for (CeedInt i=0; i<P_1d; i++)
997eaf62fffSJeremy L Thompson     for (CeedInt j=0; j<P_1d; j++) {
998eaf62fffSJeremy L Thompson       CeedScalar sum = 0.0;
999eaf62fffSJeremy L Thompson       for (CeedInt k=0; k<Q_1d; k++)
1000eaf62fffSJeremy L Thompson         sum += interp_1d[k*P_1d+i]*q_weight_1d[k]*interp_1d[k*P_1d+j];
1001eaf62fffSJeremy L Thompson       mass[i+j*P_1d] = sum;
1002eaf62fffSJeremy L Thompson     }
1003eaf62fffSJeremy L Thompson   // -- Laplacian
1004eaf62fffSJeremy L Thompson   for (CeedInt i=0; i<P_1d; i++)
1005eaf62fffSJeremy L Thompson     for (CeedInt j=0; j<P_1d; j++) {
1006eaf62fffSJeremy L Thompson       CeedScalar sum = 0.0;
1007eaf62fffSJeremy L Thompson       for (CeedInt k=0; k<Q_1d; k++)
1008eaf62fffSJeremy L Thompson         sum += grad_1d[k*P_1d+i]*q_weight_1d[k]*grad_1d[k*P_1d+j];
1009eaf62fffSJeremy L Thompson       laplace[i+j*P_1d] = sum;
1010eaf62fffSJeremy L Thompson     }
1011eaf62fffSJeremy L Thompson   CeedScalar perturbation = dim>2 ? 1e-6 : 1e-4;
1012eaf62fffSJeremy L Thompson   for (CeedInt i=0; i<P_1d; i++)
1013eaf62fffSJeremy L Thompson     laplace[i+P_1d*i] += perturbation;
1014eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1015eaf62fffSJeremy L Thompson }
1016eaf62fffSJeremy L Thompson CeedPragmaOptimizeOn
1017eaf62fffSJeremy L Thompson 
1018eaf62fffSJeremy L Thompson /// @}
1019eaf62fffSJeremy L Thompson 
1020eaf62fffSJeremy L Thompson /// ----------------------------------------------------------------------------
1021eaf62fffSJeremy L Thompson /// CeedOperator Public API
1022eaf62fffSJeremy L Thompson /// ----------------------------------------------------------------------------
1023eaf62fffSJeremy L Thompson /// @addtogroup CeedOperatorUser
1024eaf62fffSJeremy L Thompson /// @{
1025eaf62fffSJeremy L Thompson 
1026eaf62fffSJeremy L Thompson /**
1027eaf62fffSJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
1028eaf62fffSJeremy L Thompson 
1029eaf62fffSJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
1030eaf62fffSJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
1031eaf62fffSJeremy L Thompson     The vector 'assembled' is of shape
1032eaf62fffSJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
1033eaf62fffSJeremy L Thompson     and contains column-major matrices representing the action of the
1034eaf62fffSJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
1035eaf62fffSJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
1036eaf62fffSJeremy L Thompson     For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
1037eaf62fffSJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
1038eaf62fffSJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
1039eaf62fffSJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
1040eaf62fffSJeremy L Thompson 
1041f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1042f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1043f04ea552SJeremy L Thompson 
1044eaf62fffSJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
1045eaf62fffSJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedQFunction at
1046eaf62fffSJeremy L Thompson                            quadrature points
1047eaf62fffSJeremy L Thompson   @param[out] rstr       CeedElemRestriction for CeedVector containing assembled
1048eaf62fffSJeremy L Thompson                            CeedQFunction
1049eaf62fffSJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
1050eaf62fffSJeremy L Thompson                            @ref CEED_REQUEST_IMMEDIATE
1051eaf62fffSJeremy L Thompson 
1052eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1053eaf62fffSJeremy L Thompson 
1054eaf62fffSJeremy L Thompson   @ref User
1055eaf62fffSJeremy L Thompson **/
1056eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled,
1057eaf62fffSJeremy L Thompson                                         CeedElemRestriction *rstr,
1058eaf62fffSJeremy L Thompson                                         CeedRequest *request) {
1059eaf62fffSJeremy L Thompson   int ierr;
1060eaf62fffSJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1061eaf62fffSJeremy L Thompson 
1062eaf62fffSJeremy L Thompson   // Backend version
1063eaf62fffSJeremy L Thompson   if (op->LinearAssembleQFunction) {
106470a7ffb3SJeremy L Thompson     ierr = op->LinearAssembleQFunction(op, assembled, rstr, request);
106570a7ffb3SJeremy L Thompson     CeedChk(ierr);
1066eaf62fffSJeremy L Thompson   } else {
1067eaf62fffSJeremy L Thompson     // Fallback to reference Ceed
1068eaf62fffSJeremy L Thompson     if (!op->op_fallback) {
1069eaf62fffSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1070eaf62fffSJeremy L Thompson     }
1071eaf62fffSJeremy L Thompson     // Assemble
1072eaf62fffSJeremy L Thompson     ierr = CeedOperatorLinearAssembleQFunction(op->op_fallback, assembled,
1073eaf62fffSJeremy L Thompson            rstr, request); CeedChk(ierr);
107470a7ffb3SJeremy L Thompson   }
1075eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1076eaf62fffSJeremy L Thompson }
107770a7ffb3SJeremy L Thompson 
107870a7ffb3SJeremy L Thompson /**
107970a7ffb3SJeremy L Thompson   @brief Assemble CeedQFunction and store result internall. Return copied
108070a7ffb3SJeremy L Thompson            references of stored data to the caller. Caller is responsible for
108170a7ffb3SJeremy L Thompson            ownership and destruction of the copied references. See also
108270a7ffb3SJeremy L Thompson            @ref CeedOperatorLinearAssembleQFunction
108370a7ffb3SJeremy L Thompson 
108470a7ffb3SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
108570a7ffb3SJeremy L Thompson   @param assembled       CeedVector to store assembled CeedQFunction at
108670a7ffb3SJeremy L Thompson                            quadrature points
108770a7ffb3SJeremy L Thompson   @param rstr            CeedElemRestriction for CeedVector containing assembled
108870a7ffb3SJeremy L Thompson                            CeedQFunction
108970a7ffb3SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
109070a7ffb3SJeremy L Thompson                            @ref CEED_REQUEST_IMMEDIATE
109170a7ffb3SJeremy L Thompson 
109270a7ffb3SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
109370a7ffb3SJeremy L Thompson 
109470a7ffb3SJeremy L Thompson   @ref User
109570a7ffb3SJeremy L Thompson **/
109670a7ffb3SJeremy L Thompson int CeedOperatorLinearAssembleQFunctionBuildOrUpdate(CeedOperator op,
109770a7ffb3SJeremy L Thompson     CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) {
109870a7ffb3SJeremy L Thompson   int ierr;
109970a7ffb3SJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
110070a7ffb3SJeremy L Thompson 
110170a7ffb3SJeremy L Thompson   // Backend version
110270a7ffb3SJeremy L Thompson   if (op->LinearAssembleQFunctionUpdate) {
110370a7ffb3SJeremy L Thompson     if (op->has_qf_assembled) {
110470a7ffb3SJeremy L Thompson       ierr = op->LinearAssembleQFunctionUpdate(op, op->qf_assembled,
110570a7ffb3SJeremy L Thompson              op->qf_assembled_rstr, request);
110670a7ffb3SJeremy L Thompson     } else {
110770a7ffb3SJeremy L Thompson       ierr = op->LinearAssembleQFunction(op, &op->qf_assembled,
110870a7ffb3SJeremy L Thompson                                          &op->qf_assembled_rstr, request);
110970a7ffb3SJeremy L Thompson     }
111070a7ffb3SJeremy L Thompson     CeedChk(ierr);
111170a7ffb3SJeremy L Thompson     op->has_qf_assembled = true;
111270a7ffb3SJeremy L Thompson     // Copy reference to internally held copy
111370a7ffb3SJeremy L Thompson     *assembled = NULL;
111470a7ffb3SJeremy L Thompson     *rstr = NULL;
111570a7ffb3SJeremy L Thompson     ierr = CeedVectorReferenceCopy(op->qf_assembled, assembled); CeedChk(ierr);
111670a7ffb3SJeremy L Thompson     ierr = CeedElemRestrictionReferenceCopy(op->qf_assembled_rstr, rstr);
111770a7ffb3SJeremy L Thompson   } else {
111870a7ffb3SJeremy L Thompson     // Fallback to reference Ceed
111970a7ffb3SJeremy L Thompson     if (!op->op_fallback) {
112070a7ffb3SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
112170a7ffb3SJeremy L Thompson     }
112270a7ffb3SJeremy L Thompson     // Assemble
112370a7ffb3SJeremy L Thompson     ierr = CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op->op_fallback,
112470a7ffb3SJeremy L Thompson            assembled, rstr, request); CeedChk(ierr);
112570a7ffb3SJeremy L Thompson   }
112670a7ffb3SJeremy L Thompson   CeedChk(ierr);
112770a7ffb3SJeremy L Thompson 
112870a7ffb3SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1129eaf62fffSJeremy L Thompson }
1130eaf62fffSJeremy L Thompson 
1131eaf62fffSJeremy L Thompson /**
1132eaf62fffSJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
1133eaf62fffSJeremy L Thompson 
1134eaf62fffSJeremy L Thompson   This overwrites a CeedVector with the diagonal of a linear CeedOperator.
1135eaf62fffSJeremy L Thompson 
1136eaf62fffSJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1137eaf62fffSJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1138eaf62fffSJeremy L Thompson 
1139f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1140f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1141f04ea552SJeremy L Thompson 
1142eaf62fffSJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
1143eaf62fffSJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator diagonal
1144eaf62fffSJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
1145eaf62fffSJeremy L Thompson                            @ref CEED_REQUEST_IMMEDIATE
1146eaf62fffSJeremy L Thompson 
1147eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1148eaf62fffSJeremy L Thompson 
1149eaf62fffSJeremy L Thompson   @ref User
1150eaf62fffSJeremy L Thompson **/
1151eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled,
1152eaf62fffSJeremy L Thompson                                        CeedRequest *request) {
1153eaf62fffSJeremy L Thompson   int ierr;
1154eaf62fffSJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1155eaf62fffSJeremy L Thompson 
1156eaf62fffSJeremy L Thompson   // Use backend version, if available
1157eaf62fffSJeremy L Thompson   if (op->LinearAssembleDiagonal) {
1158eaf62fffSJeremy L Thompson     ierr = op->LinearAssembleDiagonal(op, assembled, request); CeedChk(ierr);
1159eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1160eaf62fffSJeremy L Thompson   } else if (op->LinearAssembleAddDiagonal) {
1161eaf62fffSJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
1162eaf62fffSJeremy L Thompson     ierr = op->LinearAssembleAddDiagonal(op, assembled, request); CeedChk(ierr);
1163eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1164eaf62fffSJeremy L Thompson   } else {
1165eaf62fffSJeremy L Thompson     // Check for valid fallback resource
1166eaf62fffSJeremy L Thompson     const char *resource, *fallback_resource;
1167eaf62fffSJeremy L Thompson     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1168eaf62fffSJeremy L Thompson     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
1169eaf62fffSJeremy L Thompson     CeedChk(ierr);
1170eaf62fffSJeremy L Thompson     if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) {
1171eaf62fffSJeremy L Thompson       // Fallback to reference Ceed
1172eaf62fffSJeremy L Thompson       if (!op->op_fallback) {
1173eaf62fffSJeremy L Thompson         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1174eaf62fffSJeremy L Thompson       }
1175eaf62fffSJeremy L Thompson       // Assemble
1176eaf62fffSJeremy L Thompson       ierr = CeedOperatorLinearAssembleDiagonal(op->op_fallback, assembled, request);
1177eaf62fffSJeremy L Thompson       CeedChk(ierr);
1178eaf62fffSJeremy L Thompson       return CEED_ERROR_SUCCESS;
1179eaf62fffSJeremy L Thompson     }
1180eaf62fffSJeremy L Thompson   }
1181eaf62fffSJeremy L Thompson 
1182eaf62fffSJeremy L Thompson   // Default interface implementation
1183eaf62fffSJeremy L Thompson   ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
1184eaf62fffSJeremy L Thompson   ierr = CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
1185eaf62fffSJeremy L Thompson   CeedChk(ierr);
1186eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1187eaf62fffSJeremy L Thompson }
1188eaf62fffSJeremy L Thompson 
1189eaf62fffSJeremy L Thompson /**
1190eaf62fffSJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
1191eaf62fffSJeremy L Thompson 
1192eaf62fffSJeremy L Thompson   This sums into a CeedVector the diagonal of a linear CeedOperator.
1193eaf62fffSJeremy L Thompson 
1194eaf62fffSJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1195eaf62fffSJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1196eaf62fffSJeremy L Thompson 
1197f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1198f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1199f04ea552SJeremy L Thompson 
1200eaf62fffSJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
1201eaf62fffSJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator diagonal
1202eaf62fffSJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
1203eaf62fffSJeremy L Thompson                            @ref CEED_REQUEST_IMMEDIATE
1204eaf62fffSJeremy L Thompson 
1205eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1206eaf62fffSJeremy L Thompson 
1207eaf62fffSJeremy L Thompson   @ref User
1208eaf62fffSJeremy L Thompson **/
1209eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled,
1210eaf62fffSJeremy L Thompson     CeedRequest *request) {
1211eaf62fffSJeremy L Thompson   int ierr;
1212eaf62fffSJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1213eaf62fffSJeremy L Thompson 
1214eaf62fffSJeremy L Thompson   // Use backend version, if available
1215eaf62fffSJeremy L Thompson   if (op->LinearAssembleAddDiagonal) {
1216eaf62fffSJeremy L Thompson     ierr = op->LinearAssembleAddDiagonal(op, assembled, request); CeedChk(ierr);
1217eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1218eaf62fffSJeremy L Thompson   } else {
1219eaf62fffSJeremy L Thompson     // Check for valid fallback resource
1220eaf62fffSJeremy L Thompson     const char *resource, *fallback_resource;
1221eaf62fffSJeremy L Thompson     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1222eaf62fffSJeremy L Thompson     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
1223eaf62fffSJeremy L Thompson     CeedChk(ierr);
1224eaf62fffSJeremy L Thompson     if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) {
1225eaf62fffSJeremy L Thompson       // Fallback to reference Ceed
1226eaf62fffSJeremy L Thompson       if (!op->op_fallback) {
1227eaf62fffSJeremy L Thompson         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1228eaf62fffSJeremy L Thompson       }
1229eaf62fffSJeremy L Thompson       // Assemble
1230eaf62fffSJeremy L Thompson       ierr = CeedOperatorLinearAssembleAddDiagonal(op->op_fallback, assembled,
1231eaf62fffSJeremy L Thompson              request); CeedChk(ierr);
1232eaf62fffSJeremy L Thompson       return CEED_ERROR_SUCCESS;
1233eaf62fffSJeremy L Thompson     }
1234eaf62fffSJeremy L Thompson   }
1235eaf62fffSJeremy L Thompson 
1236eaf62fffSJeremy L Thompson   // Default interface implementation
1237eaf62fffSJeremy L Thompson   bool is_composite;
1238eaf62fffSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1239eaf62fffSJeremy L Thompson   if (is_composite) {
1240eaf62fffSJeremy L Thompson     ierr = CeedCompositeOperatorLinearAssembleAddDiagonal(op, request,
1241eaf62fffSJeremy L Thompson            false, assembled); CeedChk(ierr);
1242eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1243eaf62fffSJeremy L Thompson   } else {
1244eaf62fffSJeremy L Thompson     ierr = CeedSingleOperatorAssembleAddDiagonal(op, request, false, assembled);
1245eaf62fffSJeremy L Thompson     CeedChk(ierr);
1246eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1247eaf62fffSJeremy L Thompson   }
1248eaf62fffSJeremy L Thompson }
1249eaf62fffSJeremy L Thompson 
1250eaf62fffSJeremy L Thompson /**
1251eaf62fffSJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
1252eaf62fffSJeremy L Thompson 
1253eaf62fffSJeremy L Thompson   This overwrites a CeedVector with the point block diagonal of a linear
1254eaf62fffSJeremy L Thompson     CeedOperator.
1255eaf62fffSJeremy L Thompson 
1256eaf62fffSJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1257eaf62fffSJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1258eaf62fffSJeremy L Thompson 
1259f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1260f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1261f04ea552SJeremy L Thompson 
1262eaf62fffSJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
1263eaf62fffSJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator point block
1264eaf62fffSJeremy L Thompson                            diagonal, provided in row-major form with an
1265eaf62fffSJeremy L Thompson                            @a num_comp * @a num_comp block at each node. The dimensions
1266eaf62fffSJeremy L Thompson                            of this vector are derived from the active vector
1267eaf62fffSJeremy L Thompson                            for the CeedOperator. The array has shape
1268eaf62fffSJeremy L Thompson                            [nodes, component out, component in].
1269eaf62fffSJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
1270eaf62fffSJeremy L Thompson                            CEED_REQUEST_IMMEDIATE
1271eaf62fffSJeremy L Thompson 
1272eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1273eaf62fffSJeremy L Thompson 
1274eaf62fffSJeremy L Thompson   @ref User
1275eaf62fffSJeremy L Thompson **/
1276eaf62fffSJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op,
1277eaf62fffSJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
1278eaf62fffSJeremy L Thompson   int ierr;
1279eaf62fffSJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1280eaf62fffSJeremy L Thompson 
1281eaf62fffSJeremy L Thompson   // Use backend version, if available
1282eaf62fffSJeremy L Thompson   if (op->LinearAssemblePointBlockDiagonal) {
1283eaf62fffSJeremy L Thompson     ierr = op->LinearAssemblePointBlockDiagonal(op, assembled, request);
1284eaf62fffSJeremy L Thompson     CeedChk(ierr);
1285eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1286eaf62fffSJeremy L Thompson   } else if (op->LinearAssembleAddPointBlockDiagonal) {
1287eaf62fffSJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
1288eaf62fffSJeremy L Thompson     ierr = CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
1289eaf62fffSJeremy L Thompson            request); CeedChk(ierr);
1290eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1291eaf62fffSJeremy L Thompson   } else {
1292eaf62fffSJeremy L Thompson     // Check for valid fallback resource
1293eaf62fffSJeremy L Thompson     const char *resource, *fallback_resource;
1294eaf62fffSJeremy L Thompson     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1295eaf62fffSJeremy L Thompson     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
1296eaf62fffSJeremy L Thompson     CeedChk(ierr);
1297eaf62fffSJeremy L Thompson     if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) {
1298eaf62fffSJeremy L Thompson       // Fallback to reference Ceed
1299eaf62fffSJeremy L Thompson       if (!op->op_fallback) {
1300eaf62fffSJeremy L Thompson         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1301eaf62fffSJeremy L Thompson       }
1302eaf62fffSJeremy L Thompson       // Assemble
1303eaf62fffSJeremy L Thompson       ierr = CeedOperatorLinearAssemblePointBlockDiagonal(op->op_fallback,
1304eaf62fffSJeremy L Thompson              assembled, request); CeedChk(ierr);
1305eaf62fffSJeremy L Thompson       return CEED_ERROR_SUCCESS;
1306eaf62fffSJeremy L Thompson     }
1307eaf62fffSJeremy L Thompson   }
1308eaf62fffSJeremy L Thompson 
1309eaf62fffSJeremy L Thompson   // Default interface implementation
1310eaf62fffSJeremy L Thompson   ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
1311eaf62fffSJeremy L Thompson   ierr = CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, request);
1312eaf62fffSJeremy L Thompson   CeedChk(ierr);
1313eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1314eaf62fffSJeremy L Thompson }
1315eaf62fffSJeremy L Thompson 
1316eaf62fffSJeremy L Thompson /**
1317eaf62fffSJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
1318eaf62fffSJeremy L Thompson 
1319eaf62fffSJeremy L Thompson   This sums into a CeedVector with the point block diagonal of a linear
1320eaf62fffSJeremy L Thompson     CeedOperator.
1321eaf62fffSJeremy L Thompson 
1322eaf62fffSJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1323eaf62fffSJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1324eaf62fffSJeremy L Thompson 
1325f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1326f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1327f04ea552SJeremy L Thompson 
1328eaf62fffSJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
1329eaf62fffSJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator point block
1330eaf62fffSJeremy L Thompson                            diagonal, provided in row-major form with an
1331eaf62fffSJeremy L Thompson                            @a num_comp * @a num_comp block at each node. The dimensions
1332eaf62fffSJeremy L Thompson                            of this vector are derived from the active vector
1333eaf62fffSJeremy L Thompson                            for the CeedOperator. The array has shape
1334eaf62fffSJeremy L Thompson                            [nodes, component out, component in].
1335eaf62fffSJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
1336eaf62fffSJeremy L Thompson                            CEED_REQUEST_IMMEDIATE
1337eaf62fffSJeremy L Thompson 
1338eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1339eaf62fffSJeremy L Thompson 
1340eaf62fffSJeremy L Thompson   @ref User
1341eaf62fffSJeremy L Thompson **/
1342eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op,
1343eaf62fffSJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
1344eaf62fffSJeremy L Thompson   int ierr;
1345eaf62fffSJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1346eaf62fffSJeremy L Thompson 
1347eaf62fffSJeremy L Thompson   // Use backend version, if available
1348eaf62fffSJeremy L Thompson   if (op->LinearAssembleAddPointBlockDiagonal) {
1349eaf62fffSJeremy L Thompson     ierr = op->LinearAssembleAddPointBlockDiagonal(op, assembled, request);
1350eaf62fffSJeremy L Thompson     CeedChk(ierr);
1351eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1352eaf62fffSJeremy L Thompson   } else {
1353eaf62fffSJeremy L Thompson     // Check for valid fallback resource
1354eaf62fffSJeremy L Thompson     const char *resource, *fallback_resource;
1355eaf62fffSJeremy L Thompson     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1356eaf62fffSJeremy L Thompson     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
1357eaf62fffSJeremy L Thompson     CeedChk(ierr);
1358eaf62fffSJeremy L Thompson     if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) {
1359eaf62fffSJeremy L Thompson       // Fallback to reference Ceed
1360eaf62fffSJeremy L Thompson       if (!op->op_fallback) {
1361eaf62fffSJeremy L Thompson         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1362eaf62fffSJeremy L Thompson       }
1363eaf62fffSJeremy L Thompson       // Assemble
1364eaf62fffSJeremy L Thompson       ierr = CeedOperatorLinearAssembleAddPointBlockDiagonal(op->op_fallback,
1365eaf62fffSJeremy L Thompson              assembled, request); CeedChk(ierr);
1366eaf62fffSJeremy L Thompson       return CEED_ERROR_SUCCESS;
1367eaf62fffSJeremy L Thompson     }
1368eaf62fffSJeremy L Thompson   }
1369eaf62fffSJeremy L Thompson 
1370eaf62fffSJeremy L Thompson   // Default interface implemenation
1371eaf62fffSJeremy L Thompson   bool is_composite;
1372eaf62fffSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1373eaf62fffSJeremy L Thompson   if (is_composite) {
1374eaf62fffSJeremy L Thompson     ierr = CeedCompositeOperatorLinearAssembleAddDiagonal(op, request,
1375eaf62fffSJeremy L Thompson            true, assembled); CeedChk(ierr);
1376eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1377eaf62fffSJeremy L Thompson   } else {
1378eaf62fffSJeremy L Thompson     ierr = CeedSingleOperatorAssembleAddDiagonal(op, request, true, assembled);
1379eaf62fffSJeremy L Thompson     CeedChk(ierr);
1380eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1381eaf62fffSJeremy L Thompson   }
1382eaf62fffSJeremy L Thompson }
1383eaf62fffSJeremy L Thompson 
1384eaf62fffSJeremy L Thompson /**
1385eaf62fffSJeremy L Thompson    @brief Fully assemble the nonzero pattern of a linear operator.
1386eaf62fffSJeremy L Thompson 
1387eaf62fffSJeremy L Thompson    Expected to be used in conjunction with CeedOperatorLinearAssemble()
1388eaf62fffSJeremy L Thompson 
1389eaf62fffSJeremy L Thompson    The assembly routines use coordinate format, with num_entries tuples of the
1390eaf62fffSJeremy L Thompson    form (i, j, value) which indicate that value should be added to the matrix
1391eaf62fffSJeremy L Thompson    in entry (i, j). Note that the (i, j) pairs are not unique and may repeat.
1392eaf62fffSJeremy L Thompson    This function returns the number of entries and their (i, j) locations,
1393eaf62fffSJeremy L Thompson    while CeedOperatorLinearAssemble() provides the values in the same
1394eaf62fffSJeremy L Thompson    ordering.
1395eaf62fffSJeremy L Thompson 
1396eaf62fffSJeremy L Thompson    This will generally be slow unless your operator is low-order.
1397eaf62fffSJeremy L Thompson 
1398f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1399f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1400f04ea552SJeremy L Thompson 
1401eaf62fffSJeremy L Thompson    @param[in]  op           CeedOperator to assemble
1402eaf62fffSJeremy L Thompson    @param[out] num_entries  Number of entries in coordinate nonzero pattern
1403eaf62fffSJeremy L Thompson    @param[out] rows         Row number for each entry
1404eaf62fffSJeremy L Thompson    @param[out] cols         Column number for each entry
1405eaf62fffSJeremy L Thompson 
1406eaf62fffSJeremy L Thompson    @ref User
1407eaf62fffSJeremy L Thompson **/
1408eaf62fffSJeremy L Thompson int CeedOperatorLinearAssembleSymbolic(CeedOperator op, CeedInt *num_entries,
1409eaf62fffSJeremy L Thompson                                        CeedInt **rows, CeedInt **cols) {
1410eaf62fffSJeremy L Thompson   int ierr;
1411eaf62fffSJeremy L Thompson   CeedInt num_suboperators, single_entries;
1412eaf62fffSJeremy L Thompson   CeedOperator *sub_operators;
1413eaf62fffSJeremy L Thompson   bool is_composite;
1414eaf62fffSJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1415eaf62fffSJeremy L Thompson 
1416eaf62fffSJeremy L Thompson   // Use backend version, if available
1417eaf62fffSJeremy L Thompson   if (op->LinearAssembleSymbolic) {
1418eaf62fffSJeremy L Thompson     ierr = op->LinearAssembleSymbolic(op, num_entries, rows, cols); CeedChk(ierr);
1419eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1420eaf62fffSJeremy L Thompson   } else {
1421eaf62fffSJeremy L Thompson     // Check for valid fallback resource
1422eaf62fffSJeremy L Thompson     const char *resource, *fallback_resource;
1423eaf62fffSJeremy L Thompson     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1424eaf62fffSJeremy L Thompson     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
1425eaf62fffSJeremy L Thompson     CeedChk(ierr);
1426eaf62fffSJeremy L Thompson     if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) {
1427eaf62fffSJeremy L Thompson       // Fallback to reference Ceed
1428eaf62fffSJeremy L Thompson       if (!op->op_fallback) {
1429eaf62fffSJeremy L Thompson         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1430eaf62fffSJeremy L Thompson       }
1431eaf62fffSJeremy L Thompson       // Assemble
1432eaf62fffSJeremy L Thompson       ierr = CeedOperatorLinearAssembleSymbolic(op->op_fallback, num_entries, rows,
1433eaf62fffSJeremy L Thompson              cols); CeedChk(ierr);
1434eaf62fffSJeremy L Thompson       return CEED_ERROR_SUCCESS;
1435eaf62fffSJeremy L Thompson     }
1436eaf62fffSJeremy L Thompson   }
1437eaf62fffSJeremy L Thompson 
1438eaf62fffSJeremy L Thompson   // Default interface implementation
1439eaf62fffSJeremy L Thompson 
1440eaf62fffSJeremy L Thompson   // count entries and allocate rows, cols arrays
1441eaf62fffSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1442eaf62fffSJeremy L Thompson   *num_entries = 0;
1443eaf62fffSJeremy L Thompson   if (is_composite) {
1444eaf62fffSJeremy L Thompson     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1445eaf62fffSJeremy L Thompson     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1446eaf62fffSJeremy L Thompson     for (int k = 0; k < num_suboperators; ++k) {
1447eaf62fffSJeremy L Thompson       ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k],
1448eaf62fffSJeremy L Thompson              &single_entries); CeedChk(ierr);
1449eaf62fffSJeremy L Thompson       *num_entries += single_entries;
1450eaf62fffSJeremy L Thompson     }
1451eaf62fffSJeremy L Thompson   } else {
1452eaf62fffSJeremy L Thompson     ierr = CeedSingleOperatorAssemblyCountEntries(op,
1453eaf62fffSJeremy L Thompson            &single_entries); CeedChk(ierr);
1454eaf62fffSJeremy L Thompson     *num_entries += single_entries;
1455eaf62fffSJeremy L Thompson   }
1456eaf62fffSJeremy L Thompson   ierr = CeedCalloc(*num_entries, rows); CeedChk(ierr);
1457eaf62fffSJeremy L Thompson   ierr = CeedCalloc(*num_entries, cols); CeedChk(ierr);
1458eaf62fffSJeremy L Thompson 
1459eaf62fffSJeremy L Thompson   // assemble nonzero locations
1460eaf62fffSJeremy L Thompson   CeedInt offset = 0;
1461eaf62fffSJeremy L Thompson   if (is_composite) {
1462eaf62fffSJeremy L Thompson     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1463eaf62fffSJeremy L Thompson     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1464eaf62fffSJeremy L Thompson     for (int k = 0; k < num_suboperators; ++k) {
1465eaf62fffSJeremy L Thompson       ierr = CeedSingleOperatorAssembleSymbolic(sub_operators[k], offset, *rows,
1466eaf62fffSJeremy L Thompson              *cols); CeedChk(ierr);
1467eaf62fffSJeremy L Thompson       ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k],
1468eaf62fffSJeremy L Thompson              &single_entries);
1469eaf62fffSJeremy L Thompson       CeedChk(ierr);
1470eaf62fffSJeremy L Thompson       offset += single_entries;
1471eaf62fffSJeremy L Thompson     }
1472eaf62fffSJeremy L Thompson   } else {
1473eaf62fffSJeremy L Thompson     ierr = CeedSingleOperatorAssembleSymbolic(op, offset, *rows, *cols);
1474eaf62fffSJeremy L Thompson     CeedChk(ierr);
1475eaf62fffSJeremy L Thompson   }
1476eaf62fffSJeremy L Thompson 
1477eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1478eaf62fffSJeremy L Thompson }
1479eaf62fffSJeremy L Thompson 
1480eaf62fffSJeremy L Thompson /**
1481eaf62fffSJeremy L Thompson    @brief Fully assemble the nonzero entries of a linear operator.
1482eaf62fffSJeremy L Thompson 
1483eaf62fffSJeremy L Thompson    Expected to be used in conjunction with CeedOperatorLinearAssembleSymbolic()
1484eaf62fffSJeremy L Thompson 
1485eaf62fffSJeremy L Thompson    The assembly routines use coordinate format, with num_entries tuples of the
1486eaf62fffSJeremy L Thompson    form (i, j, value) which indicate that value should be added to the matrix
1487eaf62fffSJeremy L Thompson    in entry (i, j). Note that the (i, j) pairs are not unique and may repeat.
1488eaf62fffSJeremy L Thompson    This function returns the values of the nonzero entries to be added, their
1489eaf62fffSJeremy L Thompson    (i, j) locations are provided by CeedOperatorLinearAssembleSymbolic()
1490eaf62fffSJeremy L Thompson 
1491eaf62fffSJeremy L Thompson    This will generally be slow unless your operator is low-order.
1492eaf62fffSJeremy L Thompson 
1493f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1494f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1495f04ea552SJeremy L Thompson 
1496eaf62fffSJeremy L Thompson    @param[in]  op      CeedOperator to assemble
1497eaf62fffSJeremy L Thompson    @param[out] values  Values to assemble into matrix
1498eaf62fffSJeremy L Thompson 
1499eaf62fffSJeremy L Thompson    @ref User
1500eaf62fffSJeremy L Thompson **/
1501eaf62fffSJeremy L Thompson int CeedOperatorLinearAssemble(CeedOperator op, CeedVector values) {
1502eaf62fffSJeremy L Thompson   int ierr;
1503eaf62fffSJeremy L Thompson   CeedInt num_suboperators, single_entries = 0;
1504eaf62fffSJeremy L Thompson   CeedOperator *sub_operators;
1505eaf62fffSJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1506eaf62fffSJeremy L Thompson 
1507eaf62fffSJeremy L Thompson   // Use backend version, if available
1508eaf62fffSJeremy L Thompson   if (op->LinearAssemble) {
1509eaf62fffSJeremy L Thompson     ierr = op->LinearAssemble(op, values); CeedChk(ierr);
1510eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1511eaf62fffSJeremy L Thompson   } else {
1512eaf62fffSJeremy L Thompson     // Check for valid fallback resource
1513eaf62fffSJeremy L Thompson     const char *resource, *fallback_resource;
1514eaf62fffSJeremy L Thompson     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1515eaf62fffSJeremy L Thompson     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
1516eaf62fffSJeremy L Thompson     CeedChk(ierr);
1517eaf62fffSJeremy L Thompson     if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) {
1518eaf62fffSJeremy L Thompson       // Fallback to reference Ceed
1519eaf62fffSJeremy L Thompson       if (!op->op_fallback) {
1520eaf62fffSJeremy L Thompson         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1521eaf62fffSJeremy L Thompson       }
1522eaf62fffSJeremy L Thompson       // Assemble
1523eaf62fffSJeremy L Thompson       ierr = CeedOperatorLinearAssemble(op->op_fallback, values); CeedChk(ierr);
1524eaf62fffSJeremy L Thompson       return CEED_ERROR_SUCCESS;
1525eaf62fffSJeremy L Thompson     }
1526eaf62fffSJeremy L Thompson   }
1527eaf62fffSJeremy L Thompson 
1528eaf62fffSJeremy L Thompson   // Default interface implementation
1529eaf62fffSJeremy L Thompson   bool is_composite;
1530eaf62fffSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1531eaf62fffSJeremy L Thompson 
1532eaf62fffSJeremy L Thompson   CeedInt offset = 0;
1533eaf62fffSJeremy L Thompson   if (is_composite) {
1534eaf62fffSJeremy L Thompson     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1535eaf62fffSJeremy L Thompson     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1536eaf62fffSJeremy L Thompson     for (int k = 0; k < num_suboperators; ++k) {
1537eaf62fffSJeremy L Thompson       ierr = CeedSingleOperatorAssemble(sub_operators[k], offset, values);
1538eaf62fffSJeremy L Thompson       CeedChk(ierr);
1539eaf62fffSJeremy L Thompson       ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k],
1540eaf62fffSJeremy L Thompson              &single_entries);
1541eaf62fffSJeremy L Thompson       CeedChk(ierr);
1542eaf62fffSJeremy L Thompson       offset += single_entries;
1543eaf62fffSJeremy L Thompson     }
1544eaf62fffSJeremy L Thompson   } else {
1545eaf62fffSJeremy L Thompson     ierr = CeedSingleOperatorAssemble(op, offset, values); CeedChk(ierr);
1546eaf62fffSJeremy L Thompson   }
1547eaf62fffSJeremy L Thompson 
1548eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1549eaf62fffSJeremy L Thompson }
1550eaf62fffSJeremy L Thompson 
1551eaf62fffSJeremy L Thompson /**
1552eaf62fffSJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1553eaf62fffSJeremy L Thompson            for a CeedOperator, creating the prolongation basis from the
1554eaf62fffSJeremy L Thompson            fine and coarse grid interpolation
1555eaf62fffSJeremy L Thompson 
1556f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1557f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1558f04ea552SJeremy L Thompson 
1559eaf62fffSJeremy L Thompson   @param[in] op_fine       Fine grid operator
1560eaf62fffSJeremy L Thompson   @param[in] p_mult_fine   L-vector multiplicity in parallel gather/scatter
1561eaf62fffSJeremy L Thompson   @param[in] rstr_coarse   Coarse grid restriction
1562eaf62fffSJeremy L Thompson   @param[in] basis_coarse  Coarse grid active vector basis
1563eaf62fffSJeremy L Thompson   @param[out] op_coarse    Coarse grid operator
1564eaf62fffSJeremy L Thompson   @param[out] op_prolong   Coarse to fine operator
1565eaf62fffSJeremy L Thompson   @param[out] op_restrict  Fine to coarse operator
1566eaf62fffSJeremy L Thompson 
1567eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1568eaf62fffSJeremy L Thompson 
1569eaf62fffSJeremy L Thompson   @ref User
1570eaf62fffSJeremy L Thompson **/
1571eaf62fffSJeremy L Thompson int CeedOperatorMultigridLevelCreate(CeedOperator op_fine,
1572eaf62fffSJeremy L Thompson                                      CeedVector p_mult_fine,
1573eaf62fffSJeremy L Thompson                                      CeedElemRestriction rstr_coarse, CeedBasis basis_coarse,
1574eaf62fffSJeremy L Thompson                                      CeedOperator *op_coarse, CeedOperator *op_prolong,
1575eaf62fffSJeremy L Thompson                                      CeedOperator *op_restrict) {
1576eaf62fffSJeremy L Thompson   int ierr;
1577f04ea552SJeremy L Thompson   ierr = CeedOperatorCheckReady(op_fine); CeedChk(ierr);
1578eaf62fffSJeremy L Thompson   Ceed ceed;
1579eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
1580eaf62fffSJeremy L Thompson 
1581eaf62fffSJeremy L Thompson   // Check for compatible quadrature spaces
1582eaf62fffSJeremy L Thompson   CeedBasis basis_fine;
1583eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr);
1584eaf62fffSJeremy L Thompson   CeedInt Q_f, Q_c;
1585eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr);
1586eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr);
1587eaf62fffSJeremy L Thompson   if (Q_f != Q_c)
1588eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
1589eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1590eaf62fffSJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1591eaf62fffSJeremy L Thompson   // LCOV_EXCL_STOP
1592eaf62fffSJeremy L Thompson 
1593eaf62fffSJeremy L Thompson   // Coarse to fine basis
1594eaf62fffSJeremy L Thompson   CeedInt P_f, P_c, Q = Q_f;
1595eaf62fffSJeremy L Thompson   bool is_tensor_f, is_tensor_c;
1596eaf62fffSJeremy L Thompson   ierr = CeedBasisIsTensor(basis_fine, &is_tensor_f); CeedChk(ierr);
1597eaf62fffSJeremy L Thompson   ierr = CeedBasisIsTensor(basis_coarse, &is_tensor_c); CeedChk(ierr);
1598eaf62fffSJeremy L Thompson   CeedScalar *interp_c, *interp_f, *interp_c_to_f, *tau;
1599eaf62fffSJeremy L Thompson   if (is_tensor_f && is_tensor_c) {
1600eaf62fffSJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basis_fine, &P_f); CeedChk(ierr);
1601eaf62fffSJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basis_coarse, &P_c); CeedChk(ierr);
1602eaf62fffSJeremy L Thompson     ierr = CeedBasisGetNumQuadraturePoints1D(basis_coarse, &Q); CeedChk(ierr);
1603eaf62fffSJeremy L Thompson   } else if (!is_tensor_f && !is_tensor_c) {
1604eaf62fffSJeremy L Thompson     ierr = CeedBasisGetNumNodes(basis_fine, &P_f); CeedChk(ierr);
1605eaf62fffSJeremy L Thompson     ierr = CeedBasisGetNumNodes(basis_coarse, &P_c); CeedChk(ierr);
1606eaf62fffSJeremy L Thompson   } else {
1607eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
1608eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
1609eaf62fffSJeremy L Thompson                      "Bases must both be tensor or non-tensor");
1610eaf62fffSJeremy L Thompson     // LCOV_EXCL_STOP
1611eaf62fffSJeremy L Thompson   }
1612eaf62fffSJeremy L Thompson 
1613eaf62fffSJeremy L Thompson   ierr = CeedMalloc(Q*P_f, &interp_f); CeedChk(ierr);
1614eaf62fffSJeremy L Thompson   ierr = CeedMalloc(Q*P_c, &interp_c); CeedChk(ierr);
1615eaf62fffSJeremy L Thompson   ierr = CeedCalloc(P_c*P_f, &interp_c_to_f); CeedChk(ierr);
1616eaf62fffSJeremy L Thompson   ierr = CeedMalloc(Q, &tau); CeedChk(ierr);
1617eaf62fffSJeremy L Thompson   if (is_tensor_f) {
1618eaf62fffSJeremy L Thompson     memcpy(interp_f, basis_fine->interp_1d, Q*P_f*sizeof basis_fine->interp_1d[0]);
1619eaf62fffSJeremy L Thompson     memcpy(interp_c, basis_coarse->interp_1d,
1620eaf62fffSJeremy L Thompson            Q*P_c*sizeof basis_coarse->interp_1d[0]);
1621eaf62fffSJeremy L Thompson   } else {
1622eaf62fffSJeremy L Thompson     memcpy(interp_f, basis_fine->interp, Q*P_f*sizeof basis_fine->interp[0]);
1623eaf62fffSJeremy L Thompson     memcpy(interp_c, basis_coarse->interp, Q*P_c*sizeof basis_coarse->interp[0]);
1624eaf62fffSJeremy L Thompson   }
1625eaf62fffSJeremy L Thompson 
1626eaf62fffSJeremy L Thompson   // -- QR Factorization, interp_f = Q R
1627eaf62fffSJeremy L Thompson   ierr = CeedQRFactorization(ceed, interp_f, tau, Q, P_f); CeedChk(ierr);
1628eaf62fffSJeremy L Thompson 
1629eaf62fffSJeremy L Thompson   // -- Apply Qtranspose, interp_c = Qtranspose interp_c
1630eaf62fffSJeremy L Thompson   ierr = CeedHouseholderApplyQ(interp_c, interp_f, tau, CEED_TRANSPOSE,
1631eaf62fffSJeremy L Thompson                                Q, P_c, P_f, P_c, 1); CeedChk(ierr);
1632eaf62fffSJeremy L Thompson 
1633eaf62fffSJeremy L Thompson   // -- Apply Rinv, interp_c_to_f = Rinv interp_c
1634eaf62fffSJeremy L Thompson   for (CeedInt j=0; j<P_c; j++) { // Column j
1635eaf62fffSJeremy L Thompson     interp_c_to_f[j+P_c*(P_f-1)] = interp_c[j+P_c*(P_f-1)]/interp_f[P_f*P_f-1];
1636eaf62fffSJeremy L Thompson     for (CeedInt i=P_f-2; i>=0; i--) { // Row i
1637eaf62fffSJeremy L Thompson       interp_c_to_f[j+P_c*i] = interp_c[j+P_c*i];
1638eaf62fffSJeremy L Thompson       for (CeedInt k=i+1; k<P_f; k++)
1639eaf62fffSJeremy L Thompson         interp_c_to_f[j+P_c*i] -= interp_f[k+P_f*i]*interp_c_to_f[j+P_c*k];
1640eaf62fffSJeremy L Thompson       interp_c_to_f[j+P_c*i] /= interp_f[i+P_f*i];
1641eaf62fffSJeremy L Thompson     }
1642eaf62fffSJeremy L Thompson   }
1643eaf62fffSJeremy L Thompson   ierr = CeedFree(&tau); CeedChk(ierr);
1644eaf62fffSJeremy L Thompson   ierr = CeedFree(&interp_c); CeedChk(ierr);
1645eaf62fffSJeremy L Thompson   ierr = CeedFree(&interp_f); CeedChk(ierr);
1646eaf62fffSJeremy L Thompson 
1647eaf62fffSJeremy L Thompson   // Complete with interp_c_to_f versions of code
1648eaf62fffSJeremy L Thompson   if (is_tensor_f) {
1649eaf62fffSJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateTensorH1(op_fine, p_mult_fine,
1650eaf62fffSJeremy L Thompson            rstr_coarse, basis_coarse, interp_c_to_f, op_coarse, op_prolong, op_restrict);
1651eaf62fffSJeremy L Thompson     CeedChk(ierr);
1652eaf62fffSJeremy L Thompson   } else {
1653eaf62fffSJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateH1(op_fine, p_mult_fine,
1654eaf62fffSJeremy L Thompson            rstr_coarse, basis_coarse, interp_c_to_f, op_coarse, op_prolong, op_restrict);
1655eaf62fffSJeremy L Thompson     CeedChk(ierr);
1656eaf62fffSJeremy L Thompson   }
1657eaf62fffSJeremy L Thompson 
1658eaf62fffSJeremy L Thompson   // Cleanup
1659eaf62fffSJeremy L Thompson   ierr = CeedFree(&interp_c_to_f); CeedChk(ierr);
1660eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1661eaf62fffSJeremy L Thompson }
1662eaf62fffSJeremy L Thompson 
1663eaf62fffSJeremy L Thompson /**
1664eaf62fffSJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1665eaf62fffSJeremy L Thompson            for a CeedOperator with a tensor basis for the active basis
1666eaf62fffSJeremy L Thompson 
1667f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1668f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1669f04ea552SJeremy L Thompson 
1670eaf62fffSJeremy L Thompson   @param[in] op_fine        Fine grid operator
1671eaf62fffSJeremy L Thompson   @param[in] p_mult_fine    L-vector multiplicity in parallel gather/scatter
1672eaf62fffSJeremy L Thompson   @param[in] rstr_coarse    Coarse grid restriction
1673eaf62fffSJeremy L Thompson   @param[in] basis_coarse   Coarse grid active vector basis
1674eaf62fffSJeremy L Thompson   @param[in] interp_c_to_f  Matrix for coarse to fine interpolation
1675eaf62fffSJeremy L Thompson   @param[out] op_coarse     Coarse grid operator
1676eaf62fffSJeremy L Thompson   @param[out] op_prolong    Coarse to fine operator
1677eaf62fffSJeremy L Thompson   @param[out] op_restrict   Fine to coarse operator
1678eaf62fffSJeremy L Thompson 
1679eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1680eaf62fffSJeremy L Thompson 
1681eaf62fffSJeremy L Thompson   @ref User
1682eaf62fffSJeremy L Thompson **/
1683eaf62fffSJeremy L Thompson int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator op_fine,
1684eaf62fffSJeremy L Thompson     CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse,
1685eaf62fffSJeremy L Thompson     const CeedScalar *interp_c_to_f, CeedOperator *op_coarse,
1686eaf62fffSJeremy L Thompson     CeedOperator *op_prolong, CeedOperator *op_restrict) {
1687eaf62fffSJeremy L Thompson   int ierr;
1688f04ea552SJeremy L Thompson   ierr = CeedOperatorCheckReady(op_fine); CeedChk(ierr);
1689eaf62fffSJeremy L Thompson   Ceed ceed;
1690eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
1691eaf62fffSJeremy L Thompson 
1692eaf62fffSJeremy L Thompson   // Check for compatible quadrature spaces
1693eaf62fffSJeremy L Thompson   CeedBasis basis_fine;
1694eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr);
1695eaf62fffSJeremy L Thompson   CeedInt Q_f, Q_c;
1696eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr);
1697eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr);
1698eaf62fffSJeremy L Thompson   if (Q_f != Q_c)
1699eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
1700eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1701eaf62fffSJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1702eaf62fffSJeremy L Thompson   // LCOV_EXCL_STOP
1703eaf62fffSJeremy L Thompson 
1704eaf62fffSJeremy L Thompson   // Coarse to fine basis
1705eaf62fffSJeremy L Thompson   CeedInt dim, num_comp, num_nodes_c, P_1d_f, P_1d_c;
1706eaf62fffSJeremy L Thompson   ierr = CeedBasisGetDimension(basis_fine, &dim); CeedChk(ierr);
1707eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumComponents(basis_fine, &num_comp); CeedChk(ierr);
1708eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumNodes1D(basis_fine, &P_1d_f); CeedChk(ierr);
1709eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c);
1710eaf62fffSJeremy L Thompson   CeedChk(ierr);
1711eaf62fffSJeremy L Thompson   P_1d_c = dim == 1 ? num_nodes_c :
1712eaf62fffSJeremy L Thompson            dim == 2 ? sqrt(num_nodes_c) :
1713eaf62fffSJeremy L Thompson            cbrt(num_nodes_c);
1714eaf62fffSJeremy L Thompson   CeedScalar *q_ref, *q_weight, *grad;
1715eaf62fffSJeremy L Thompson   ierr = CeedCalloc(P_1d_f, &q_ref); CeedChk(ierr);
1716eaf62fffSJeremy L Thompson   ierr = CeedCalloc(P_1d_f, &q_weight); CeedChk(ierr);
1717eaf62fffSJeremy L Thompson   ierr = CeedCalloc(P_1d_f*P_1d_c*dim, &grad); CeedChk(ierr);
1718eaf62fffSJeremy L Thompson   CeedBasis basis_c_to_f;
1719eaf62fffSJeremy L Thompson   ierr = CeedBasisCreateTensorH1(ceed, dim, num_comp, P_1d_c, P_1d_f,
1720eaf62fffSJeremy L Thompson                                  interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f);
1721eaf62fffSJeremy L Thompson   CeedChk(ierr);
1722eaf62fffSJeremy L Thompson   ierr = CeedFree(&q_ref); CeedChk(ierr);
1723eaf62fffSJeremy L Thompson   ierr = CeedFree(&q_weight); CeedChk(ierr);
1724eaf62fffSJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
1725eaf62fffSJeremy L Thompson 
1726eaf62fffSJeremy L Thompson   // Core code
1727eaf62fffSJeremy L Thompson   ierr = CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse,
1728eaf62fffSJeremy L Thompson                                           basis_coarse, basis_c_to_f, op_coarse,
1729eaf62fffSJeremy L Thompson                                           op_prolong, op_restrict);
1730eaf62fffSJeremy L Thompson   CeedChk(ierr);
1731eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1732eaf62fffSJeremy L Thompson }
1733eaf62fffSJeremy L Thompson 
1734eaf62fffSJeremy L Thompson /**
1735eaf62fffSJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1736eaf62fffSJeremy L Thompson            for a CeedOperator with a non-tensor basis for the active vector
1737eaf62fffSJeremy L Thompson 
1738f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1739f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1740f04ea552SJeremy L Thompson 
1741eaf62fffSJeremy L Thompson   @param[in] op_fine        Fine grid operator
1742eaf62fffSJeremy L Thompson   @param[in] p_mult_fine    L-vector multiplicity in parallel gather/scatter
1743eaf62fffSJeremy L Thompson   @param[in] rstr_coarse    Coarse grid restriction
1744eaf62fffSJeremy L Thompson   @param[in] basis_coarse   Coarse grid active vector basis
1745eaf62fffSJeremy L Thompson   @param[in] interp_c_to_f  Matrix for coarse to fine interpolation
1746eaf62fffSJeremy L Thompson   @param[out] op_coarse     Coarse grid operator
1747eaf62fffSJeremy L Thompson   @param[out] op_prolong    Coarse to fine operator
1748eaf62fffSJeremy L Thompson   @param[out] op_restrict   Fine to coarse operator
1749eaf62fffSJeremy L Thompson 
1750eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1751eaf62fffSJeremy L Thompson 
1752eaf62fffSJeremy L Thompson   @ref User
1753eaf62fffSJeremy L Thompson **/
1754eaf62fffSJeremy L Thompson int CeedOperatorMultigridLevelCreateH1(CeedOperator op_fine,
1755eaf62fffSJeremy L Thompson                                        CeedVector p_mult_fine,
1756eaf62fffSJeremy L Thompson                                        CeedElemRestriction rstr_coarse,
1757eaf62fffSJeremy L Thompson                                        CeedBasis basis_coarse,
1758eaf62fffSJeremy L Thompson                                        const CeedScalar *interp_c_to_f,
1759eaf62fffSJeremy L Thompson                                        CeedOperator *op_coarse,
1760eaf62fffSJeremy L Thompson                                        CeedOperator *op_prolong,
1761eaf62fffSJeremy L Thompson                                        CeedOperator *op_restrict) {
1762eaf62fffSJeremy L Thompson   int ierr;
1763f04ea552SJeremy L Thompson   ierr = CeedOperatorCheckReady(op_fine); CeedChk(ierr);
1764eaf62fffSJeremy L Thompson   Ceed ceed;
1765eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
1766eaf62fffSJeremy L Thompson 
1767eaf62fffSJeremy L Thompson   // Check for compatible quadrature spaces
1768eaf62fffSJeremy L Thompson   CeedBasis basis_fine;
1769eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr);
1770eaf62fffSJeremy L Thompson   CeedInt Q_f, Q_c;
1771eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr);
1772eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr);
1773eaf62fffSJeremy L Thompson   if (Q_f != Q_c)
1774eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
1775eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1776eaf62fffSJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1777eaf62fffSJeremy L Thompson   // LCOV_EXCL_STOP
1778eaf62fffSJeremy L Thompson 
1779eaf62fffSJeremy L Thompson   // Coarse to fine basis
1780eaf62fffSJeremy L Thompson   CeedElemTopology topo;
1781eaf62fffSJeremy L Thompson   ierr = CeedBasisGetTopology(basis_fine, &topo); CeedChk(ierr);
1782eaf62fffSJeremy L Thompson   CeedInt dim, num_comp, num_nodes_c, num_nodes_f;
1783eaf62fffSJeremy L Thompson   ierr = CeedBasisGetDimension(basis_fine, &dim); CeedChk(ierr);
1784eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumComponents(basis_fine, &num_comp); CeedChk(ierr);
1785eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumNodes(basis_fine, &num_nodes_f); CeedChk(ierr);
1786eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c);
1787eaf62fffSJeremy L Thompson   CeedChk(ierr);
1788eaf62fffSJeremy L Thompson   CeedScalar *q_ref, *q_weight, *grad;
1789eaf62fffSJeremy L Thompson   ierr = CeedCalloc(num_nodes_f, &q_ref); CeedChk(ierr);
1790eaf62fffSJeremy L Thompson   ierr = CeedCalloc(num_nodes_f, &q_weight); CeedChk(ierr);
1791eaf62fffSJeremy L Thompson   ierr = CeedCalloc(num_nodes_f*num_nodes_c*dim, &grad); CeedChk(ierr);
1792eaf62fffSJeremy L Thompson   CeedBasis basis_c_to_f;
1793eaf62fffSJeremy L Thompson   ierr = CeedBasisCreateH1(ceed, topo, num_comp, num_nodes_c, num_nodes_f,
1794eaf62fffSJeremy L Thompson                            interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f);
1795eaf62fffSJeremy L Thompson   CeedChk(ierr);
1796eaf62fffSJeremy L Thompson   ierr = CeedFree(&q_ref); CeedChk(ierr);
1797eaf62fffSJeremy L Thompson   ierr = CeedFree(&q_weight); CeedChk(ierr);
1798eaf62fffSJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
1799eaf62fffSJeremy L Thompson 
1800eaf62fffSJeremy L Thompson   // Core code
1801eaf62fffSJeremy L Thompson   ierr = CeedSingleOperatorMultigridLevel(op_fine, p_mult_fine, rstr_coarse,
1802eaf62fffSJeremy L Thompson                                           basis_coarse, basis_c_to_f, op_coarse,
1803eaf62fffSJeremy L Thompson                                           op_prolong, op_restrict);
1804eaf62fffSJeremy L Thompson   CeedChk(ierr);
1805eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1806eaf62fffSJeremy L Thompson }
1807eaf62fffSJeremy L Thompson 
1808eaf62fffSJeremy L Thompson /**
1809eaf62fffSJeremy L Thompson   @brief Build a FDM based approximate inverse for each element for a
1810eaf62fffSJeremy L Thompson            CeedOperator
1811eaf62fffSJeremy L Thompson 
1812eaf62fffSJeremy L Thompson   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
1813eaf62fffSJeremy L Thompson     Method based approximate inverse. This function obtains the simultaneous
1814eaf62fffSJeremy L Thompson     diagonalization for the 1D mass and Laplacian operators,
1815eaf62fffSJeremy L Thompson       M = V^T V, K = V^T S V.
1816eaf62fffSJeremy L Thompson     The assembled QFunction is used to modify the eigenvalues from simultaneous
1817eaf62fffSJeremy L Thompson     diagonalization and obtain an approximate inverse of the form
1818eaf62fffSJeremy L Thompson       V^T S^hat V. The CeedOperator must be linear and non-composite. The
1819eaf62fffSJeremy L Thompson     associated CeedQFunction must therefore also be linear.
1820eaf62fffSJeremy L Thompson 
1821f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1822f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1823f04ea552SJeremy L Thompson 
1824eaf62fffSJeremy L Thompson   @param op            CeedOperator to create element inverses
1825eaf62fffSJeremy L Thompson   @param[out] fdm_inv  CeedOperator to apply the action of a FDM based inverse
1826eaf62fffSJeremy L Thompson                          for each element
1827eaf62fffSJeremy L Thompson   @param request       Address of CeedRequest for non-blocking completion, else
1828eaf62fffSJeremy L Thompson                          @ref CEED_REQUEST_IMMEDIATE
1829eaf62fffSJeremy L Thompson 
1830eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1831eaf62fffSJeremy L Thompson 
1832eaf62fffSJeremy L Thompson   @ref Backend
1833eaf62fffSJeremy L Thompson **/
1834eaf62fffSJeremy L Thompson int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdm_inv,
1835eaf62fffSJeremy L Thompson                                         CeedRequest *request) {
1836eaf62fffSJeremy L Thompson   int ierr;
1837eaf62fffSJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1838eaf62fffSJeremy L Thompson 
1839eaf62fffSJeremy L Thompson   // Use backend version, if available
1840eaf62fffSJeremy L Thompson   if (op->CreateFDMElementInverse) {
1841eaf62fffSJeremy L Thompson     ierr = op->CreateFDMElementInverse(op, fdm_inv, request); CeedChk(ierr);
1842eaf62fffSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1843eaf62fffSJeremy L Thompson   } else {
1844eaf62fffSJeremy L Thompson     // Check for valid fallback resource
1845eaf62fffSJeremy L Thompson     const char *resource, *fallback_resource;
1846eaf62fffSJeremy L Thompson     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1847eaf62fffSJeremy L Thompson     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
1848eaf62fffSJeremy L Thompson     CeedChk(ierr);
1849eaf62fffSJeremy L Thompson     if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) {
1850eaf62fffSJeremy L Thompson       // Fallback to reference Ceed
1851eaf62fffSJeremy L Thompson       if (!op->op_fallback) {
1852eaf62fffSJeremy L Thompson         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1853eaf62fffSJeremy L Thompson       }
1854eaf62fffSJeremy L Thompson       // Assemble
1855eaf62fffSJeremy L Thompson       ierr = CeedOperatorCreateFDMElementInverse(op->op_fallback, fdm_inv, request);
1856eaf62fffSJeremy L Thompson       CeedChk(ierr);
1857eaf62fffSJeremy L Thompson       return CEED_ERROR_SUCCESS;
1858eaf62fffSJeremy L Thompson     }
1859eaf62fffSJeremy L Thompson   }
1860eaf62fffSJeremy L Thompson 
1861eaf62fffSJeremy L Thompson   // Interface implementation
1862eaf62fffSJeremy L Thompson   Ceed ceed, ceed_parent;
1863eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
1864eaf62fffSJeremy L Thompson   ierr = CeedGetOperatorFallbackParentCeed(ceed, &ceed_parent); CeedChk(ierr);
1865eaf62fffSJeremy L Thompson   ceed_parent = ceed_parent ? ceed_parent : ceed;
1866eaf62fffSJeremy L Thompson   CeedQFunction qf;
1867eaf62fffSJeremy L Thompson   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
1868eaf62fffSJeremy L Thompson 
1869eaf62fffSJeremy L Thompson   // Determine active input basis
1870eaf62fffSJeremy L Thompson   bool interp = false, grad = false;
1871eaf62fffSJeremy L Thompson   CeedBasis basis = NULL;
1872eaf62fffSJeremy L Thompson   CeedElemRestriction rstr = NULL;
1873eaf62fffSJeremy L Thompson   CeedOperatorField *op_fields;
1874eaf62fffSJeremy L Thompson   CeedQFunctionField *qf_fields;
1875eaf62fffSJeremy L Thompson   CeedInt num_input_fields;
18767e7773b5SJeremy L Thompson   ierr = CeedOperatorGetFields(op, &num_input_fields, &op_fields, NULL, NULL);
18777e7773b5SJeremy L Thompson   CeedChk(ierr);
18787e7773b5SJeremy L Thompson   ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL); CeedChk(ierr);
1879eaf62fffSJeremy L Thompson   for (CeedInt i=0; i<num_input_fields; i++) {
1880eaf62fffSJeremy L Thompson     CeedVector vec;
1881eaf62fffSJeremy L Thompson     ierr = CeedOperatorFieldGetVector(op_fields[i], &vec); CeedChk(ierr);
1882eaf62fffSJeremy L Thompson     if (vec == CEED_VECTOR_ACTIVE) {
1883eaf62fffSJeremy L Thompson       CeedEvalMode eval_mode;
1884eaf62fffSJeremy L Thompson       ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode); CeedChk(ierr);
1885eaf62fffSJeremy L Thompson       interp = interp || eval_mode == CEED_EVAL_INTERP;
1886eaf62fffSJeremy L Thompson       grad = grad || eval_mode == CEED_EVAL_GRAD;
1887eaf62fffSJeremy L Thompson       ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis); CeedChk(ierr);
1888eaf62fffSJeremy L Thompson       ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr); CeedChk(ierr);
1889eaf62fffSJeremy L Thompson     }
1890eaf62fffSJeremy L Thompson   }
1891eaf62fffSJeremy L Thompson   if (!basis)
1892eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
1893eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_BACKEND, "No active field set");
1894eaf62fffSJeremy L Thompson   // LCOV_EXCL_STOP
1895eaf62fffSJeremy L Thompson   CeedInt P_1d, Q_1d, elem_size, num_qpts, dim, num_comp = 1, num_elem = 1,
1896eaf62fffSJeremy L Thompson                                                 l_size = 1;
1897eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumNodes1D(basis, &P_1d); CeedChk(ierr);
1898eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumNodes(basis, &elem_size); CeedChk(ierr);
1899eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d); CeedChk(ierr);
1900eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basis, &num_qpts); CeedChk(ierr);
1901eaf62fffSJeremy L Thompson   ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
1902eaf62fffSJeremy L Thompson   ierr = CeedBasisGetNumComponents(basis, &num_comp); CeedChk(ierr);
1903eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr);
1904eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetLVectorSize(rstr, &l_size); CeedChk(ierr);
1905eaf62fffSJeremy L Thompson 
1906eaf62fffSJeremy L Thompson   // Build and diagonalize 1D Mass and Laplacian
1907eaf62fffSJeremy L Thompson   bool tensor_basis;
1908eaf62fffSJeremy L Thompson   ierr = CeedBasisIsTensor(basis, &tensor_basis); CeedChk(ierr);
1909eaf62fffSJeremy L Thompson   if (!tensor_basis)
1910eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
1911eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_BACKEND,
1912eaf62fffSJeremy L Thompson                      "FDMElementInverse only supported for tensor "
1913eaf62fffSJeremy L Thompson                      "bases");
1914eaf62fffSJeremy L Thompson   // LCOV_EXCL_STOP
1915eaf62fffSJeremy L Thompson   CeedScalar *mass, *laplace, *x, *fdm_interp, *lambda;
1916eaf62fffSJeremy L Thompson   ierr = CeedCalloc(P_1d*P_1d, &mass); CeedChk(ierr);
1917eaf62fffSJeremy L Thompson   ierr = CeedCalloc(P_1d*P_1d, &laplace); CeedChk(ierr);
1918eaf62fffSJeremy L Thompson   ierr = CeedCalloc(P_1d*P_1d, &x); CeedChk(ierr);
1919eaf62fffSJeremy L Thompson   ierr = CeedCalloc(P_1d*P_1d, &fdm_interp); CeedChk(ierr);
1920eaf62fffSJeremy L Thompson   ierr = CeedCalloc(P_1d, &lambda); CeedChk(ierr);
1921eaf62fffSJeremy L Thompson   // -- Build matrices
1922eaf62fffSJeremy L Thompson   const CeedScalar *interp_1d, *grad_1d, *q_weight_1d;
1923eaf62fffSJeremy L Thompson   ierr = CeedBasisGetInterp1D(basis, &interp_1d); CeedChk(ierr);
1924eaf62fffSJeremy L Thompson   ierr = CeedBasisGetGrad1D(basis, &grad_1d); CeedChk(ierr);
1925eaf62fffSJeremy L Thompson   ierr = CeedBasisGetQWeights(basis, &q_weight_1d); CeedChk(ierr);
1926eaf62fffSJeremy L Thompson   ierr = CeedBuildMassLaplace(interp_1d, grad_1d, q_weight_1d, P_1d, Q_1d, dim,
1927eaf62fffSJeremy L Thompson                               mass, laplace); CeedChk(ierr);
1928eaf62fffSJeremy L Thompson 
1929eaf62fffSJeremy L Thompson   // -- Diagonalize
1930eaf62fffSJeremy L Thompson   ierr = CeedSimultaneousDiagonalization(ceed, laplace, mass, x, lambda, P_1d);
1931eaf62fffSJeremy L Thompson   CeedChk(ierr);
1932eaf62fffSJeremy L Thompson   ierr = CeedFree(&mass); CeedChk(ierr);
1933eaf62fffSJeremy L Thompson   ierr = CeedFree(&laplace); CeedChk(ierr);
1934eaf62fffSJeremy L Thompson   for (CeedInt i=0; i<P_1d; i++)
1935eaf62fffSJeremy L Thompson     for (CeedInt j=0; j<P_1d; j++)
1936eaf62fffSJeremy L Thompson       fdm_interp[i+j*P_1d] = x[j+i*P_1d];
1937eaf62fffSJeremy L Thompson   ierr = CeedFree(&x); CeedChk(ierr);
1938eaf62fffSJeremy L Thompson 
1939eaf62fffSJeremy L Thompson   // Assemble QFunction
1940eaf62fffSJeremy L Thompson   CeedVector assembled;
1941eaf62fffSJeremy L Thompson   CeedElemRestriction rstr_qf;
194270a7ffb3SJeremy L Thompson   ierr =  CeedOperatorLinearAssembleQFunctionBuildOrUpdate(op, &assembled,
194370a7ffb3SJeremy L Thompson           &rstr_qf, request); CeedChk(ierr);
1944eaf62fffSJeremy L Thompson   CeedInt layout[3];
1945eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionGetELayout(rstr_qf, &layout); CeedChk(ierr);
1946eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionDestroy(&rstr_qf); CeedChk(ierr);
1947eaf62fffSJeremy L Thompson   CeedScalar max_norm = 0;
1948eaf62fffSJeremy L Thompson   ierr = CeedVectorNorm(assembled, CEED_NORM_MAX, &max_norm); CeedChk(ierr);
1949eaf62fffSJeremy L Thompson 
1950eaf62fffSJeremy L Thompson   // Calculate element averages
1951eaf62fffSJeremy L Thompson   CeedInt num_modes = (interp?1:0) + (grad?dim:0);
1952eaf62fffSJeremy L Thompson   CeedScalar *elem_avg;
1953eaf62fffSJeremy L Thompson   const CeedScalar *assembled_array, *q_weight_array;
1954eaf62fffSJeremy L Thompson   CeedVector q_weight;
1955eaf62fffSJeremy L Thompson   ierr = CeedVectorCreate(ceed_parent, num_qpts, &q_weight); CeedChk(ierr);
1956eaf62fffSJeremy L Thompson   ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT,
1957eaf62fffSJeremy L Thompson                         CEED_VECTOR_NONE, q_weight); CeedChk(ierr);
1958eaf62fffSJeremy L Thompson   ierr = CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembled_array);
1959eaf62fffSJeremy L Thompson   CeedChk(ierr);
1960eaf62fffSJeremy L Thompson   ierr = CeedVectorGetArrayRead(q_weight, CEED_MEM_HOST, &q_weight_array);
1961eaf62fffSJeremy L Thompson   CeedChk(ierr);
1962eaf62fffSJeremy L Thompson   ierr = CeedCalloc(num_elem, &elem_avg); CeedChk(ierr);
1963eaf62fffSJeremy L Thompson   const CeedScalar qf_value_bound = max_norm*100*CEED_EPSILON;
1964eaf62fffSJeremy L Thompson   for (CeedInt e=0; e<num_elem; e++) {
1965eaf62fffSJeremy L Thompson     CeedInt count = 0;
1966eaf62fffSJeremy L Thompson     for (CeedInt q=0; q<num_qpts; q++)
1967eaf62fffSJeremy L Thompson       for (CeedInt i=0; i<num_comp*num_comp*num_modes*num_modes; i++)
1968eaf62fffSJeremy L Thompson         if (fabs(assembled_array[q*layout[0] + i*layout[1] + e*layout[2]]) >
1969eaf62fffSJeremy L Thompson             qf_value_bound) {
1970eaf62fffSJeremy L Thompson           elem_avg[e] += assembled_array[q*layout[0] + i*layout[1] + e*layout[2]] /
1971eaf62fffSJeremy L Thompson                          q_weight_array[q];
1972eaf62fffSJeremy L Thompson           count++;
1973eaf62fffSJeremy L Thompson         }
1974eaf62fffSJeremy L Thompson     if (count) {
1975eaf62fffSJeremy L Thompson       elem_avg[e] /= count;
1976eaf62fffSJeremy L Thompson     } else {
1977eaf62fffSJeremy L Thompson       elem_avg[e] = 1.0;
1978eaf62fffSJeremy L Thompson     }
1979eaf62fffSJeremy L Thompson   }
1980eaf62fffSJeremy L Thompson   ierr = CeedVectorRestoreArrayRead(assembled, &assembled_array); CeedChk(ierr);
1981eaf62fffSJeremy L Thompson   ierr = CeedVectorDestroy(&assembled); CeedChk(ierr);
1982eaf62fffSJeremy L Thompson   ierr = CeedVectorRestoreArrayRead(q_weight, &q_weight_array); CeedChk(ierr);
1983eaf62fffSJeremy L Thompson   ierr = CeedVectorDestroy(&q_weight); CeedChk(ierr);
1984eaf62fffSJeremy L Thompson 
1985eaf62fffSJeremy L Thompson   // Build FDM diagonal
1986eaf62fffSJeremy L Thompson   CeedVector q_data;
1987eaf62fffSJeremy L Thompson   CeedScalar *q_data_array, *fdm_diagonal;
1988eaf62fffSJeremy L Thompson   ierr = CeedCalloc(num_comp*elem_size, &fdm_diagonal); CeedChk(ierr);
1989eaf62fffSJeremy L Thompson   const CeedScalar fdm_diagonal_bound = elem_size*CEED_EPSILON;
1990eaf62fffSJeremy L Thompson   for (CeedInt c=0; c<num_comp; c++)
1991eaf62fffSJeremy L Thompson     for (CeedInt n=0; n<elem_size; n++) {
1992eaf62fffSJeremy L Thompson       if (interp)
1993eaf62fffSJeremy L Thompson         fdm_diagonal[c*elem_size + n] = 1.0;
1994eaf62fffSJeremy L Thompson       if (grad)
1995eaf62fffSJeremy L Thompson         for (CeedInt d=0; d<dim; d++) {
1996eaf62fffSJeremy L Thompson           CeedInt i = (n / CeedIntPow(P_1d, d)) % P_1d;
1997eaf62fffSJeremy L Thompson           fdm_diagonal[c*elem_size + n] += lambda[i];
1998eaf62fffSJeremy L Thompson         }
1999eaf62fffSJeremy L Thompson       if (fabs(fdm_diagonal[c*elem_size + n]) < fdm_diagonal_bound)
2000eaf62fffSJeremy L Thompson         fdm_diagonal[c*elem_size + n] = fdm_diagonal_bound;
2001eaf62fffSJeremy L Thompson     }
2002eaf62fffSJeremy L Thompson   ierr = CeedVectorCreate(ceed_parent, num_elem*num_comp*elem_size, &q_data);
2003eaf62fffSJeremy L Thompson   CeedChk(ierr);
2004eaf62fffSJeremy L Thompson   ierr = CeedVectorSetValue(q_data, 0.0); CeedChk(ierr);
2005*9c774eddSJeremy L Thompson   ierr = CeedVectorGetArrayWrite(q_data, CEED_MEM_HOST, &q_data_array);
2006*9c774eddSJeremy L Thompson   CeedChk(ierr);
2007eaf62fffSJeremy L Thompson   for (CeedInt e=0; e<num_elem; e++)
2008eaf62fffSJeremy L Thompson     for (CeedInt c=0; c<num_comp; c++)
2009eaf62fffSJeremy L Thompson       for (CeedInt n=0; n<elem_size; n++)
2010eaf62fffSJeremy L Thompson         q_data_array[(e*num_comp+c)*elem_size+n] = 1. / (elem_avg[e] *
2011eaf62fffSJeremy L Thompson             fdm_diagonal[c*elem_size + n]);
2012eaf62fffSJeremy L Thompson   ierr = CeedFree(&elem_avg); CeedChk(ierr);
2013eaf62fffSJeremy L Thompson   ierr = CeedFree(&fdm_diagonal); CeedChk(ierr);
2014eaf62fffSJeremy L Thompson   ierr = CeedVectorRestoreArray(q_data, &q_data_array); CeedChk(ierr);
2015eaf62fffSJeremy L Thompson 
2016eaf62fffSJeremy L Thompson   // Setup FDM operator
2017eaf62fffSJeremy L Thompson   // -- Basis
2018eaf62fffSJeremy L Thompson   CeedBasis fdm_basis;
2019eaf62fffSJeremy L Thompson   CeedScalar *grad_dummy, *q_ref_dummy, *q_weight_dummy;
2020eaf62fffSJeremy L Thompson   ierr = CeedCalloc(P_1d*P_1d, &grad_dummy); CeedChk(ierr);
2021eaf62fffSJeremy L Thompson   ierr = CeedCalloc(P_1d, &q_ref_dummy); CeedChk(ierr);
2022eaf62fffSJeremy L Thompson   ierr = CeedCalloc(P_1d, &q_weight_dummy); CeedChk(ierr);
2023eaf62fffSJeremy L Thompson   ierr = CeedBasisCreateTensorH1(ceed_parent, dim, num_comp, P_1d, P_1d,
2024eaf62fffSJeremy L Thompson                                  fdm_interp, grad_dummy, q_ref_dummy,
2025eaf62fffSJeremy L Thompson                                  q_weight_dummy, &fdm_basis); CeedChk(ierr);
2026eaf62fffSJeremy L Thompson   ierr = CeedFree(&fdm_interp); CeedChk(ierr);
2027eaf62fffSJeremy L Thompson   ierr = CeedFree(&grad_dummy); CeedChk(ierr);
2028eaf62fffSJeremy L Thompson   ierr = CeedFree(&q_ref_dummy); CeedChk(ierr);
2029eaf62fffSJeremy L Thompson   ierr = CeedFree(&q_weight_dummy); CeedChk(ierr);
2030eaf62fffSJeremy L Thompson   ierr = CeedFree(&lambda); CeedChk(ierr);
2031eaf62fffSJeremy L Thompson 
2032eaf62fffSJeremy L Thompson   // -- Restriction
2033eaf62fffSJeremy L Thompson   CeedElemRestriction rstr_qd_i;
2034eaf62fffSJeremy L Thompson   CeedInt strides[3] = {1, elem_size, elem_size*num_comp};
2035eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionCreateStrided(ceed_parent, num_elem, elem_size,
2036eaf62fffSJeremy L Thompson                                           num_comp, num_elem*num_comp*elem_size,
2037eaf62fffSJeremy L Thompson                                           strides, &rstr_qd_i); CeedChk(ierr);
2038eaf62fffSJeremy L Thompson   // -- QFunction
2039eaf62fffSJeremy L Thompson   CeedQFunction qf_fdm;
2040eaf62fffSJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed_parent, "Scale", &qf_fdm);
2041eaf62fffSJeremy L Thompson   CeedChk(ierr);
2042eaf62fffSJeremy L Thompson   ierr = CeedQFunctionAddInput(qf_fdm, "input", num_comp, CEED_EVAL_INTERP);
2043eaf62fffSJeremy L Thompson   CeedChk(ierr);
2044eaf62fffSJeremy L Thompson   ierr = CeedQFunctionAddInput(qf_fdm, "scale", num_comp, CEED_EVAL_NONE);
2045eaf62fffSJeremy L Thompson   CeedChk(ierr);
2046eaf62fffSJeremy L Thompson   ierr = CeedQFunctionAddOutput(qf_fdm, "output", num_comp, CEED_EVAL_INTERP);
2047eaf62fffSJeremy L Thompson   CeedChk(ierr);
2048eaf62fffSJeremy L Thompson   // -- QFunction context
2049eaf62fffSJeremy L Thompson   CeedInt *num_comp_data;
2050eaf62fffSJeremy L Thompson   ierr = CeedCalloc(1, &num_comp_data); CeedChk(ierr);
2051eaf62fffSJeremy L Thompson   num_comp_data[0] = num_comp;
2052eaf62fffSJeremy L Thompson   CeedQFunctionContext ctx_fdm;
2053eaf62fffSJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctx_fdm); CeedChk(ierr);
2054eaf62fffSJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctx_fdm, CEED_MEM_HOST, CEED_OWN_POINTER,
2055eaf62fffSJeremy L Thompson                                      sizeof(*num_comp_data), num_comp_data);
2056eaf62fffSJeremy L Thompson   CeedChk(ierr);
2057eaf62fffSJeremy L Thompson   ierr = CeedQFunctionSetContext(qf_fdm, ctx_fdm); CeedChk(ierr);
2058eaf62fffSJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctx_fdm); CeedChk(ierr);
2059eaf62fffSJeremy L Thompson   // -- Operator
2060eaf62fffSJeremy L Thompson   ierr = CeedOperatorCreate(ceed_parent, qf_fdm, NULL, NULL, fdm_inv);
2061eaf62fffSJeremy L Thompson   CeedChk(ierr);
2062eaf62fffSJeremy L Thompson   CeedOperatorSetField(*fdm_inv, "input", rstr, fdm_basis, CEED_VECTOR_ACTIVE);
2063eaf62fffSJeremy L Thompson   CeedChk(ierr);
2064eaf62fffSJeremy L Thompson   CeedOperatorSetField(*fdm_inv, "scale", rstr_qd_i, CEED_BASIS_COLLOCATED,
2065eaf62fffSJeremy L Thompson                        q_data); CeedChk(ierr);
2066eaf62fffSJeremy L Thompson   CeedOperatorSetField(*fdm_inv, "output", rstr, fdm_basis, CEED_VECTOR_ACTIVE);
2067eaf62fffSJeremy L Thompson   CeedChk(ierr);
2068eaf62fffSJeremy L Thompson 
2069eaf62fffSJeremy L Thompson   // Cleanup
2070eaf62fffSJeremy L Thompson   ierr = CeedVectorDestroy(&q_data); CeedChk(ierr);
2071eaf62fffSJeremy L Thompson   ierr = CeedBasisDestroy(&fdm_basis); CeedChk(ierr);
2072eaf62fffSJeremy L Thompson   ierr = CeedElemRestrictionDestroy(&rstr_qd_i); CeedChk(ierr);
2073eaf62fffSJeremy L Thompson   ierr = CeedQFunctionDestroy(&qf_fdm); CeedChk(ierr);
2074eaf62fffSJeremy L Thompson 
2075eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
2076eaf62fffSJeremy L Thompson }
2077eaf62fffSJeremy L Thompson 
2078eaf62fffSJeremy L Thompson /// @}
2079