xref: /libCEED/rust/libceed-sys/c-src/backends/blocked/ceed-blocked-operator.c (revision 4a2e7687020d2b79efacc5b03550abddf4643331)
1*4a2e7687Sjeremylt // Copyright (c) 2017-2018, Lawrence Livermore National Security, LLC.
2*4a2e7687Sjeremylt // Produced at the Lawrence Livermore National Laboratory. LLNL-CODE-734707.
3*4a2e7687Sjeremylt // All Rights reserved. See files LICENSE and NOTICE for details.
4*4a2e7687Sjeremylt //
5*4a2e7687Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
6*4a2e7687Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
7*4a2e7687Sjeremylt // element discretizations for exascale applications. For more information and
8*4a2e7687Sjeremylt // source code availability see http://github.com/ceed.
9*4a2e7687Sjeremylt //
10*4a2e7687Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11*4a2e7687Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
12*4a2e7687Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
13*4a2e7687Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
14*4a2e7687Sjeremylt // software, applications, hardware, advanced system engineering and early
15*4a2e7687Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
16*4a2e7687Sjeremylt 
17*4a2e7687Sjeremylt #include <ceed-impl.h>
18*4a2e7687Sjeremylt #include <string.h>
19*4a2e7687Sjeremylt #include "ceed-blocked.h"
20*4a2e7687Sjeremylt #include "../ref/ceed-ref.h"
21*4a2e7687Sjeremylt 
22*4a2e7687Sjeremylt static int CeedOperatorDestroy_Blocked(CeedOperator op) {
23*4a2e7687Sjeremylt   CeedOperator_Blocked *impl = op->data;
24*4a2e7687Sjeremylt   int ierr;
25*4a2e7687Sjeremylt 
26*4a2e7687Sjeremylt   for (CeedInt i=0; i<impl->numein+impl->numeout; i++) {
27*4a2e7687Sjeremylt     ierr = CeedElemRestrictionDestroy(&impl->blkrestr[i]); CeedChk(ierr);
28*4a2e7687Sjeremylt     ierr = CeedVectorDestroy(&impl->evecs[i]); CeedChk(ierr);
29*4a2e7687Sjeremylt   }
30*4a2e7687Sjeremylt   ierr = CeedFree(&impl->blkrestr); CeedChk(ierr);
31*4a2e7687Sjeremylt   ierr = CeedFree(&impl->evecs); CeedChk(ierr);
32*4a2e7687Sjeremylt   ierr = CeedFree(&impl->edata); CeedChk(ierr);
33*4a2e7687Sjeremylt 
34*4a2e7687Sjeremylt   for (CeedInt i=0; i<impl->numqin+impl->numqout; i++) {
35*4a2e7687Sjeremylt     ierr = CeedFree(&impl->qdata_alloc[i]); CeedChk(ierr);
36*4a2e7687Sjeremylt   }
37*4a2e7687Sjeremylt   ierr = CeedFree(&impl->qdata_alloc); CeedChk(ierr);
38*4a2e7687Sjeremylt   ierr = CeedFree(&impl->qdata); CeedChk(ierr);
39*4a2e7687Sjeremylt 
40*4a2e7687Sjeremylt   ierr = CeedFree(&impl->indata); CeedChk(ierr);
41*4a2e7687Sjeremylt   ierr = CeedFree(&impl->outdata); CeedChk(ierr);
42*4a2e7687Sjeremylt 
43*4a2e7687Sjeremylt   ierr = CeedFree(&op->data); CeedChk(ierr);
44*4a2e7687Sjeremylt   return 0;
45*4a2e7687Sjeremylt }
46*4a2e7687Sjeremylt 
47*4a2e7687Sjeremylt /*
48*4a2e7687Sjeremylt   Setup infields or outfields
49*4a2e7687Sjeremylt  */
50*4a2e7687Sjeremylt static int CeedOperatorSetupFields_Blocked(struct CeedQFunctionField qfields[16],
51*4a2e7687Sjeremylt                                        struct CeedOperatorField ofields[16],
52*4a2e7687Sjeremylt                                        CeedElemRestriction *blkrestr,
53*4a2e7687Sjeremylt                                        CeedVector *evecs, CeedScalar **qdata,
54*4a2e7687Sjeremylt                                        CeedScalar **qdata_alloc, CeedScalar **indata,
55*4a2e7687Sjeremylt                                        CeedInt starti, CeedInt startq,
56*4a2e7687Sjeremylt                                        CeedInt numfields, CeedInt Q) {
57*4a2e7687Sjeremylt   CeedInt dim, ierr, iq=startq, ncomp;
58*4a2e7687Sjeremylt   const CeedInt blksize = 8;
59*4a2e7687Sjeremylt 
60*4a2e7687Sjeremylt   // Loop over fields
61*4a2e7687Sjeremylt   for (CeedInt i=0; i<numfields; i++) {
62*4a2e7687Sjeremylt     CeedEvalMode emode = qfields[i].emode;
63*4a2e7687Sjeremylt 
64*4a2e7687Sjeremylt     if (emode != CEED_EVAL_WEIGHT) {
65*4a2e7687Sjeremylt       CeedElemRestriction r = ofields[i].Erestrict;
66*4a2e7687Sjeremylt       CeedElemRestriction_Ref *data = r->data;
67*4a2e7687Sjeremylt       ierr = CeedElemRestrictionCreateBlocked(r->ceed, r->nelem, r->elemsize,
68*4a2e7687Sjeremylt                                               blksize, r->ndof, r->ncomp,
69*4a2e7687Sjeremylt                                               CEED_MEM_HOST, CEED_COPY_VALUES,
70*4a2e7687Sjeremylt                                               data->indices, &blkrestr[i+starti]);
71*4a2e7687Sjeremylt       CeedChk(ierr);
72*4a2e7687Sjeremylt       ierr = CeedElemRestrictionCreateVector(blkrestr[i+starti], NULL,
73*4a2e7687Sjeremylt                                              &evecs[i+starti]);
74*4a2e7687Sjeremylt       CeedChk(ierr);
75*4a2e7687Sjeremylt     }
76*4a2e7687Sjeremylt 
77*4a2e7687Sjeremylt     switch(emode) {
78*4a2e7687Sjeremylt     case CEED_EVAL_NONE:
79*4a2e7687Sjeremylt       break; // No action
80*4a2e7687Sjeremylt     case CEED_EVAL_INTERP:
81*4a2e7687Sjeremylt       ncomp = qfields[i].ncomp;
82*4a2e7687Sjeremylt       ierr = CeedMalloc(Q*ncomp*blksize, &qdata_alloc[iq]); CeedChk(ierr);
83*4a2e7687Sjeremylt       qdata[i + starti] = qdata_alloc[iq];
84*4a2e7687Sjeremylt       iq++;
85*4a2e7687Sjeremylt       break;
86*4a2e7687Sjeremylt     case CEED_EVAL_GRAD:
87*4a2e7687Sjeremylt       ncomp = qfields[i].ncomp;
88*4a2e7687Sjeremylt       dim = ofields[i].basis->dim;
89*4a2e7687Sjeremylt       ierr = CeedMalloc(Q*ncomp*dim*blksize, &qdata_alloc[iq]); CeedChk(ierr);
90*4a2e7687Sjeremylt       qdata[i + starti] = qdata_alloc[iq];
91*4a2e7687Sjeremylt       iq++;
92*4a2e7687Sjeremylt       break;
93*4a2e7687Sjeremylt     case CEED_EVAL_WEIGHT: // Only on input fields
94*4a2e7687Sjeremylt       ierr = CeedMalloc(Q*blksize, &qdata_alloc[iq]); CeedChk(ierr);
95*4a2e7687Sjeremylt       ierr = CeedBasisApply(ofields[iq].basis, blksize, CEED_NOTRANSPOSE,
96*4a2e7687Sjeremylt                             CEED_EVAL_WEIGHT, NULL, qdata_alloc[iq]); CeedChk(ierr);
97*4a2e7687Sjeremylt       qdata[i] = qdata_alloc[iq];
98*4a2e7687Sjeremylt       indata[i] = qdata[i];
99*4a2e7687Sjeremylt       iq++;
100*4a2e7687Sjeremylt       break;
101*4a2e7687Sjeremylt     case CEED_EVAL_DIV:
102*4a2e7687Sjeremylt       break; // Not implimented
103*4a2e7687Sjeremylt     case CEED_EVAL_CURL:
104*4a2e7687Sjeremylt       break; // Not implimented
105*4a2e7687Sjeremylt     }
106*4a2e7687Sjeremylt   }
107*4a2e7687Sjeremylt   return 0;
108*4a2e7687Sjeremylt }
109*4a2e7687Sjeremylt 
110*4a2e7687Sjeremylt /*
111*4a2e7687Sjeremylt   CeedOperator needs to connect all the named fields (be they active or passive)
112*4a2e7687Sjeremylt   to the named inputs and outputs of its CeedQFunction.
113*4a2e7687Sjeremylt  */
114*4a2e7687Sjeremylt static int CeedOperatorSetup_Blocked(CeedOperator op) {
115*4a2e7687Sjeremylt   if (op->setupdone) return 0;
116*4a2e7687Sjeremylt   CeedOperator_Blocked *impl = op->data;
117*4a2e7687Sjeremylt   CeedQFunction qf = op->qf;
118*4a2e7687Sjeremylt   CeedInt Q = op->numqpoints, numinputfields, numoutputfields;
119*4a2e7687Sjeremylt   int ierr;
120*4a2e7687Sjeremylt 
121*4a2e7687Sjeremylt   // Count infield and outfield array sizes and evectors
122*4a2e7687Sjeremylt   ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
123*4a2e7687Sjeremylt   CeedChk(ierr);
124*4a2e7687Sjeremylt   impl->numein = numinputfields;
125*4a2e7687Sjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
126*4a2e7687Sjeremylt     CeedEvalMode emode = qf->inputfields[i].emode;
127*4a2e7687Sjeremylt     impl->numqin += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD) +
128*4a2e7687Sjeremylt                     !!(emode & CEED_EVAL_WEIGHT);
129*4a2e7687Sjeremylt   }
130*4a2e7687Sjeremylt   impl->numeout = numoutputfields;
131*4a2e7687Sjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
132*4a2e7687Sjeremylt     CeedEvalMode emode = qf->outputfields[i].emode;
133*4a2e7687Sjeremylt     impl->numqout += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD);
134*4a2e7687Sjeremylt   }
135*4a2e7687Sjeremylt 
136*4a2e7687Sjeremylt   // Allocate
137*4a2e7687Sjeremylt   ierr = CeedCalloc(impl->numein + impl->numeout, &impl->blkrestr);
138*4a2e7687Sjeremylt   CeedChk(ierr);
139*4a2e7687Sjeremylt   ierr = CeedCalloc(impl->numein + impl->numeout, &impl->evecs);
140*4a2e7687Sjeremylt   CeedChk(ierr);
141*4a2e7687Sjeremylt   ierr = CeedCalloc(impl->numein + impl->numeout, &impl->edata);
142*4a2e7687Sjeremylt   CeedChk(ierr);
143*4a2e7687Sjeremylt 
144*4a2e7687Sjeremylt   ierr = CeedCalloc(impl->numqin + impl->numqout, &impl->qdata_alloc);
145*4a2e7687Sjeremylt   CeedChk(ierr);
146*4a2e7687Sjeremylt   ierr = CeedCalloc(numinputfields + numoutputfields, &impl->qdata);
147*4a2e7687Sjeremylt   CeedChk(ierr);
148*4a2e7687Sjeremylt 
149*4a2e7687Sjeremylt   ierr = CeedCalloc(16, &impl->indata); CeedChk(ierr);
150*4a2e7687Sjeremylt   ierr = CeedCalloc(16, &impl->outdata); CeedChk(ierr);
151*4a2e7687Sjeremylt   // Set up infield and outfield pointer arrays
152*4a2e7687Sjeremylt   // Infields
153*4a2e7687Sjeremylt   ierr = CeedOperatorSetupFields_Blocked(qf->inputfields, op->inputfields,
154*4a2e7687Sjeremylt                                      impl->blkrestr, impl->evecs,
155*4a2e7687Sjeremylt                                      impl->qdata, impl->qdata_alloc,
156*4a2e7687Sjeremylt                                      impl->indata, 0,
157*4a2e7687Sjeremylt                                      0, numinputfields, Q);
158*4a2e7687Sjeremylt   CeedChk(ierr);
159*4a2e7687Sjeremylt   // Outfields
160*4a2e7687Sjeremylt   ierr = CeedOperatorSetupFields_Blocked(qf->outputfields, op->outputfields,
161*4a2e7687Sjeremylt                                      impl->blkrestr, impl->evecs,
162*4a2e7687Sjeremylt                                      impl->qdata, impl->qdata_alloc,
163*4a2e7687Sjeremylt                                      impl->indata, numinputfields,
164*4a2e7687Sjeremylt                                      impl->numqin, numoutputfields, Q);
165*4a2e7687Sjeremylt   CeedChk(ierr);
166*4a2e7687Sjeremylt   // Input Qvecs
167*4a2e7687Sjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
168*4a2e7687Sjeremylt     CeedEvalMode emode = qf->inputfields[i].emode;
169*4a2e7687Sjeremylt     if ((emode != CEED_EVAL_NONE) && (emode != CEED_EVAL_WEIGHT))
170*4a2e7687Sjeremylt       impl->indata[i] =  impl->qdata[i];
171*4a2e7687Sjeremylt   }
172*4a2e7687Sjeremylt   // Output Qvecs
173*4a2e7687Sjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
174*4a2e7687Sjeremylt     CeedEvalMode emode = qf->outputfields[i].emode;
175*4a2e7687Sjeremylt     if (emode != CEED_EVAL_NONE)
176*4a2e7687Sjeremylt       impl->outdata[i] =  impl->qdata[i + numinputfields];
177*4a2e7687Sjeremylt   }
178*4a2e7687Sjeremylt 
179*4a2e7687Sjeremylt   op->setupdone = 1;
180*4a2e7687Sjeremylt 
181*4a2e7687Sjeremylt   return 0;
182*4a2e7687Sjeremylt }
183*4a2e7687Sjeremylt 
184*4a2e7687Sjeremylt static int CeedOperatorApply_Blocked(CeedOperator op, CeedVector invec,
185*4a2e7687Sjeremylt                                  CeedVector outvec, CeedRequest *request) {
186*4a2e7687Sjeremylt   CeedOperator_Blocked *impl = op->data;
187*4a2e7687Sjeremylt   const CeedInt blksize = 8;
188*4a2e7687Sjeremylt   CeedInt Q = op->numqpoints, elemsize, numinputfields, numoutputfields,
189*4a2e7687Sjeremylt           nblks = (op->numelements/blksize) + !!(op->numelements%blksize);
190*4a2e7687Sjeremylt   int ierr;
191*4a2e7687Sjeremylt   CeedQFunction qf = op->qf;
192*4a2e7687Sjeremylt   CeedTransposeMode lmode = CEED_NOTRANSPOSE;
193*4a2e7687Sjeremylt 
194*4a2e7687Sjeremylt   // Setup
195*4a2e7687Sjeremylt   ierr = CeedOperatorSetup_Blocked(op); CeedChk(ierr);
196*4a2e7687Sjeremylt   ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
197*4a2e7687Sjeremylt   CeedChk(ierr);
198*4a2e7687Sjeremylt 
199*4a2e7687Sjeremylt   // Input Evecs and Restriction
200*4a2e7687Sjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
201*4a2e7687Sjeremylt     CeedEvalMode emode = qf->inputfields[i].emode;
202*4a2e7687Sjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
203*4a2e7687Sjeremylt     } else {
204*4a2e7687Sjeremylt       // Active
205*4a2e7687Sjeremylt       // Restrict
206*4a2e7687Sjeremylt       if (op->inputfields[i].vec == CEED_VECTOR_ACTIVE) {
207*4a2e7687Sjeremylt         ierr = CeedElemRestrictionApply(impl->blkrestr[i], CEED_NOTRANSPOSE,
208*4a2e7687Sjeremylt                                         lmode, invec, impl->evecs[i],
209*4a2e7687Sjeremylt                                         request); CeedChk(ierr); CeedChk(ierr);
210*4a2e7687Sjeremylt       } else {
211*4a2e7687Sjeremylt         // Passive
212*4a2e7687Sjeremylt         // Restrict
213*4a2e7687Sjeremylt         ierr = CeedElemRestrictionApply(impl->blkrestr[i], CEED_NOTRANSPOSE,
214*4a2e7687Sjeremylt                                         lmode, op->inputfields[i].vec, impl->evecs[i],
215*4a2e7687Sjeremylt                                         request); CeedChk(ierr);
216*4a2e7687Sjeremylt       }
217*4a2e7687Sjeremylt       // Get evec
218*4a2e7687Sjeremylt       ierr = CeedVectorGetArrayRead(impl->evecs[i], CEED_MEM_HOST,
219*4a2e7687Sjeremylt                                     (const CeedScalar **) &impl->edata[i]);
220*4a2e7687Sjeremylt       CeedChk(ierr);
221*4a2e7687Sjeremylt     }
222*4a2e7687Sjeremylt   }
223*4a2e7687Sjeremylt 
224*4a2e7687Sjeremylt   // Output Evecs
225*4a2e7687Sjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
226*4a2e7687Sjeremylt     ierr = CeedVectorGetArray(impl->evecs[i+impl->numein], CEED_MEM_HOST,
227*4a2e7687Sjeremylt                               &impl->edata[i + numinputfields]); CeedChk(ierr);
228*4a2e7687Sjeremylt   }
229*4a2e7687Sjeremylt 
230*4a2e7687Sjeremylt   // Loop through elements
231*4a2e7687Sjeremylt   for (CeedInt e=0; e<nblks*blksize; e+=blksize) {
232*4a2e7687Sjeremylt     // Input basis apply if needed
233*4a2e7687Sjeremylt     for (CeedInt i=0; i<numinputfields; i++) {
234*4a2e7687Sjeremylt       // Get elemsize, emode, ncomp
235*4a2e7687Sjeremylt       elemsize = op->inputfields[i].Erestrict->elemsize;
236*4a2e7687Sjeremylt       CeedEvalMode emode = qf->inputfields[i].emode;
237*4a2e7687Sjeremylt       CeedInt ncomp = qf->inputfields[i].ncomp;
238*4a2e7687Sjeremylt       // Basis action
239*4a2e7687Sjeremylt       switch(emode) {
240*4a2e7687Sjeremylt       case CEED_EVAL_NONE:
241*4a2e7687Sjeremylt         impl->indata[i] = &impl->edata[i][e*Q*ncomp];
242*4a2e7687Sjeremylt         break;
243*4a2e7687Sjeremylt       case CEED_EVAL_INTERP:
244*4a2e7687Sjeremylt         ierr = CeedBasisApply(op->inputfields[i].basis, blksize, CEED_NOTRANSPOSE,
245*4a2e7687Sjeremylt                               CEED_EVAL_INTERP, &impl->edata[i][e*elemsize*ncomp], impl->qdata[i]);
246*4a2e7687Sjeremylt         CeedChk(ierr);
247*4a2e7687Sjeremylt         break;
248*4a2e7687Sjeremylt       case CEED_EVAL_GRAD:
249*4a2e7687Sjeremylt         ierr = CeedBasisApply(op->inputfields[i].basis, blksize, CEED_NOTRANSPOSE,
250*4a2e7687Sjeremylt                               CEED_EVAL_GRAD, &impl->edata[i][e*elemsize*ncomp], impl->qdata[i]);
251*4a2e7687Sjeremylt         CeedChk(ierr);
252*4a2e7687Sjeremylt         break;
253*4a2e7687Sjeremylt       case CEED_EVAL_WEIGHT:
254*4a2e7687Sjeremylt         break;  // No action
255*4a2e7687Sjeremylt       case CEED_EVAL_DIV:
256*4a2e7687Sjeremylt         break; // Not implimented
257*4a2e7687Sjeremylt       case CEED_EVAL_CURL:
258*4a2e7687Sjeremylt         break; // Not implimented
259*4a2e7687Sjeremylt       }
260*4a2e7687Sjeremylt     }
261*4a2e7687Sjeremylt 
262*4a2e7687Sjeremylt     // Output pointers
263*4a2e7687Sjeremylt     for (CeedInt i=0; i<numoutputfields; i++) {
264*4a2e7687Sjeremylt       CeedEvalMode emode = qf->outputfields[i].emode;
265*4a2e7687Sjeremylt       if (emode == CEED_EVAL_NONE) {
266*4a2e7687Sjeremylt         CeedInt ncomp = qf->outputfields[i].ncomp;
267*4a2e7687Sjeremylt         impl->outdata[i] = &impl->edata[i + numinputfields][e*Q*ncomp];
268*4a2e7687Sjeremylt       }
269*4a2e7687Sjeremylt     }
270*4a2e7687Sjeremylt     // Q function
271*4a2e7687Sjeremylt     ierr = CeedQFunctionApply(op->qf, Q*blksize,
272*4a2e7687Sjeremylt                               (const CeedScalar * const*) impl->indata,
273*4a2e7687Sjeremylt                               impl->outdata); CeedChk(ierr);
274*4a2e7687Sjeremylt 
275*4a2e7687Sjeremylt     // Output basis apply if needed
276*4a2e7687Sjeremylt     for (CeedInt i=0; i<numoutputfields; i++) {
277*4a2e7687Sjeremylt       // Get elemsize, emode, ncomp
278*4a2e7687Sjeremylt       elemsize = op->outputfields[i].Erestrict->elemsize;
279*4a2e7687Sjeremylt       CeedInt ncomp = qf->outputfields[i].ncomp;
280*4a2e7687Sjeremylt       CeedEvalMode emode = qf->outputfields[i].emode;
281*4a2e7687Sjeremylt       // Basis action
282*4a2e7687Sjeremylt       switch(emode) {
283*4a2e7687Sjeremylt       case CEED_EVAL_NONE:
284*4a2e7687Sjeremylt         break; // No action
285*4a2e7687Sjeremylt       case CEED_EVAL_INTERP:
286*4a2e7687Sjeremylt         ierr = CeedBasisApply(op->outputfields[i].basis, blksize, CEED_TRANSPOSE,
287*4a2e7687Sjeremylt                               CEED_EVAL_INTERP, impl->outdata[i],
288*4a2e7687Sjeremylt                               &impl->edata[i + numinputfields][e*elemsize*ncomp]);
289*4a2e7687Sjeremylt         CeedChk(ierr);
290*4a2e7687Sjeremylt         break;
291*4a2e7687Sjeremylt       case CEED_EVAL_GRAD:
292*4a2e7687Sjeremylt         ierr = CeedBasisApply(op->outputfields[i].basis, blksize, CEED_TRANSPOSE,
293*4a2e7687Sjeremylt                               CEED_EVAL_GRAD,
294*4a2e7687Sjeremylt                               impl->outdata[i], &impl->edata[i + numinputfields][e*elemsize*ncomp]);
295*4a2e7687Sjeremylt         CeedChk(ierr);
296*4a2e7687Sjeremylt         break;
297*4a2e7687Sjeremylt       case CEED_EVAL_WEIGHT:
298*4a2e7687Sjeremylt         return CeedError(op->ceed, 1,
299*4a2e7687Sjeremylt                          "CEED_EVAL_WEIGHT cannot be an output evaluation mode");
300*4a2e7687Sjeremylt         break; // Should not occur
301*4a2e7687Sjeremylt       case CEED_EVAL_DIV:
302*4a2e7687Sjeremylt         break; // Not implimented
303*4a2e7687Sjeremylt       case CEED_EVAL_CURL:
304*4a2e7687Sjeremylt         break; // Not implimented
305*4a2e7687Sjeremylt       }
306*4a2e7687Sjeremylt     }
307*4a2e7687Sjeremylt   }
308*4a2e7687Sjeremylt 
309*4a2e7687Sjeremylt   // Zero lvecs
310*4a2e7687Sjeremylt   ierr = CeedVectorSetValue(outvec, 0.0); CeedChk(ierr);
311*4a2e7687Sjeremylt   for (CeedInt i=0; i<qf->numoutputfields; i++)
312*4a2e7687Sjeremylt     if (op->outputfields[i].vec != CEED_VECTOR_ACTIVE) {
313*4a2e7687Sjeremylt       ierr = CeedVectorSetValue(op->outputfields[i].vec, 0.0); CeedChk(ierr);
314*4a2e7687Sjeremylt     }
315*4a2e7687Sjeremylt 
316*4a2e7687Sjeremylt   // Output restriction
317*4a2e7687Sjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
318*4a2e7687Sjeremylt     // Restore evec
319*4a2e7687Sjeremylt     ierr = CeedVectorRestoreArray(impl->evecs[i+impl->numein],
320*4a2e7687Sjeremylt                                   &impl->edata[i + numinputfields]); CeedChk(ierr);
321*4a2e7687Sjeremylt     // Active
322*4a2e7687Sjeremylt     if (op->outputfields[i].vec == CEED_VECTOR_ACTIVE) {
323*4a2e7687Sjeremylt       // Restrict
324*4a2e7687Sjeremylt       ierr = CeedElemRestrictionApply(impl->blkrestr[i+impl->numein], CEED_TRANSPOSE,
325*4a2e7687Sjeremylt                                       lmode, impl->evecs[i+impl->numein], outvec, request); CeedChk(ierr);
326*4a2e7687Sjeremylt     } else {
327*4a2e7687Sjeremylt       // Passive
328*4a2e7687Sjeremylt       // Restrict
329*4a2e7687Sjeremylt       ierr = CeedElemRestrictionApply(impl->blkrestr[i+impl->numein], CEED_TRANSPOSE,
330*4a2e7687Sjeremylt                                       lmode, impl->evecs[i+impl->numein], op->outputfields[i].vec,
331*4a2e7687Sjeremylt                                       request); CeedChk(ierr);
332*4a2e7687Sjeremylt     }
333*4a2e7687Sjeremylt   }
334*4a2e7687Sjeremylt 
335*4a2e7687Sjeremylt   // Restore input arrays
336*4a2e7687Sjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
337*4a2e7687Sjeremylt     CeedEvalMode emode = qf->inputfields[i].emode;
338*4a2e7687Sjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
339*4a2e7687Sjeremylt     } else {
340*4a2e7687Sjeremylt       ierr = CeedVectorRestoreArrayRead(impl->evecs[i],
341*4a2e7687Sjeremylt                                         (const CeedScalar **) &impl->edata[i]); CeedChk(ierr);
342*4a2e7687Sjeremylt     }
343*4a2e7687Sjeremylt   }
344*4a2e7687Sjeremylt 
345*4a2e7687Sjeremylt   return 0;
346*4a2e7687Sjeremylt }
347*4a2e7687Sjeremylt 
348*4a2e7687Sjeremylt int CeedOperatorCreate_Blocked(CeedOperator op) {
349*4a2e7687Sjeremylt   CeedOperator_Blocked *impl;
350*4a2e7687Sjeremylt   int ierr;
351*4a2e7687Sjeremylt 
352*4a2e7687Sjeremylt   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
353*4a2e7687Sjeremylt   op->data = impl;
354*4a2e7687Sjeremylt   op->Destroy = CeedOperatorDestroy_Blocked;
355*4a2e7687Sjeremylt   op->Apply = CeedOperatorApply_Blocked;
356*4a2e7687Sjeremylt   return 0;
357*4a2e7687Sjeremylt }
358