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