xref: /libCEED/interface/ceed-fortran.c (revision 91dfd1cde504855b06db4052ed3242027f67af19)
1 // Copyright (c) 2017-2018, Lawrence Livermore National Security, LLC.
2 // Produced at the Lawrence Livermore National Laboratory. LLNL-CODE-734707.
3 // All Rights reserved. See files LICENSE and NOTICE for details.
4 //
5 // This file is part of CEED, a collection of benchmarks, miniapps, software
6 // libraries and APIs for efficient high-order finite element and spectral
7 // element discretizations for exascale applications. For more information and
8 // source code availability see http://github.com/ceed.
9 //
10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11 // a collaborative effort of two U.S. Department of Energy organizations (Office
12 // of Science and the National Nuclear Security Administration) responsible for
13 // the planning and preparation of a capable exascale ecosystem, including
14 // software, applications, hardware, advanced system engineering and early
15 // testbed platforms, in support of the nation's exascale computing imperative.
16 
17 // Fortran interface
18 #include <ceed.h>
19 #include <ceed-impl.h>
20 #include <ceed-backend.h>
21 #include <ceed-fortran-name.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #define FORTRAN_REQUEST_IMMEDIATE -1
26 #define FORTRAN_REQUEST_ORDERED -2
27 #define FORTRAN_NULL -3
28 #define FORTRAN_STRIDES_BACKEND -4
29 #define FORTRAN_VECTOR_ACTIVE -5
30 #define FORTRAN_VECTOR_NONE -6
31 #define FORTRAN_ELEMRESTRICTION_NONE -7
32 #define FORTRAN_BASIS_COLLOCATED -8
33 #define FORTRAN_QFUNCTION_NONE -9
34 
35 static Ceed *Ceed_dict = NULL;
36 static int Ceed_count = 0;
37 static int Ceed_n = 0;
38 static int Ceed_count_max = 0;
39 
40 // This test should actually be for the gfortran version, but we don't currently
41 // have a configure system to determine that (TODO).  At present, this will use
42 // the smaller integer when run with clang+gfortran=8, for example.  (That is
43 // sketchy, but will likely work for users that don't have huge character
44 // strings.)
45 #if __GNUC__ >= 8
46 typedef size_t fortran_charlen_t;
47 #else
48 typedef int fortran_charlen_t;
49 #endif
50 
51 #define Splice(a, b) a ## b
52 
53 // Fortran strings are generally unterminated and the length is passed as an
54 // extra argument after all the normal arguments.  Some compilers (I only know
55 // of Windows) place the length argument immediately after the string parameter
56 // (TODO).
57 //
58 // We can't just NULL-terminate the string in-place because that could overwrite
59 // other strings or attempt to write to read-only memory.  This macro allocates
60 // a string to hold the null-terminated version of the string that C expects.
61 #define FIX_STRING(stringname)                                          \
62   char Splice(stringname, _c)[1024];                                    \
63   if (Splice(stringname, _len) > 1023)                                  \
64     CeedError(NULL, 1, "Fortran string length too long %zd", (size_t)Splice(stringname, _len)); \
65   strncpy(Splice(stringname, _c), stringname, Splice(stringname, _len)); \
66   Splice(stringname, _c)[Splice(stringname, _len)] = 0;                 \
67 
68 // -----------------------------------------------------------------------------
69 // Ceed
70 // -----------------------------------------------------------------------------
71 #define fCeedInit FORTRAN_NAME(ceedinit,CEEDINIT)
72 void fCeedInit(const char *resource, int *ceed, int *err,
73                fortran_charlen_t resource_len) {
74   FIX_STRING(resource);
75   if (Ceed_count == Ceed_count_max) {
76     Ceed_count_max += Ceed_count_max/2 + 1;
77     CeedRealloc(Ceed_count_max, &Ceed_dict);
78   }
79 
80   Ceed *ceed_ = &Ceed_dict[Ceed_count];
81   *err = CeedInit(resource_c, ceed_);
82 
83   if (*err == 0) {
84     *ceed = Ceed_count++;
85     Ceed_n++;
86   }
87 }
88 
89 #define fCeedIsDeterministic \
90     FORTRAN_NAME(ceedisdeterministic,CEEDISDETERMINISTIC)
91 void fCeedIsDeterministic(int *ceed, int *isDeterministic, int *err) {
92   *err = CeedIsDeterministic(Ceed_dict[*ceed], (bool *)isDeterministic);
93 }
94 
95 #define fCeedGetPreferredMemType \
96     FORTRAN_NAME(ceedgetpreferredmemtype,CEEDGETPREFERREDMEMTYPE)
97 void fCeedGetPreferredMemType(int *ceed, int *type, int *err) {
98   *err = CeedGetPreferredMemType(Ceed_dict[*ceed], (CeedMemType *)type);
99 }
100 
101 #define fCeedView FORTRAN_NAME(ceedview,CEEDVIEW)
102 void fCeedView(int *ceed, int *err) {
103   *err = CeedView(Ceed_dict[*ceed], stdout);
104 }
105 
106 #define fCeedDestroy FORTRAN_NAME(ceeddestroy,CEEDDESTROY)
107 void fCeedDestroy(int *ceed, int *err) {
108   if (*ceed == FORTRAN_NULL) return;
109   *err = CeedDestroy(&Ceed_dict[*ceed]);
110 
111   if (*err == 0) {
112     *ceed = FORTRAN_NULL;
113     Ceed_n--;
114     if (Ceed_n == 0) {
115       CeedFree(&Ceed_dict);
116       Ceed_count = 0;
117       Ceed_count_max = 0;
118     }
119   }
120 }
121 
122 // -----------------------------------------------------------------------------
123 // CeedVector
124 // -----------------------------------------------------------------------------
125 static CeedVector *CeedVector_dict = NULL;
126 static int CeedVector_count = 0;
127 static int CeedVector_n = 0;
128 static int CeedVector_count_max = 0;
129 
130 #define fCeedVectorCreate FORTRAN_NAME(ceedvectorcreate,CEEDVECTORCREATE)
131 void fCeedVectorCreate(int *ceed, int *length, int *vec, int *err) {
132   if (CeedVector_count == CeedVector_count_max) {
133     CeedVector_count_max += CeedVector_count_max/2 + 1;
134     CeedRealloc(CeedVector_count_max, &CeedVector_dict);
135   }
136 
137   CeedVector *vec_ = &CeedVector_dict[CeedVector_count];
138   *err = CeedVectorCreate(Ceed_dict[*ceed], *length, vec_);
139 
140   if (*err == 0) {
141     *vec = CeedVector_count++;
142     CeedVector_n++;
143   }
144 }
145 
146 #define fCeedVectorSetArray FORTRAN_NAME(ceedvectorsetarray,CEEDVECTORSETARRAY)
147 void fCeedVectorSetArray(int *vec, int *memtype, int *copymode,
148                          CeedScalar *array, int64_t *offset, int *err) {
149   *err = CeedVectorSetArray(CeedVector_dict[*vec], (CeedMemType)*memtype,
150                             (CeedCopyMode)*copymode,
151                             (CeedScalar *)(array + *offset));
152 }
153 
154 #define fCeedVectorTakeArray FORTRAN_NAME(ceedvectortakearray,CEEDVECTORTAKEARRAY)
155 void fCeedVectorTakeArray(int *vec, int *memtype, CeedScalar *array,
156                           int64_t *offset, int *err) {
157   CeedScalar *b;
158   CeedVector vec_ = CeedVector_dict[*vec];
159   *err = CeedVectorTakeArray(vec_, (CeedMemType)*memtype, &b);
160   *offset = b - array;
161 }
162 
163 #define fCeedVectorSyncArray FORTRAN_NAME(ceedvectorsyncarray,CEEDVECTORSYNCARRAY)
164 void fCeedVectorSyncArray(int *vec, int *memtype, int *err) {
165   *err = CeedVectorSyncArray(CeedVector_dict[*vec], (CeedMemType)*memtype);
166 }
167 
168 #define fCeedVectorSetValue FORTRAN_NAME(ceedvectorsetvalue,CEEDVECTORSETVALUE)
169 void fCeedVectorSetValue(int *vec, CeedScalar *value, int *err) {
170   *err = CeedVectorSetValue(CeedVector_dict[*vec], *value);
171 }
172 
173 #define fCeedVectorGetArray FORTRAN_NAME(ceedvectorgetarray,CEEDVECTORGETARRAY)
174 void fCeedVectorGetArray(int *vec, int *memtype, CeedScalar *array,
175                          int64_t *offset, int *err) {
176   CeedScalar *b;
177   CeedVector vec_ = CeedVector_dict[*vec];
178   *err = CeedVectorGetArray(vec_, (CeedMemType)*memtype, &b);
179   *offset = b - array;
180 }
181 
182 #define fCeedVectorGetArrayRead \
183     FORTRAN_NAME(ceedvectorgetarrayread,CEEDVECTORGETARRAYREAD)
184 void fCeedVectorGetArrayRead(int *vec, int *memtype, CeedScalar *array,
185                              int64_t *offset, int *err) {
186   const CeedScalar *b;
187   CeedVector vec_ = CeedVector_dict[*vec];
188   *err = CeedVectorGetArrayRead(vec_, (CeedMemType)*memtype, &b);
189   *offset = b - array;
190 }
191 
192 #define fCeedVectorRestoreArray \
193     FORTRAN_NAME(ceedvectorrestorearray,CEEDVECTORRESTOREARRAY)
194 void fCeedVectorRestoreArray(int *vec, CeedScalar *array,
195                              int64_t *offset, int *err) {
196   *err = CeedVectorRestoreArray(CeedVector_dict[*vec], &array);
197   *offset = 0;
198 }
199 
200 #define fCeedVectorRestoreArrayRead \
201     FORTRAN_NAME(ceedvectorrestorearrayread,CEEDVECTORRESTOREARRAYREAD)
202 void fCeedVectorRestoreArrayRead(int *vec, const CeedScalar *array,
203                                  int64_t *offset, int *err) {
204   *err = CeedVectorRestoreArrayRead(CeedVector_dict[*vec], &array);
205   *offset = 0;
206 }
207 
208 #define fCeedVectorNorm \
209     FORTRAN_NAME(ceedvectornorm,CEEDVECTORNORM)
210 void fCeedVectorNorm(int *vec, int *type, CeedScalar *norm, int *err) {
211   *err = CeedVectorNorm(CeedVector_dict[*vec], (CeedNormType)*type, norm);
212 }
213 
214 #define fCeedVectorReciprocal \
215     FORTRAN_NAME(ceedvectorreciprocal,CEEDVECTORRECIPROCAL)
216 void fCeedVectorReciprocal(int *vec, int *err) {
217   *err = CeedVectorReciprocal(CeedVector_dict[*vec]);
218 }
219 
220 #define fCeedVectorView FORTRAN_NAME(ceedvectorview,CEEDVECTORVIEW)
221 void fCeedVectorView(int *vec, int *err) {
222   *err = CeedVectorView(CeedVector_dict[*vec], "%12.8f", stdout);
223 }
224 
225 #define fCeedVectorDestroy FORTRAN_NAME(ceedvectordestroy,CEEDVECTORDESTROY)
226 void fCeedVectorDestroy(int *vec, int *err) {
227   if (*vec == FORTRAN_NULL) return;
228   *err = CeedVectorDestroy(&CeedVector_dict[*vec]);
229 
230   if (*err == 0) {
231     *vec = FORTRAN_NULL;
232     CeedVector_n--;
233     if (CeedVector_n == 0) {
234       CeedFree(&CeedVector_dict);
235       CeedVector_count = 0;
236       CeedVector_count_max = 0;
237     }
238   }
239 }
240 
241 // -----------------------------------------------------------------------------
242 // CeedElemRestriction
243 // -----------------------------------------------------------------------------
244 static CeedElemRestriction *CeedElemRestriction_dict = NULL;
245 static int CeedElemRestriction_count = 0;
246 static int CeedElemRestriction_n = 0;
247 static int CeedElemRestriction_count_max = 0;
248 
249 #define fCeedElemRestrictionCreate \
250     FORTRAN_NAME(ceedelemrestrictioncreate, CEEDELEMRESTRICTIONCREATE)
251 void fCeedElemRestrictionCreate(int *ceed, int *nelements, int *esize,
252                                 int *ncomp, int *compstride, int *lsize,
253                                 int *memtype, int *copymode, const int *offsets,
254                                 int *elemrestriction, int *err) {
255   if (CeedElemRestriction_count == CeedElemRestriction_count_max) {
256     CeedElemRestriction_count_max += CeedElemRestriction_count_max/2 + 1;
257     CeedRealloc(CeedElemRestriction_count_max, &CeedElemRestriction_dict);
258   }
259 
260   const int *offsets_ = offsets;
261 
262   CeedElemRestriction *elemrestriction_ =
263     &CeedElemRestriction_dict[CeedElemRestriction_count];
264   *err = CeedElemRestrictionCreate(Ceed_dict[*ceed], *nelements, *esize,
265                                    *ncomp, *compstride, *lsize,
266                                    (CeedMemType)*memtype,
267                                    (CeedCopyMode)*copymode, offsets_,
268                                    elemrestriction_);
269 
270   if (*err == 0) {
271     *elemrestriction = CeedElemRestriction_count++;
272     CeedElemRestriction_n++;
273   }
274 }
275 
276 #define fCeedElemRestrictionCreateStrided \
277     FORTRAN_NAME(ceedelemrestrictioncreatestrided, CEEDELEMRESTRICTIONCREATESTRIDED)
278 void fCeedElemRestrictionCreateStrided(int *ceed, int *nelements, int *esize,
279                                        int *ncomp, int *lsize, int *strides,
280                                        int *elemrestriction, int *err) {
281   if (CeedElemRestriction_count == CeedElemRestriction_count_max) {
282     CeedElemRestriction_count_max += CeedElemRestriction_count_max/2 + 1;
283     CeedRealloc(CeedElemRestriction_count_max, &CeedElemRestriction_dict);
284   }
285 
286   CeedElemRestriction *elemrestriction_ =
287     &CeedElemRestriction_dict[CeedElemRestriction_count];
288   *err = CeedElemRestrictionCreateStrided(Ceed_dict[*ceed], *nelements, *esize,
289                                           *ncomp, *lsize,
290                                           *strides == FORTRAN_STRIDES_BACKEND ?
291                                           CEED_STRIDES_BACKEND : strides,
292                                           elemrestriction_);
293   if (*err == 0) {
294     *elemrestriction = CeedElemRestriction_count++;
295     CeedElemRestriction_n++;
296   }
297 }
298 
299 #define fCeedElemRestrictionCreateBlocked \
300     FORTRAN_NAME(ceedelemrestrictioncreateblocked,CEEDELEMRESTRICTIONCREATEBLOCKED)
301 void fCeedElemRestrictionCreateBlocked(int *ceed, int *nelements, int *esize,
302                                        int *blocksize, int *ncomp,
303                                        int *compstride, int *lsize,
304                                        int *mtype, int *cmode,
305                                        int *blkindices, int *elemrestriction,
306                                        int *err) {
307 
308   if (CeedElemRestriction_count == CeedElemRestriction_count_max) {
309     CeedElemRestriction_count_max += CeedElemRestriction_count_max/2 + 1;
310     CeedRealloc(CeedElemRestriction_count_max, &CeedElemRestriction_dict);
311   }
312 
313   CeedElemRestriction *elemrestriction_ =
314     &CeedElemRestriction_dict[CeedElemRestriction_count];
315   *err = CeedElemRestrictionCreateBlocked(Ceed_dict[*ceed],
316                                           *nelements, *esize, *blocksize,
317                                           *ncomp, *compstride, *lsize,
318                                           (CeedMemType)*mtype,
319                                           (CeedCopyMode)*cmode, blkindices,
320                                           elemrestriction_);
321 
322   if (*err == 0) {
323     *elemrestriction = CeedElemRestriction_count++;
324     CeedElemRestriction_n++;
325   }
326 }
327 
328 #define fCeedElemRestrictionCreateBlockedStrided \
329     FORTRAN_NAME(ceedelemrestrictioncreateblockedstrided, CEEDELEMRESTRICTIONCREATEBLOCKEDSTRIDED)
330 void fCeedElemRestrictionCreateBlockedStrided(int *ceed, int *nelements,
331     int *esize, int *blksize, int *ncomp, int *lsize, int *strides,
332     int *elemrestriction, int *err) {
333   if (CeedElemRestriction_count == CeedElemRestriction_count_max) {
334     CeedElemRestriction_count_max += CeedElemRestriction_count_max/2 + 1;
335     CeedRealloc(CeedElemRestriction_count_max, &CeedElemRestriction_dict);
336   }
337 
338   CeedElemRestriction *elemrestriction_ =
339     &CeedElemRestriction_dict[CeedElemRestriction_count];
340   *err = CeedElemRestrictionCreateBlockedStrided(Ceed_dict[*ceed], *nelements,
341          *esize, *blksize, *ncomp, *lsize, strides, elemrestriction_);
342   if (*err == 0) {
343     *elemrestriction = CeedElemRestriction_count++;
344     CeedElemRestriction_n++;
345   }
346 }
347 
348 static CeedRequest *CeedRequest_dict = NULL;
349 static int CeedRequest_count = 0;
350 static int CeedRequest_n = 0;
351 static int CeedRequest_count_max = 0;
352 
353 #define fCeedElemRestrictionApply \
354     FORTRAN_NAME(ceedelemrestrictionapply,CEEDELEMRESTRICTIONAPPLY)
355 void fCeedElemRestrictionApply(int *elemr, int *tmode, int *uvec, int *ruvec,
356                                int *rqst, int *err) {
357   int createRequest = 1;
358   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
359   if (*rqst == FORTRAN_REQUEST_IMMEDIATE || *rqst == FORTRAN_REQUEST_ORDERED)
360     createRequest = 0;
361 
362   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
363     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
364     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
365   }
366 
367   CeedRequest *rqst_;
368   if      (*rqst == FORTRAN_REQUEST_IMMEDIATE) rqst_ = CEED_REQUEST_IMMEDIATE;
369   else if (*rqst == FORTRAN_REQUEST_ORDERED  ) rqst_ = CEED_REQUEST_ORDERED;
370   else rqst_ = &CeedRequest_dict[CeedRequest_count];
371 
372   *err = CeedElemRestrictionApply(CeedElemRestriction_dict[*elemr],
373                                   (CeedTransposeMode)*tmode,
374                                   CeedVector_dict[*uvec],
375                                   CeedVector_dict[*ruvec], rqst_);
376 
377   if (*err == 0 && createRequest) {
378     *rqst = CeedRequest_count++;
379     CeedRequest_n++;
380   }
381 }
382 
383 #define fCeedElemRestrictionApplyBlock \
384     FORTRAN_NAME(ceedelemrestrictionapplyblock,CEEDELEMRESTRICTIONAPPLYBLOCK)
385 void fCeedElemRestrictionApplyBlock(int *elemr, int *block, int *tmode,
386                                     int *uvec, int *ruvec, int *rqst, int *err) {
387   int createRequest = 1;
388   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
389   if (*rqst == FORTRAN_REQUEST_IMMEDIATE || *rqst == FORTRAN_REQUEST_ORDERED)
390     createRequest = 0;
391 
392   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
393     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
394     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
395   }
396 
397   CeedRequest *rqst_;
398   if      (*rqst == FORTRAN_REQUEST_IMMEDIATE) rqst_ = CEED_REQUEST_IMMEDIATE;
399   else if (*rqst == FORTRAN_REQUEST_ORDERED  ) rqst_ = CEED_REQUEST_ORDERED;
400   else rqst_ = &CeedRequest_dict[CeedRequest_count];
401 
402   *err = CeedElemRestrictionApplyBlock(CeedElemRestriction_dict[*elemr], *block,
403                                        (CeedTransposeMode)*tmode, CeedVector_dict[*uvec],
404                                        CeedVector_dict[*ruvec], rqst_);
405 
406   if (*err == 0 && createRequest) {
407     *rqst = CeedRequest_count++;
408     CeedRequest_n++;
409   }
410 }
411 
412 #define fCeedElemRestrictionGetMultiplicity \
413     FORTRAN_NAME(ceedelemrestrictiongetmultiplicity,CEEDELEMRESTRICTIONGETMULTIPLICITY)
414 void fCeedElemRestrictionGetMultiplicity(int *elemr, int *mult, int *err) {
415   *err = CeedElemRestrictionGetMultiplicity(CeedElemRestriction_dict[*elemr],
416          CeedVector_dict[*mult]);
417 }
418 
419 #define fCeedElemRestrictionGetELayout \
420     FORTRAN_NAME(ceedelemrestrictiongetelayout,CEEDELEMRESTRICTIONGETELAYOUT)
421 void fCeedElemRestrictionGetELayout(int *elemr, int *layout, int *err) {
422   CeedInt layout_c[3];
423   *err = CeedElemRestrictionGetELayout(CeedElemRestriction_dict[*elemr],
424                                        &layout_c);
425   for (int i=0; i<3; i++)
426     layout[i] = layout_c[i];
427 }
428 
429 #define fCeedElemRestrictionView \
430     FORTRAN_NAME(ceedelemrestrictionview,CEEDELEMRESTRICTIONVIEW)
431 void fCeedElemRestrictionView(int *elemr, int *err) {
432   *err = CeedElemRestrictionView(CeedElemRestriction_dict[*elemr], stdout);
433 }
434 
435 #define fCeedRequestWait FORTRAN_NAME(ceedrequestwait, CEEDREQUESTWAIT)
436 void fCeedRequestWait(int *rqst, int *err) {
437   // TODO Uncomment this once CeedRequestWait is implemented
438   //*err = CeedRequestWait(&CeedRequest_dict[*rqst]);
439 
440   if (*err == 0) {
441     CeedRequest_n--;
442     if (CeedRequest_n == 0) {
443       CeedFree(&CeedRequest_dict);
444       CeedRequest_count = 0;
445       CeedRequest_count_max = 0;
446     }
447   }
448 }
449 
450 #define fCeedElemRestrictionDestroy \
451     FORTRAN_NAME(ceedelemrestrictiondestroy,CEEDELEMRESTRICTIONDESTROY)
452 void fCeedElemRestrictionDestroy(int *elem, int *err) {
453   if (*elem == FORTRAN_NULL) return;
454   *err = CeedElemRestrictionDestroy(&CeedElemRestriction_dict[*elem]);
455 
456   if (*err == 0) {
457     *elem = FORTRAN_NULL;
458     CeedElemRestriction_n--;
459     if (CeedElemRestriction_n == 0) {
460       CeedFree(&CeedElemRestriction_dict);
461       CeedElemRestriction_count = 0;
462       CeedElemRestriction_count_max = 0;
463     }
464   }
465 }
466 
467 // -----------------------------------------------------------------------------
468 // CeedBasis
469 // -----------------------------------------------------------------------------
470 static CeedBasis *CeedBasis_dict = NULL;
471 static int CeedBasis_count = 0;
472 static int CeedBasis_n = 0;
473 static int CeedBasis_count_max = 0;
474 
475 #define fCeedBasisCreateTensorH1Lagrange \
476     FORTRAN_NAME(ceedbasiscreatetensorh1lagrange, CEEDBASISCREATETENSORH1LAGRANGE)
477 void fCeedBasisCreateTensorH1Lagrange(int *ceed, int *dim,
478                                       int *ncomp, int *P, int *Q, int *quadmode,
479                                       int *basis, int *err) {
480   if (CeedBasis_count == CeedBasis_count_max) {
481     CeedBasis_count_max += CeedBasis_count_max/2 + 1;
482     CeedRealloc(CeedBasis_count_max, &CeedBasis_dict);
483   }
484 
485   *err = CeedBasisCreateTensorH1Lagrange(Ceed_dict[*ceed], *dim, *ncomp, *P, *Q,
486                                          (CeedQuadMode)*quadmode,
487                                          &CeedBasis_dict[CeedBasis_count]);
488 
489   if (*err == 0) {
490     *basis = CeedBasis_count++;
491     CeedBasis_n++;
492   }
493 }
494 
495 #define fCeedBasisCreateTensorH1 \
496     FORTRAN_NAME(ceedbasiscreatetensorh1, CEEDBASISCREATETENSORH1)
497 void fCeedBasisCreateTensorH1(int *ceed, int *dim, int *ncomp, int *P1d,
498                               int *Q1d, const CeedScalar *interp1d,
499                               const CeedScalar *grad1d,
500                               const CeedScalar *qref1d,
501                               const CeedScalar *qweight1d, int *basis,
502                               int *err) {
503   if (CeedBasis_count == CeedBasis_count_max) {
504     CeedBasis_count_max += CeedBasis_count_max/2 + 1;
505     CeedRealloc(CeedBasis_count_max, &CeedBasis_dict);
506   }
507 
508   *err = CeedBasisCreateTensorH1(Ceed_dict[*ceed], *dim, *ncomp, *P1d, *Q1d,
509                                  interp1d, grad1d, qref1d, qweight1d,
510                                  &CeedBasis_dict[CeedBasis_count]);
511 
512   if (*err == 0) {
513     *basis = CeedBasis_count++;
514     CeedBasis_n++;
515   }
516 }
517 
518 #define fCeedBasisCreateH1 \
519     FORTRAN_NAME(ceedbasiscreateh1, CEEDBASISCREATEH1)
520 void fCeedBasisCreateH1(int *ceed, int *topo, int *ncomp, int *nnodes,
521                         int *nqpts, const CeedScalar *interp,
522                         const CeedScalar *grad, const CeedScalar *qref,
523                         const CeedScalar *qweight, int *basis, int *err) {
524   if (CeedBasis_count == CeedBasis_count_max) {
525     CeedBasis_count_max += CeedBasis_count_max/2 + 1;
526     CeedRealloc(CeedBasis_count_max, &CeedBasis_dict);
527   }
528 
529   *err = CeedBasisCreateH1(Ceed_dict[*ceed], (CeedElemTopology)*topo, *ncomp,
530                            *nnodes, *nqpts, interp, grad, qref, qweight,
531                            &CeedBasis_dict[CeedBasis_count]);
532 
533   if (*err == 0) {
534     *basis = CeedBasis_count++;
535     CeedBasis_n++;
536   }
537 }
538 
539 #define fCeedBasisView FORTRAN_NAME(ceedbasisview, CEEDBASISVIEW)
540 void fCeedBasisView(int *basis, int *err) {
541   *err = CeedBasisView(CeedBasis_dict[*basis], stdout);
542 }
543 
544 #define fCeedQRFactorization \
545     FORTRAN_NAME(ceedqrfactorization, CEEDQRFACTORIZATION)
546 void fCeedQRFactorization(int *ceed, CeedScalar *mat, CeedScalar *tau, int *m,
547                           int *n, int *err) {
548   *err = CeedQRFactorization(Ceed_dict[*ceed], mat, tau, *m, *n);
549 }
550 
551 #define fCeedSymmetricSchurDecomposition \
552     FORTRAN_NAME(ceedsymmetricschurdecomposition, CEEDSYMMETRICSCHURDECOMPOSITION)
553 void fCeedSymmetricSchurDecomposition(int *ceed, CeedScalar *mat,
554                                       CeedScalar *lambda, int *n, int *err) {
555   *err = CeedSymmetricSchurDecomposition(Ceed_dict[*ceed], mat, lambda, *n);
556 }
557 
558 #define fCeedSimultaneousDiagonalization \
559     FORTRAN_NAME(ceedsimultaneousdiagonalization, CEEDSIMULTANEOUSDIAGONALIZATION)
560 void fCeedSimultaneousDiagonalization(int *ceed, CeedScalar *matA,
561                                       CeedScalar *matB, CeedScalar *x,
562                                       CeedScalar *lambda, int *n, int *err) {
563   *err = CeedSimultaneousDiagonalization(Ceed_dict[*ceed], matA, matB, x,
564                                          lambda, *n);
565 }
566 
567 #define fCeedBasisGetCollocatedGrad \
568     FORTRAN_NAME(ceedbasisgetcollocatedgrad, CEEDBASISGETCOLLOCATEDGRAD)
569 void fCeedBasisGetCollocatedGrad(int *basis, CeedScalar *colograd1d,
570                                  int *err) {
571   *err = CeedBasisGetCollocatedGrad(CeedBasis_dict[*basis], colograd1d);
572 }
573 
574 #define fCeedBasisApply FORTRAN_NAME(ceedbasisapply, CEEDBASISAPPLY)
575 void fCeedBasisApply(int *basis, int *nelem, int *tmode, int *emode,
576                      int *u, int *v, int *err) {
577   *err = CeedBasisApply(CeedBasis_dict[*basis], *nelem, (CeedTransposeMode)*tmode,
578                         (CeedEvalMode)*emode,
579                         *u == FORTRAN_VECTOR_NONE ? CEED_VECTOR_NONE : CeedVector_dict[*u],
580                         CeedVector_dict[*v]);
581 }
582 
583 #define fCeedBasisGetNumNodes \
584     FORTRAN_NAME(ceedbasisgetnumnodes, CEEDBASISGETNUMNODES)
585 void fCeedBasisGetNumNodes(int *basis, int *P, int *err) {
586   *err = CeedBasisGetNumNodes(CeedBasis_dict[*basis], P);
587 }
588 
589 #define fCeedBasisGetNumQuadraturePoints \
590     FORTRAN_NAME(ceedbasisgetnumquadraturepoints, CEEDBASISGETNUMQUADRATUREPOINTS)
591 void fCeedBasisGetNumQuadraturePoints(int *basis, int *Q, int *err) {
592   *err = CeedBasisGetNumQuadraturePoints(CeedBasis_dict[*basis], Q);
593 }
594 
595 #define fCeedBasisGetInterp1D \
596     FORTRAN_NAME(ceedbasisgetinterp1d, CEEDBASISGETINTERP1D)
597 void fCeedBasisGetInterp1D(int *basis, CeedScalar *interp1d, int64_t *offset,
598                            int *err) {
599   const CeedScalar *interp1d_;
600   CeedBasis basis_ = CeedBasis_dict[*basis];
601   *err = CeedBasisGetInterp1D(basis_, &interp1d_);
602   *offset = interp1d_ - interp1d;
603 }
604 
605 #define fCeedBasisDestroy FORTRAN_NAME(ceedbasisdestroy,CEEDBASISDESTROY)
606 void fCeedBasisDestroy(int *basis, int *err) {
607   if (*basis == FORTRAN_NULL) return;
608   *err = CeedBasisDestroy(&CeedBasis_dict[*basis]);
609 
610   if (*err == 0) {
611     *basis = FORTRAN_NULL;
612     CeedBasis_n--;
613     if (CeedBasis_n == 0) {
614       CeedFree(&CeedBasis_dict);
615       CeedBasis_count = 0;
616       CeedBasis_count_max = 0;
617     }
618   }
619 }
620 
621 #define fCeedGaussQuadrature FORTRAN_NAME(ceedgaussquadrature, CEEDGAUSSQUADRATURE)
622 void fCeedGaussQuadrature(int *Q, CeedScalar *qref1d, CeedScalar *qweight1d,
623                           int *err) {
624   *err = CeedGaussQuadrature(*Q, qref1d, qweight1d);
625 }
626 
627 #define fCeedLobattoQuadrature \
628     FORTRAN_NAME(ceedlobattoquadrature, CEEDLOBATTOQUADRATURE)
629 void fCeedLobattoQuadrature(int *Q, CeedScalar *qref1d, CeedScalar *qweight1d,
630                             int *err) {
631   *err = CeedLobattoQuadrature(*Q, qref1d, qweight1d);
632 }
633 
634 // -----------------------------------------------------------------------------
635 // CeedQFunction
636 // -----------------------------------------------------------------------------
637 static CeedQFunction *CeedQFunction_dict = NULL;
638 static int CeedQFunction_count = 0;
639 static int CeedQFunction_n = 0;
640 static int CeedQFunction_count_max = 0;
641 
642 static int CeedQFunctionFortranStub(void *ctx, int nq,
643                                     const CeedScalar *const *u,
644                                     CeedScalar *const *v) {
645   fContext *fctx = ctx;
646   int ierr;
647 
648   CeedScalar *ctx_ = (CeedScalar *) fctx->innerctx;
649   fctx->f((void *)ctx_,&nq,u[0],u[1],u[2],u[3],u[4],u[5],u[6],
650           u[7],u[8],u[9],u[10],u[11],u[12],u[13],u[14],u[15],
651           v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],
652           v[10],v[11],v[12],v[13],v[14],v[15],&ierr);
653   return ierr;
654 }
655 
656 #define fCeedQFunctionCreateInterior \
657     FORTRAN_NAME(ceedqfunctioncreateinterior, CEEDQFUNCTIONCREATEINTERIOR)
658 void fCeedQFunctionCreateInterior(int *ceed, int *vlength,
659                                   void (*f)(void *ctx, int *nq,
660                                       const CeedScalar *u,const CeedScalar *u1,
661                                       const CeedScalar *u2,const CeedScalar *u3,
662                                       const CeedScalar *u4,const CeedScalar *u5,
663                                       const CeedScalar *u6,const CeedScalar *u7,
664                                       const CeedScalar *u8,const CeedScalar *u9,
665                                       const CeedScalar *u10,const CeedScalar *u11,
666                                       const CeedScalar *u12,const CeedScalar *u13,
667                                       const CeedScalar *u14,const CeedScalar *u15,
668                                       CeedScalar *v,CeedScalar *v1,CeedScalar *v2,
669                                       CeedScalar *v3,CeedScalar *v4,
670                                       CeedScalar *v5,CeedScalar *v6,
671                                       CeedScalar *v7,CeedScalar *v8,
672                                       CeedScalar *v9,CeedScalar *v10,
673                                       CeedScalar *v11,CeedScalar *v12,
674                                       CeedScalar *v13,CeedScalar *v14,
675                                       CeedScalar *v15,int *err),
676                                   const char *source, int *qf, int *err,
677                                   fortran_charlen_t source_len) {
678   FIX_STRING(source);
679   if (CeedQFunction_count == CeedQFunction_count_max) {
680     CeedQFunction_count_max += CeedQFunction_count_max/2 + 1;
681     CeedRealloc(CeedQFunction_count_max, &CeedQFunction_dict);
682   }
683 
684   CeedQFunction *qf_ = &CeedQFunction_dict[CeedQFunction_count];
685   *err = CeedQFunctionCreateInterior(Ceed_dict[*ceed], *vlength,
686                                      CeedQFunctionFortranStub, source_c, qf_);
687 
688   if (*err == 0) {
689     *qf = CeedQFunction_count++;
690     CeedQFunction_n++;
691   }
692 
693   fContext *fctx;
694   *err = CeedMalloc(1, &fctx);
695   if (*err) return;
696   fctx->f = f; fctx->innerctx = NULL; fctx->innerctxsize = 0;
697 
698   *err = CeedQFunctionSetContext(*qf_, fctx, sizeof(fContext));
699 
700   (*qf_)->fortranstatus = true;
701 }
702 
703 #define fCeedQFunctionCreateInteriorByName \
704     FORTRAN_NAME(ceedqfunctioncreateinteriorbyname, CEEDQFUNCTIONCREATEINTERIORBYNAME)
705 void fCeedQFunctionCreateInteriorByName(int *ceed, const char *name, int *qf,
706                                         int *err, fortran_charlen_t name_len) {
707   FIX_STRING(name);
708   if (CeedQFunction_count == CeedQFunction_count_max) {
709     CeedQFunction_count_max += CeedQFunction_count_max/2 + 1;
710     CeedRealloc(CeedQFunction_count_max, &CeedQFunction_dict);
711   }
712 
713   CeedQFunction *qf_ = &CeedQFunction_dict[CeedQFunction_count];
714   *err = CeedQFunctionCreateInteriorByName(Ceed_dict[*ceed], name_c, qf_);
715 
716   if (*err == 0) {
717     *qf = CeedQFunction_count++;
718     CeedQFunction_n++;
719   }
720 }
721 
722 #define fCeedQFunctionCreateIdentity \
723     FORTRAN_NAME(ceedqfunctioncreateidentity, CEEDQFUNCTIONCREATEIDENTITY)
724 void fCeedQFunctionCreateIdentity(int *ceed, int *size, int *inmode,
725                                   int *outmode, int *qf, int *err) {
726   if (CeedQFunction_count == CeedQFunction_count_max) {
727     CeedQFunction_count_max += CeedQFunction_count_max/2 + 1;
728     CeedRealloc(CeedQFunction_count_max, &CeedQFunction_dict);
729   }
730 
731   CeedQFunction *qf_ = &CeedQFunction_dict[CeedQFunction_count];
732   *err = CeedQFunctionCreateIdentity(Ceed_dict[*ceed], *size,
733                                      (CeedEvalMode)*inmode,
734                                      (CeedEvalMode)*outmode, qf_);
735 
736   if (*err == 0) {
737     *qf = CeedQFunction_count++;
738     CeedQFunction_n++;
739   }
740 }
741 
742 #define fCeedQFunctionAddInput \
743     FORTRAN_NAME(ceedqfunctionaddinput,CEEDQFUNCTIONADDINPUT)
744 void fCeedQFunctionAddInput(int *qf, const char *fieldname,
745                             CeedInt *ncomp, CeedEvalMode *emode, int *err,
746                             fortran_charlen_t fieldname_len) {
747   FIX_STRING(fieldname);
748   CeedQFunction qf_ = CeedQFunction_dict[*qf];
749 
750   *err = CeedQFunctionAddInput(qf_, fieldname_c, *ncomp, *emode);
751 }
752 
753 #define fCeedQFunctionAddOutput \
754     FORTRAN_NAME(ceedqfunctionaddoutput,CEEDQFUNCTIONADDOUTPUT)
755 void fCeedQFunctionAddOutput(int *qf, const char *fieldname,
756                              CeedInt *ncomp, CeedEvalMode *emode, int *err,
757                              fortran_charlen_t fieldname_len) {
758   FIX_STRING(fieldname);
759   CeedQFunction qf_ = CeedQFunction_dict[*qf];
760 
761   *err = CeedQFunctionAddOutput(qf_, fieldname_c, *ncomp, *emode);
762 }
763 
764 #define fCeedQFunctionSetContext \
765     FORTRAN_NAME(ceedqfunctionsetcontext,CEEDQFUNCTIONSETCONTEXT)
766 void fCeedQFunctionSetContext(int *qf, CeedScalar *ctx, CeedInt *n, int *err) {
767   CeedQFunction qf_ = CeedQFunction_dict[*qf];
768 
769   fContext *fctx = qf_->ctx;
770   fctx->innerctx = ctx;
771   fctx->innerctxsize = ((size_t) *n)*sizeof(CeedScalar);
772 }
773 
774 #define fCeedQFunctionView \
775     FORTRAN_NAME(ceedqfunctionview,CEEDQFUNCTIONVIEW)
776 void fCeedQFunctionView(int *qf, int *err) {
777   CeedQFunction qf_ = CeedQFunction_dict[*qf];
778 
779   *err = CeedQFunctionView(qf_, stdout);
780 }
781 
782 #define fCeedQFunctionApply \
783     FORTRAN_NAME(ceedqfunctionapply,CEEDQFUNCTIONAPPLY)
784 //TODO Need Fixing, double pointer
785 void fCeedQFunctionApply(int *qf, int *Q,
786                          int *u, int *u1, int *u2, int *u3,
787                          int *u4, int *u5, int *u6, int *u7,
788                          int *u8, int *u9, int *u10, int *u11,
789                          int *u12, int *u13, int *u14, int *u15,
790                          int *v, int *v1, int *v2, int *v3,
791                          int *v4, int *v5, int *v6, int *v7,
792                          int *v8, int *v9, int *v10, int *v11,
793                          int *v12, int *v13, int *v14, int *v15, int *err) {
794   CeedQFunction qf_ = CeedQFunction_dict[*qf];
795   CeedVector *in;
796   *err = CeedCalloc(16, &in);
797   if (*err) return;
798   in[0] = *u==FORTRAN_NULL?NULL:CeedVector_dict[*u];
799   in[1] = *u1==FORTRAN_NULL?NULL:CeedVector_dict[*u1];
800   in[2] = *u2==FORTRAN_NULL?NULL:CeedVector_dict[*u2];
801   in[3] = *u3==FORTRAN_NULL?NULL:CeedVector_dict[*u3];
802   in[4] = *u4==FORTRAN_NULL?NULL:CeedVector_dict[*u4];
803   in[5] = *u5==FORTRAN_NULL?NULL:CeedVector_dict[*u5];
804   in[6] = *u6==FORTRAN_NULL?NULL:CeedVector_dict[*u6];
805   in[7] = *u7==FORTRAN_NULL?NULL:CeedVector_dict[*u7];
806   in[8] = *u8==FORTRAN_NULL?NULL:CeedVector_dict[*u8];
807   in[9] = *u9==FORTRAN_NULL?NULL:CeedVector_dict[*u9];
808   in[10] = *u10==FORTRAN_NULL?NULL:CeedVector_dict[*u10];
809   in[11] = *u11==FORTRAN_NULL?NULL:CeedVector_dict[*u11];
810   in[12] = *u12==FORTRAN_NULL?NULL:CeedVector_dict[*u12];
811   in[13] = *u13==FORTRAN_NULL?NULL:CeedVector_dict[*u13];
812   in[14] = *u14==FORTRAN_NULL?NULL:CeedVector_dict[*u14];
813   in[15] = *u15==FORTRAN_NULL?NULL:CeedVector_dict[*u15];
814   CeedVector *out;
815   *err = CeedCalloc(16, &out);
816   if (*err) return;
817   out[0] = *v==FORTRAN_NULL?NULL:CeedVector_dict[*v];
818   out[1] = *v1==FORTRAN_NULL?NULL:CeedVector_dict[*v1];
819   out[2] = *v2==FORTRAN_NULL?NULL:CeedVector_dict[*v2];
820   out[3] = *v3==FORTRAN_NULL?NULL:CeedVector_dict[*v3];
821   out[4] = *v4==FORTRAN_NULL?NULL:CeedVector_dict[*v4];
822   out[5] = *v5==FORTRAN_NULL?NULL:CeedVector_dict[*v5];
823   out[6] = *v6==FORTRAN_NULL?NULL:CeedVector_dict[*v6];
824   out[7] = *v7==FORTRAN_NULL?NULL:CeedVector_dict[*v7];
825   out[8] = *v8==FORTRAN_NULL?NULL:CeedVector_dict[*v8];
826   out[9] = *v9==FORTRAN_NULL?NULL:CeedVector_dict[*v9];
827   out[10] = *v10==FORTRAN_NULL?NULL:CeedVector_dict[*v10];
828   out[11] = *v11==FORTRAN_NULL?NULL:CeedVector_dict[*v11];
829   out[12] = *v12==FORTRAN_NULL?NULL:CeedVector_dict[*v12];
830   out[13] = *v13==FORTRAN_NULL?NULL:CeedVector_dict[*v13];
831   out[14] = *v14==FORTRAN_NULL?NULL:CeedVector_dict[*v14];
832   out[15] = *v15==FORTRAN_NULL?NULL:CeedVector_dict[*v15];
833   *err = CeedQFunctionApply(qf_, *Q, in, out);
834   if (*err) return;
835 
836   *err = CeedFree(&in);
837   if (*err) return;
838   *err = CeedFree(&out);
839 }
840 
841 #define fCeedQFunctionDestroy \
842     FORTRAN_NAME(ceedqfunctiondestroy,CEEDQFUNCTIONDESTROY)
843 void fCeedQFunctionDestroy(int *qf, int *err) {
844   if (*qf == FORTRAN_NULL) return;
845   bool fstatus;
846   *err = CeedQFunctionIsFortran(CeedQFunction_dict[*qf], &fstatus);
847   if (*err) return;
848   if (fstatus) {
849     fContext *fctx = CeedQFunction_dict[*qf]->ctx;
850     *err = CeedFree(&fctx);
851     if (*err) return;
852   }
853 
854   *err = CeedQFunctionDestroy(&CeedQFunction_dict[*qf]);
855   if (*err == 0) {
856     *qf = FORTRAN_NULL;
857     CeedQFunction_n--;
858     if (CeedQFunction_n == 0) {
859       *err = CeedFree(&CeedQFunction_dict);
860       CeedQFunction_count = 0;
861       CeedQFunction_count_max = 0;
862     }
863   }
864 }
865 
866 // -----------------------------------------------------------------------------
867 // CeedOperator
868 // -----------------------------------------------------------------------------
869 static CeedOperator *CeedOperator_dict = NULL;
870 static int CeedOperator_count = 0;
871 static int CeedOperator_n = 0;
872 static int CeedOperator_count_max = 0;
873 
874 #define fCeedOperatorCreate \
875     FORTRAN_NAME(ceedoperatorcreate, CEEDOPERATORCREATE)
876 void fCeedOperatorCreate(int *ceed,
877                          int *qf, int *dqf, int *dqfT, int *op, int *err) {
878   if (CeedOperator_count == CeedOperator_count_max)
879     CeedOperator_count_max += CeedOperator_count_max/2 + 1,
880                               CeedOperator_dict = realloc(CeedOperator_dict,
881                                   sizeof(CeedOperator)*CeedOperator_count_max);
882 
883   CeedOperator *op_ = &CeedOperator_dict[CeedOperator_count];
884 
885   CeedQFunction dqf_  = CEED_QFUNCTION_NONE, dqfT_ = CEED_QFUNCTION_NONE;
886   if (*dqf  != FORTRAN_QFUNCTION_NONE) dqf_  = CeedQFunction_dict[*dqf ];
887   if (*dqfT != FORTRAN_QFUNCTION_NONE) dqfT_ = CeedQFunction_dict[*dqfT];
888 
889   *err = CeedOperatorCreate(Ceed_dict[*ceed], CeedQFunction_dict[*qf], dqf_,
890                             dqfT_, op_);
891   if (*err) return;
892   *op = CeedOperator_count++;
893   CeedOperator_n++;
894 }
895 
896 #define fCeedCompositeOperatorCreate \
897     FORTRAN_NAME(ceedcompositeoperatorcreate, CEEDCOMPOSITEOPERATORCREATE)
898 void fCeedCompositeOperatorCreate(int *ceed, int *op, int *err) {
899   if (CeedOperator_count == CeedOperator_count_max)
900     CeedOperator_count_max += CeedOperator_count_max/2 + 1,
901                               CeedOperator_dict = realloc(CeedOperator_dict,
902                                   sizeof(CeedOperator)*CeedOperator_count_max);
903 
904   CeedOperator *op_ = &CeedOperator_dict[CeedOperator_count];
905 
906   *err = CeedCompositeOperatorCreate(Ceed_dict[*ceed], op_);
907   if (*err) return;
908   *op = CeedOperator_count++;
909   CeedOperator_n++;
910 }
911 
912 #define fCeedOperatorSetField \
913     FORTRAN_NAME(ceedoperatorsetfield,CEEDOPERATORSETFIELD)
914 void fCeedOperatorSetField(int *op, const char *fieldname, int *r, int *b,
915                            int *v, int *err, fortran_charlen_t fieldname_len) {
916   FIX_STRING(fieldname);
917   CeedElemRestriction r_;
918   CeedBasis b_;
919   CeedVector v_;
920 
921   CeedOperator op_ = CeedOperator_dict[*op];
922 
923   if (*r == FORTRAN_NULL) {
924     r_ = NULL;
925   } else if (*r == FORTRAN_ELEMRESTRICTION_NONE) {
926     r_ = CEED_ELEMRESTRICTION_NONE;
927   } else {
928     r_ = CeedElemRestriction_dict[*r];
929   }
930 
931   if (*b == FORTRAN_NULL) {
932     b_ = NULL;
933   } else if (*b == FORTRAN_BASIS_COLLOCATED) {
934     b_ = CEED_BASIS_COLLOCATED;
935   } else {
936     b_ = CeedBasis_dict[*b];
937   }
938   if (*v == FORTRAN_NULL) {
939     v_ = NULL;
940   } else if (*v == FORTRAN_VECTOR_ACTIVE) {
941     v_ = CEED_VECTOR_ACTIVE;
942   } else if (*v == FORTRAN_VECTOR_NONE) {
943     v_ = CEED_VECTOR_NONE;
944   } else {
945     v_ = CeedVector_dict[*v];
946   }
947 
948   *err = CeedOperatorSetField(op_, fieldname_c, r_, b_, v_);
949 }
950 
951 #define fCeedCompositeOperatorAddSub \
952     FORTRAN_NAME(ceedcompositeoperatoraddsub, CEEDCOMPOSITEOPERATORADDSUB)
953 void fCeedCompositeOperatorAddSub(int *compositeop, int *subop, int *err) {
954   CeedOperator compositeop_ = CeedOperator_dict[*compositeop];
955   CeedOperator subop_ = CeedOperator_dict[*subop];
956 
957   *err = CeedCompositeOperatorAddSub(compositeop_, subop_);
958   if (*err) return;
959 }
960 
961 #define fCeedOperatorLinearAssembleQFunction \
962     FORTRAN_NAME(ceedoperatorlinearassembleqfunction, CEEDOPERATORLINEARASSEMBLEQFUNCTION)
963 void fCeedOperatorLinearAssembleQFunction(int *op, int *assembledvec,
964     int *assembledrstr, int *rqst, int *err) {
965   // Vector
966   if (CeedVector_count == CeedVector_count_max) {
967     CeedVector_count_max += CeedVector_count_max/2 + 1;
968     CeedRealloc(CeedVector_count_max, &CeedVector_dict);
969   }
970   CeedVector *assembledvec_ = &CeedVector_dict[CeedVector_count];
971 
972   // Restriction
973   if (CeedElemRestriction_count == CeedElemRestriction_count_max) {
974     CeedElemRestriction_count_max += CeedElemRestriction_count_max/2 + 1;
975     CeedRealloc(CeedElemRestriction_count_max, &CeedElemRestriction_dict);
976   }
977   CeedElemRestriction *rstr_ =
978     &CeedElemRestriction_dict[CeedElemRestriction_count];
979 
980   int createRequest = 1;
981   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
982   if (*rqst == -1 || *rqst == -2) {
983     createRequest = 0;
984   }
985 
986   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
987     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
988     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
989   }
990 
991   CeedRequest *rqst_;
992   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
993   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
994   else rqst_ = &CeedRequest_dict[CeedRequest_count];
995 
996   *err = CeedOperatorLinearAssembleQFunction(CeedOperator_dict[*op],
997          assembledvec_, rstr_, rqst_);
998   if (*err) return;
999   if (createRequest) {
1000     *rqst = CeedRequest_count++;
1001     CeedRequest_n++;
1002   }
1003 
1004   if (*err == 0) {
1005     *assembledrstr = CeedElemRestriction_count++;
1006     CeedElemRestriction_n++;
1007     *assembledvec = CeedVector_count++;
1008     CeedVector_n++;
1009   }
1010 }
1011 
1012 #define fCeedOperatorLinearAssembleDiagonal \
1013     FORTRAN_NAME(ceedoperatorlinearassemblediagonal, CEEDOPERATORLINEARASSEMBLEDIAGONAL)
1014 void fCeedOperatorLinearAssembleDiagonal(int *op, int *assembledvec,
1015     int *rqst, int *err) {
1016   int createRequest = 1;
1017   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
1018   if (*rqst == -1 || *rqst == -2) {
1019     createRequest = 0;
1020   }
1021 
1022   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
1023     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
1024     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
1025   }
1026 
1027   CeedRequest *rqst_;
1028   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
1029   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
1030   else rqst_ = &CeedRequest_dict[CeedRequest_count];
1031 
1032   *err = CeedOperatorLinearAssembleDiagonal(CeedOperator_dict[*op],
1033          CeedVector_dict[*assembledvec], rqst_);
1034   if (*err) return;
1035   if (createRequest) {
1036     *rqst = CeedRequest_count++;
1037     CeedRequest_n++;
1038   }
1039 }
1040 
1041 #define fCeedOperatorMultigridLevelCreate \
1042     FORTRAN_NAME(ceedoperatormultigridlevelcreate, CEEDOPERATORMULTIGRIDLEVELCREATE)
1043 void fCeedOperatorMultigridLevelCreate(int *opFine, int *pMultFine,
1044                                        int *rstrCoarse, int *basisCoarse, int *opCoarse,
1045                                        int *opProlong, int *opRestrict, int *err) {
1046   // Operators
1047   CeedOperator opCoarse_, opProlong_, opRestrict_;
1048 
1049   // C interface call
1050   *err = CeedOperatorMultigridLevelCreate(
1051            CeedOperator_dict[*opFine], CeedVector_dict[*pMultFine],
1052            CeedElemRestriction_dict[*rstrCoarse],
1053            CeedBasis_dict[*basisCoarse],
1054            &opCoarse_, &opProlong_, &opRestrict_);
1055 
1056   if (*err) return;
1057   while (CeedOperator_count + 2 >= CeedOperator_count_max) {
1058     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
1059   }
1060   CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
1061   CeedOperator_dict[CeedOperator_count] = opCoarse_;
1062   *opCoarse = CeedOperator_count++;
1063   CeedOperator_dict[CeedOperator_count] = opProlong_;
1064   *opProlong = CeedOperator_count++;
1065   CeedOperator_dict[CeedOperator_count] = opRestrict_;
1066   *opRestrict = CeedOperator_count++;
1067   CeedOperator_n += 3;
1068 }
1069 
1070 #define fCeedOperatorMultigridLevelCreateTensorH1 \
1071     FORTRAN_NAME(ceedoperatormultigridlevelcreatetensorh1, CEEDOPERATORMULTIGRIDLEVELCREATETENSORH1)
1072 void fCeedOperatorMultigridLevelCreateTensorH1(int *opFine, int *pMultFine,
1073     int *rstrCoarse, int *basisCoarse, const CeedScalar *interpCtoF,
1074     int *opCoarse, int *opProlong, int *opRestrict, int *err) {
1075   // Operators
1076   CeedOperator opCoarse_, opProlong_, opRestrict_;
1077 
1078   // C interface call
1079   *err = CeedOperatorMultigridLevelCreateTensorH1(
1080            CeedOperator_dict[*opFine], CeedVector_dict[*pMultFine],
1081            CeedElemRestriction_dict[*rstrCoarse], CeedBasis_dict[*basisCoarse],
1082            interpCtoF, &opCoarse_, &opProlong_, &opRestrict_);
1083 
1084   if (*err) return;
1085   while (CeedOperator_count + 2 >= CeedOperator_count_max) {
1086     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
1087   }
1088   CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
1089   CeedOperator_dict[CeedOperator_count] = opCoarse_;
1090   *opCoarse = CeedOperator_count++;
1091   CeedOperator_dict[CeedOperator_count] = opProlong_;
1092   *opProlong = CeedOperator_count++;
1093   CeedOperator_dict[CeedOperator_count] = opRestrict_;
1094   *opRestrict = CeedOperator_count++;
1095   CeedOperator_n += 3;
1096 }
1097 
1098 #define fCeedOperatorMultigridLevelCreateH1 \
1099     FORTRAN_NAME(ceedoperatormultigridlevelcreateh1, CEEDOPERATORMULTIGRIDLEVELCREATEH1)
1100 void fCeedOperatorMultigridLevelCreateH1(int *opFine, int *pMultFine,
1101     int *rstrCoarse, int *basisCoarse, const CeedScalar *interpCtoF,
1102     int *opCoarse, int *opProlong, int *opRestrict, int *err) {
1103   // Operators
1104   CeedOperator opCoarse_, opProlong_, opRestrict_;
1105 
1106   // C interface call
1107   *err = CeedOperatorMultigridLevelCreateH1(
1108            CeedOperator_dict[*opFine], CeedVector_dict[*pMultFine],
1109            CeedElemRestriction_dict[*rstrCoarse], CeedBasis_dict[*basisCoarse],
1110            interpCtoF, &opCoarse_, &opProlong_, &opRestrict_);
1111 
1112   if (*err) return;
1113   while (CeedOperator_count + 2 >= CeedOperator_count_max) {
1114     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
1115   }
1116   CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
1117   CeedOperator_dict[CeedOperator_count] = opCoarse_;
1118   *opCoarse = CeedOperator_count++;
1119   CeedOperator_dict[CeedOperator_count] = opProlong_;
1120   *opProlong = CeedOperator_count++;
1121   CeedOperator_dict[CeedOperator_count] = opRestrict_;
1122   *opRestrict = CeedOperator_count++;
1123   CeedOperator_n += 3;
1124 }
1125 
1126 #define fCeedOperatorView \
1127     FORTRAN_NAME(ceedoperatorview,CEEDOPERATORVIEW)
1128 void fCeedOperatorView(int *op, int *err) {
1129   CeedOperator op_ = CeedOperator_dict[*op];
1130 
1131   *err = CeedOperatorView(op_, stdout);
1132 }
1133 
1134 #define fCeedOperatorCreateFDMElementInverse \
1135     FORTRAN_NAME(ceedoperatorcreatefdmelementinverse, CEEDOPERATORCREATEFDMELEMENTINVERSE)
1136 void fCeedOperatorCreateFDMElementInverse(int *op, int *fdminv,
1137     int *rqst, int *err) {
1138   // Operator
1139   if (CeedOperator_count == CeedOperator_count_max) {
1140     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
1141     CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
1142   }
1143   CeedOperator *fdminv_ =
1144     &CeedOperator_dict[CeedOperator_count];
1145 
1146   int createRequest = 1;
1147   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
1148   if (*rqst == -1 || *rqst == -2) {
1149     createRequest = 0;
1150   }
1151 
1152   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
1153     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
1154     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
1155   }
1156 
1157   CeedRequest *rqst_;
1158   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
1159   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
1160   else rqst_ = &CeedRequest_dict[CeedRequest_count];
1161 
1162   *err = CeedOperatorCreateFDMElementInverse(CeedOperator_dict[*op],
1163          fdminv_, rqst_);
1164   if (*err) return;
1165   if (createRequest) {
1166     *rqst = CeedRequest_count++;
1167     CeedRequest_n++;
1168   }
1169 
1170   if (*err == 0) {
1171     *fdminv = CeedOperator_count++;
1172     CeedOperator_n++;
1173   }
1174 }
1175 
1176 #define fCeedOperatorApply FORTRAN_NAME(ceedoperatorapply, CEEDOPERATORAPPLY)
1177 void fCeedOperatorApply(int *op, int *ustatevec,
1178                         int *resvec, int *rqst, int *err) {
1179   CeedVector ustatevec_ = (*ustatevec == FORTRAN_NULL) ?
1180                           NULL : (*ustatevec == FORTRAN_VECTOR_NONE ?
1181                                   CEED_VECTOR_NONE : CeedVector_dict[*ustatevec]);
1182   CeedVector resvec_ = (*resvec == FORTRAN_NULL) ?
1183                        NULL : (*resvec == FORTRAN_VECTOR_NONE ?
1184                                CEED_VECTOR_NONE : CeedVector_dict[*resvec]);
1185 
1186   int createRequest = 1;
1187   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
1188   if (*rqst == -1 || *rqst == -2) {
1189     createRequest = 0;
1190   }
1191 
1192   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
1193     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
1194     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
1195   }
1196 
1197   CeedRequest *rqst_;
1198   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
1199   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
1200   else rqst_ = &CeedRequest_dict[CeedRequest_count];
1201 
1202   *err = CeedOperatorApply(CeedOperator_dict[*op],
1203                            ustatevec_, resvec_, rqst_);
1204   if (*err) return;
1205   if (createRequest) {
1206     *rqst = CeedRequest_count++;
1207     CeedRequest_n++;
1208   }
1209 }
1210 
1211 #define fCeedOperatorApplyAdd FORTRAN_NAME(ceedoperatorapplyadd, CEEDOPERATORAPPLYADD)
1212 void fCeedOperatorApplyAdd(int *op, int *ustatevec,
1213                            int *resvec, int *rqst, int *err) {
1214   CeedVector ustatevec_ = *ustatevec == FORTRAN_NULL
1215                           ? NULL : CeedVector_dict[*ustatevec];
1216   CeedVector resvec_ = *resvec == FORTRAN_NULL
1217                        ? NULL : CeedVector_dict[*resvec];
1218 
1219   int createRequest = 1;
1220   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
1221   if (*rqst == -1 || *rqst == -2) {
1222     createRequest = 0;
1223   }
1224 
1225   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
1226     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
1227     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
1228   }
1229 
1230   CeedRequest *rqst_;
1231   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
1232   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
1233   else rqst_ = &CeedRequest_dict[CeedRequest_count];
1234 
1235   *err = CeedOperatorApplyAdd(CeedOperator_dict[*op],
1236                               ustatevec_, resvec_, rqst_);
1237   if (*err) return;
1238   if (createRequest) {
1239     *rqst = CeedRequest_count++;
1240     CeedRequest_n++;
1241   }
1242 }
1243 
1244 #define fCeedOperatorApplyJacobian \
1245     FORTRAN_NAME(ceedoperatorapplyjacobian, CEEDOPERATORAPPLYJACOBIAN)
1246 void fCeedOperatorApplyJacobian(int *op, int *qdatavec, int *ustatevec,
1247                                 int *dustatevec, int *dresvec, int *rqst,
1248                                 int *err) {
1249 // TODO Uncomment this when CeedOperatorApplyJacobian is implemented
1250 //  *err = CeedOperatorApplyJacobian(CeedOperator_dict[*op], CeedVector_dict[*qdatavec],
1251 //             CeedVector_dict[*ustatevec], CeedVector_dict[*dustatevec],
1252 //             CeedVector_dict[*dresvec], &CeedRequest_dict[*rqst]);
1253 }
1254 
1255 #define fCeedOperatorDestroy \
1256     FORTRAN_NAME(ceedoperatordestroy, CEEDOPERATORDESTROY)
1257 void fCeedOperatorDestroy(int *op, int *err) {
1258   if (*op == FORTRAN_NULL) return;
1259   *err = CeedOperatorDestroy(&CeedOperator_dict[*op]);
1260   if (*err == 0) {
1261     *op = FORTRAN_NULL;
1262     CeedOperator_n--;
1263     if (CeedOperator_n == 0) {
1264       *err = CeedFree(&CeedOperator_dict);
1265       CeedOperator_count = 0;
1266       CeedOperator_count_max = 0;
1267     }
1268   }
1269 }
1270 
1271 // -----------------------------------------------------------------------------
1272