xref: /libCEED/interface/ceed-fortran.c (revision 777ff853944a0dbc06f7f09486fdf4674828e728)
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 // CeedQFunctionContext
636 // -----------------------------------------------------------------------------
637 static CeedQFunctionContext *CeedQFunctionContext_dict = NULL;
638 static int CeedQFunctionContext_count = 0;
639 static int CeedQFunctionContext_n = 0;
640 static int CeedQFunctionContext_count_max = 0;
641 
642 #define fCeedQFunctionContextCreate \
643     FORTRAN_NAME(ceedqfunctioncontextcreate,CEEDQFUNCTIONCONTEXTCREATE)
644 void fCeedQFunctionContextCreate(int *ceed, int *ctx, int *err) {
645   if (CeedQFunctionContext_count == CeedQFunctionContext_count_max) {
646     CeedQFunctionContext_count_max += CeedQFunctionContext_count_max/2 + 1;
647     CeedRealloc(CeedQFunctionContext_count_max, &CeedQFunctionContext_dict);
648   }
649 
650   CeedQFunctionContext *ctx_ =
651     &CeedQFunctionContext_dict[CeedQFunctionContext_count];
652 
653   *err = CeedQFunctionContextCreate(Ceed_dict[*ceed], ctx_);
654   if (*err) return;
655   *ctx = CeedQFunctionContext_count++;
656   CeedQFunctionContext_n++;
657 }
658 
659 #define fCeedQFunctionContextSetData \
660     FORTRAN_NAME(ceedqfunctioncontextsetdata,CEEDQFUNCTIONCONTEXTSETDATA)
661 void fCeedQFunctionContextSetData(int *ctx, int *memtype, int *copymode,
662                                   CeedInt *n,
663                                   CeedScalar *data, int64_t *offset, int *err) {
664   size_t ctxsize = ((size_t) *n)*sizeof(CeedScalar);
665   *err = CeedQFunctionContextSetData(CeedQFunctionContext_dict[*ctx],
666                                      (CeedMemType)*memtype,
667                                      (CeedCopyMode)*copymode, ctxsize,
668                                      data + *offset);
669 }
670 
671 #define fCeedQFunctionContextGetData \
672     FORTRAN_NAME(ceedqfunctioncontextgetdata,CEEDQFUNCTIONCONTEXTGETDATA)
673 void fCeedQFunctionContextGetData(int *ctx, int *memtype, CeedScalar *data,
674                                   int64_t *offset, int *err) {
675   CeedScalar *b;
676   CeedQFunctionContext ctx_ = CeedQFunctionContext_dict[*ctx];
677   *err = CeedQFunctionContextGetData(ctx_, (CeedMemType)*memtype, &b);
678   *offset = b - data;
679 }
680 
681 #define fCeedQFunctionContextRestoreData \
682     FORTRAN_NAME(ceedqfunctioncontextrestoredata,CEEDQFUNCTIONCONTEXTRESTOREDATA)
683 void fCeedQFunctionContextRestoreData(int *ctx, CeedScalar *data,
684                                       int64_t *offset, int *err) {
685   *err = CeedQFunctionContextRestoreData(CeedQFunctionContext_dict[*ctx],
686                                          (void **)&data);
687   *offset = 0;
688 }
689 
690 #define fCeedQFunctionContextView \
691     FORTRAN_NAME(ceedqfunctioncontextview,CEEDQFUNCTIONCONTEXTVIEW)
692 void fCeedQFunctionContextView(int *ctx, int *err) {
693   *err = CeedQFunctionContextView(CeedQFunctionContext_dict[*ctx], stdout);
694 }
695 
696 #define fCeedQFunctionContextDestroy \
697     FORTRAN_NAME(ceedqfunctioncontextdestroy,CEEDQFUNCTIONCONTEXTDESTROY)
698 void fCeedQFunctionContextDestroy(int *ctx, int *err) {
699   if (*ctx == FORTRAN_NULL) return;
700   *err = CeedQFunctionContextDestroy(&CeedQFunctionContext_dict[*ctx]);
701 
702   if (*err == 0) {
703     *ctx = FORTRAN_NULL;
704     CeedQFunctionContext_n--;
705     if (CeedQFunctionContext_n == 0) {
706       CeedFree(&CeedQFunctionContext_dict);
707       CeedQFunctionContext_count = 0;
708       CeedQFunctionContext_count_max = 0;
709     }
710   }
711 }
712 
713 // -----------------------------------------------------------------------------
714 // CeedQFunction
715 // -----------------------------------------------------------------------------
716 static CeedQFunction *CeedQFunction_dict = NULL;
717 static int CeedQFunction_count = 0;
718 static int CeedQFunction_n = 0;
719 static int CeedQFunction_count_max = 0;
720 
721 static int CeedQFunctionFortranStub(void *ctx, int nq,
722                                     const CeedScalar *const *u,
723                                     CeedScalar *const *v) {
724   CeedFortranContext fctx = ctx;
725   CeedQFunctionContext innerctx = fctx->innerctx;
726   int ierr;
727 
728   CeedScalar *ctx_ = NULL;
729   // Note: Device backends are generating their own kernels from
730   //         single source files, so only Host backends need to
731   //         use this Fortran stub.
732   if (innerctx) {
733     ierr = CeedQFunctionContextGetData(innerctx, CEED_MEM_HOST, &ctx_);
734     CeedChk(ierr);
735   }
736 
737   fctx->f((void *)ctx_,&nq,u[0],u[1],u[2],u[3],u[4],u[5],u[6],
738           u[7],u[8],u[9],u[10],u[11],u[12],u[13],u[14],u[15],
739           v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],
740           v[10],v[11],v[12],v[13],v[14],v[15],&ierr);
741 
742   if (innerctx) {
743     ierr = CeedQFunctionContextRestoreData(innerctx, (void *)&ctx_);
744     CeedChk(ierr);
745   }
746 
747   return ierr;
748 }
749 
750 #define fCeedQFunctionCreateInterior \
751     FORTRAN_NAME(ceedqfunctioncreateinterior, CEEDQFUNCTIONCREATEINTERIOR)
752 void fCeedQFunctionCreateInterior(int *ceed, int *vlength,
753                                   void (*f)(void *ctx, int *nq,
754                                       const CeedScalar *u,const CeedScalar *u1,
755                                       const CeedScalar *u2,const CeedScalar *u3,
756                                       const CeedScalar *u4,const CeedScalar *u5,
757                                       const CeedScalar *u6,const CeedScalar *u7,
758                                       const CeedScalar *u8,const CeedScalar *u9,
759                                       const CeedScalar *u10,const CeedScalar *u11,
760                                       const CeedScalar *u12,const CeedScalar *u13,
761                                       const CeedScalar *u14,const CeedScalar *u15,
762                                       CeedScalar *v,CeedScalar *v1,CeedScalar *v2,
763                                       CeedScalar *v3,CeedScalar *v4,
764                                       CeedScalar *v5,CeedScalar *v6,
765                                       CeedScalar *v7,CeedScalar *v8,
766                                       CeedScalar *v9,CeedScalar *v10,
767                                       CeedScalar *v11,CeedScalar *v12,
768                                       CeedScalar *v13,CeedScalar *v14,
769                                       CeedScalar *v15,int *err),
770                                   const char *source, int *qf, int *err,
771                                   fortran_charlen_t source_len) {
772   FIX_STRING(source);
773   if (CeedQFunction_count == CeedQFunction_count_max) {
774     CeedQFunction_count_max += CeedQFunction_count_max/2 + 1;
775     CeedRealloc(CeedQFunction_count_max, &CeedQFunction_dict);
776   }
777 
778   CeedQFunction *qf_ = &CeedQFunction_dict[CeedQFunction_count];
779   *err = CeedQFunctionCreateInterior(Ceed_dict[*ceed], *vlength,
780                                      CeedQFunctionFortranStub, source_c, qf_);
781 
782   if (*err == 0) {
783     *qf = CeedQFunction_count++;
784     CeedQFunction_n++;
785   }
786 
787   CeedFortranContext fctxdata;
788   *err = CeedCalloc(1, &fctxdata);
789   if (*err) return;
790   fctxdata->f = f; fctxdata->innerctx = NULL;
791   CeedQFunctionContext fctx;
792   *err = CeedQFunctionContextCreate(Ceed_dict[*ceed], &fctx);
793   if (*err) return;
794   *err = CeedQFunctionContextSetData(fctx, CEED_MEM_HOST, CEED_OWN_POINTER,
795                                      sizeof(*fctxdata), fctxdata);
796   if (*err) return;
797   *err = CeedQFunctionSetContext(*qf_, fctx);
798   if (*err) return;
799   CeedQFunctionContextDestroy(&fctx);
800   if (*err) return;
801 
802   *err = CeedQFunctionSetFortranStatus(*qf_, true);
803 }
804 
805 #define fCeedQFunctionCreateInteriorByName \
806     FORTRAN_NAME(ceedqfunctioncreateinteriorbyname, CEEDQFUNCTIONCREATEINTERIORBYNAME)
807 void fCeedQFunctionCreateInteriorByName(int *ceed, const char *name, int *qf,
808                                         int *err, fortran_charlen_t name_len) {
809   FIX_STRING(name);
810   if (CeedQFunction_count == CeedQFunction_count_max) {
811     CeedQFunction_count_max += CeedQFunction_count_max/2 + 1;
812     CeedRealloc(CeedQFunction_count_max, &CeedQFunction_dict);
813   }
814 
815   CeedQFunction *qf_ = &CeedQFunction_dict[CeedQFunction_count];
816   *err = CeedQFunctionCreateInteriorByName(Ceed_dict[*ceed], name_c, qf_);
817 
818   if (*err == 0) {
819     *qf = CeedQFunction_count++;
820     CeedQFunction_n++;
821   }
822 }
823 
824 #define fCeedQFunctionCreateIdentity \
825     FORTRAN_NAME(ceedqfunctioncreateidentity, CEEDQFUNCTIONCREATEIDENTITY)
826 void fCeedQFunctionCreateIdentity(int *ceed, int *size, int *inmode,
827                                   int *outmode, int *qf, int *err) {
828   if (CeedQFunction_count == CeedQFunction_count_max) {
829     CeedQFunction_count_max += CeedQFunction_count_max/2 + 1;
830     CeedRealloc(CeedQFunction_count_max, &CeedQFunction_dict);
831   }
832 
833   CeedQFunction *qf_ = &CeedQFunction_dict[CeedQFunction_count];
834   *err = CeedQFunctionCreateIdentity(Ceed_dict[*ceed], *size,
835                                      (CeedEvalMode)*inmode,
836                                      (CeedEvalMode)*outmode, qf_);
837 
838   if (*err == 0) {
839     *qf = CeedQFunction_count++;
840     CeedQFunction_n++;
841   }
842 }
843 
844 #define fCeedQFunctionAddInput \
845     FORTRAN_NAME(ceedqfunctionaddinput,CEEDQFUNCTIONADDINPUT)
846 void fCeedQFunctionAddInput(int *qf, const char *fieldname,
847                             CeedInt *ncomp, CeedEvalMode *emode, int *err,
848                             fortran_charlen_t fieldname_len) {
849   FIX_STRING(fieldname);
850   CeedQFunction qf_ = CeedQFunction_dict[*qf];
851 
852   *err = CeedQFunctionAddInput(qf_, fieldname_c, *ncomp, *emode);
853 }
854 
855 #define fCeedQFunctionAddOutput \
856     FORTRAN_NAME(ceedqfunctionaddoutput,CEEDQFUNCTIONADDOUTPUT)
857 void fCeedQFunctionAddOutput(int *qf, const char *fieldname,
858                              CeedInt *ncomp, CeedEvalMode *emode, int *err,
859                              fortran_charlen_t fieldname_len) {
860   FIX_STRING(fieldname);
861   CeedQFunction qf_ = CeedQFunction_dict[*qf];
862 
863   *err = CeedQFunctionAddOutput(qf_, fieldname_c, *ncomp, *emode);
864 }
865 
866 #define fCeedQFunctionSetContext \
867     FORTRAN_NAME(ceedqfunctionsetcontext,CEEDQFUNCTIONSETCONTEXT)
868 void fCeedQFunctionSetContext(int *qf, int *ctx, int *err) {
869   CeedQFunction qf_ = CeedQFunction_dict[*qf];
870   CeedQFunctionContext ctx_ = CeedQFunctionContext_dict[*ctx];
871 
872   CeedQFunctionContext fctx;
873   *err = CeedQFunctionGetContext(qf_, &fctx);
874   if (*err) return;
875   CeedFortranContext fctxdata;
876   *err = CeedQFunctionContextGetData(fctx, CEED_MEM_HOST, &fctxdata);
877   if (*err) return;
878   fctxdata->innerctx = ctx_;
879   *err = CeedQFunctionContextRestoreData(fctx, (void **)&fctxdata);
880 }
881 
882 #define fCeedQFunctionView \
883     FORTRAN_NAME(ceedqfunctionview,CEEDQFUNCTIONVIEW)
884 void fCeedQFunctionView(int *qf, int *err) {
885   CeedQFunction qf_ = CeedQFunction_dict[*qf];
886 
887   *err = CeedQFunctionView(qf_, stdout);
888 }
889 
890 #define fCeedQFunctionApply \
891     FORTRAN_NAME(ceedqfunctionapply,CEEDQFUNCTIONAPPLY)
892 //TODO Need Fixing, double pointer
893 void fCeedQFunctionApply(int *qf, int *Q,
894                          int *u, int *u1, int *u2, int *u3,
895                          int *u4, int *u5, int *u6, int *u7,
896                          int *u8, int *u9, int *u10, int *u11,
897                          int *u12, int *u13, int *u14, int *u15,
898                          int *v, int *v1, int *v2, int *v3,
899                          int *v4, int *v5, int *v6, int *v7,
900                          int *v8, int *v9, int *v10, int *v11,
901                          int *v12, int *v13, int *v14, int *v15, int *err) {
902   CeedQFunction qf_ = CeedQFunction_dict[*qf];
903   CeedVector *in;
904   *err = CeedCalloc(16, &in);
905   if (*err) return;
906   in[0] = *u==FORTRAN_NULL?NULL:CeedVector_dict[*u];
907   in[1] = *u1==FORTRAN_NULL?NULL:CeedVector_dict[*u1];
908   in[2] = *u2==FORTRAN_NULL?NULL:CeedVector_dict[*u2];
909   in[3] = *u3==FORTRAN_NULL?NULL:CeedVector_dict[*u3];
910   in[4] = *u4==FORTRAN_NULL?NULL:CeedVector_dict[*u4];
911   in[5] = *u5==FORTRAN_NULL?NULL:CeedVector_dict[*u5];
912   in[6] = *u6==FORTRAN_NULL?NULL:CeedVector_dict[*u6];
913   in[7] = *u7==FORTRAN_NULL?NULL:CeedVector_dict[*u7];
914   in[8] = *u8==FORTRAN_NULL?NULL:CeedVector_dict[*u8];
915   in[9] = *u9==FORTRAN_NULL?NULL:CeedVector_dict[*u9];
916   in[10] = *u10==FORTRAN_NULL?NULL:CeedVector_dict[*u10];
917   in[11] = *u11==FORTRAN_NULL?NULL:CeedVector_dict[*u11];
918   in[12] = *u12==FORTRAN_NULL?NULL:CeedVector_dict[*u12];
919   in[13] = *u13==FORTRAN_NULL?NULL:CeedVector_dict[*u13];
920   in[14] = *u14==FORTRAN_NULL?NULL:CeedVector_dict[*u14];
921   in[15] = *u15==FORTRAN_NULL?NULL:CeedVector_dict[*u15];
922   CeedVector *out;
923   *err = CeedCalloc(16, &out);
924   if (*err) return;
925   out[0] = *v==FORTRAN_NULL?NULL:CeedVector_dict[*v];
926   out[1] = *v1==FORTRAN_NULL?NULL:CeedVector_dict[*v1];
927   out[2] = *v2==FORTRAN_NULL?NULL:CeedVector_dict[*v2];
928   out[3] = *v3==FORTRAN_NULL?NULL:CeedVector_dict[*v3];
929   out[4] = *v4==FORTRAN_NULL?NULL:CeedVector_dict[*v4];
930   out[5] = *v5==FORTRAN_NULL?NULL:CeedVector_dict[*v5];
931   out[6] = *v6==FORTRAN_NULL?NULL:CeedVector_dict[*v6];
932   out[7] = *v7==FORTRAN_NULL?NULL:CeedVector_dict[*v7];
933   out[8] = *v8==FORTRAN_NULL?NULL:CeedVector_dict[*v8];
934   out[9] = *v9==FORTRAN_NULL?NULL:CeedVector_dict[*v9];
935   out[10] = *v10==FORTRAN_NULL?NULL:CeedVector_dict[*v10];
936   out[11] = *v11==FORTRAN_NULL?NULL:CeedVector_dict[*v11];
937   out[12] = *v12==FORTRAN_NULL?NULL:CeedVector_dict[*v12];
938   out[13] = *v13==FORTRAN_NULL?NULL:CeedVector_dict[*v13];
939   out[14] = *v14==FORTRAN_NULL?NULL:CeedVector_dict[*v14];
940   out[15] = *v15==FORTRAN_NULL?NULL:CeedVector_dict[*v15];
941   *err = CeedQFunctionApply(qf_, *Q, in, out);
942   if (*err) return;
943 
944   *err = CeedFree(&in);
945   if (*err) return;
946   *err = CeedFree(&out);
947 }
948 
949 #define fCeedQFunctionDestroy \
950     FORTRAN_NAME(ceedqfunctiondestroy,CEEDQFUNCTIONDESTROY)
951 void fCeedQFunctionDestroy(int *qf, int *err) {
952   if (*qf == FORTRAN_NULL) return;
953 
954   *err = CeedQFunctionDestroy(&CeedQFunction_dict[*qf]);
955   if (*err == 0) {
956     *qf = FORTRAN_NULL;
957     CeedQFunction_n--;
958     if (CeedQFunction_n == 0) {
959       *err = CeedFree(&CeedQFunction_dict);
960       CeedQFunction_count = 0;
961       CeedQFunction_count_max = 0;
962     }
963   }
964 }
965 
966 // -----------------------------------------------------------------------------
967 // CeedOperator
968 // -----------------------------------------------------------------------------
969 static CeedOperator *CeedOperator_dict = NULL;
970 static int CeedOperator_count = 0;
971 static int CeedOperator_n = 0;
972 static int CeedOperator_count_max = 0;
973 
974 #define fCeedOperatorCreate \
975     FORTRAN_NAME(ceedoperatorcreate, CEEDOPERATORCREATE)
976 void fCeedOperatorCreate(int *ceed,
977                          int *qf, int *dqf, int *dqfT, int *op, int *err) {
978   if (CeedOperator_count == CeedOperator_count_max) {
979     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
980     CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
981   }
982 
983   CeedOperator *op_ = &CeedOperator_dict[CeedOperator_count];
984 
985   CeedQFunction dqf_  = CEED_QFUNCTION_NONE, dqfT_ = CEED_QFUNCTION_NONE;
986   if (*dqf  != FORTRAN_QFUNCTION_NONE) dqf_  = CeedQFunction_dict[*dqf ];
987   if (*dqfT != FORTRAN_QFUNCTION_NONE) dqfT_ = CeedQFunction_dict[*dqfT];
988 
989   *err = CeedOperatorCreate(Ceed_dict[*ceed], CeedQFunction_dict[*qf], dqf_,
990                             dqfT_, op_);
991   if (*err) return;
992   *op = CeedOperator_count++;
993   CeedOperator_n++;
994 }
995 
996 #define fCeedCompositeOperatorCreate \
997     FORTRAN_NAME(ceedcompositeoperatorcreate, CEEDCOMPOSITEOPERATORCREATE)
998 void fCeedCompositeOperatorCreate(int *ceed, int *op, int *err) {
999   if (CeedOperator_count == CeedOperator_count_max) {
1000     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
1001     CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
1002   }
1003 
1004   CeedOperator *op_ = &CeedOperator_dict[CeedOperator_count];
1005 
1006   *err = CeedCompositeOperatorCreate(Ceed_dict[*ceed], op_);
1007   if (*err) return;
1008   *op = CeedOperator_count++;
1009   CeedOperator_n++;
1010 }
1011 
1012 #define fCeedOperatorSetField \
1013     FORTRAN_NAME(ceedoperatorsetfield,CEEDOPERATORSETFIELD)
1014 void fCeedOperatorSetField(int *op, const char *fieldname, int *r, int *b,
1015                            int *v, int *err, fortran_charlen_t fieldname_len) {
1016   FIX_STRING(fieldname);
1017   CeedElemRestriction r_;
1018   CeedBasis b_;
1019   CeedVector v_;
1020 
1021   CeedOperator op_ = CeedOperator_dict[*op];
1022 
1023   if (*r == FORTRAN_NULL) {
1024     r_ = NULL;
1025   } else if (*r == FORTRAN_ELEMRESTRICTION_NONE) {
1026     r_ = CEED_ELEMRESTRICTION_NONE;
1027   } else {
1028     r_ = CeedElemRestriction_dict[*r];
1029   }
1030 
1031   if (*b == FORTRAN_NULL) {
1032     b_ = NULL;
1033   } else if (*b == FORTRAN_BASIS_COLLOCATED) {
1034     b_ = CEED_BASIS_COLLOCATED;
1035   } else {
1036     b_ = CeedBasis_dict[*b];
1037   }
1038   if (*v == FORTRAN_NULL) {
1039     v_ = NULL;
1040   } else if (*v == FORTRAN_VECTOR_ACTIVE) {
1041     v_ = CEED_VECTOR_ACTIVE;
1042   } else if (*v == FORTRAN_VECTOR_NONE) {
1043     v_ = CEED_VECTOR_NONE;
1044   } else {
1045     v_ = CeedVector_dict[*v];
1046   }
1047 
1048   *err = CeedOperatorSetField(op_, fieldname_c, r_, b_, v_);
1049 }
1050 
1051 #define fCeedCompositeOperatorAddSub \
1052     FORTRAN_NAME(ceedcompositeoperatoraddsub, CEEDCOMPOSITEOPERATORADDSUB)
1053 void fCeedCompositeOperatorAddSub(int *compositeop, int *subop, int *err) {
1054   CeedOperator compositeop_ = CeedOperator_dict[*compositeop];
1055   CeedOperator subop_ = CeedOperator_dict[*subop];
1056 
1057   *err = CeedCompositeOperatorAddSub(compositeop_, subop_);
1058   if (*err) return;
1059 }
1060 
1061 #define fCeedOperatorLinearAssembleQFunction \
1062     FORTRAN_NAME(ceedoperatorlinearassembleqfunction, CEEDOPERATORLINEARASSEMBLEQFUNCTION)
1063 void fCeedOperatorLinearAssembleQFunction(int *op, int *assembledvec,
1064     int *assembledrstr, int *rqst, int *err) {
1065   // Vector
1066   if (CeedVector_count == CeedVector_count_max) {
1067     CeedVector_count_max += CeedVector_count_max/2 + 1;
1068     CeedRealloc(CeedVector_count_max, &CeedVector_dict);
1069   }
1070   CeedVector *assembledvec_ = &CeedVector_dict[CeedVector_count];
1071 
1072   // Restriction
1073   if (CeedElemRestriction_count == CeedElemRestriction_count_max) {
1074     CeedElemRestriction_count_max += CeedElemRestriction_count_max/2 + 1;
1075     CeedRealloc(CeedElemRestriction_count_max, &CeedElemRestriction_dict);
1076   }
1077   CeedElemRestriction *rstr_ =
1078     &CeedElemRestriction_dict[CeedElemRestriction_count];
1079 
1080   int createRequest = 1;
1081   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
1082   if (*rqst == -1 || *rqst == -2) {
1083     createRequest = 0;
1084   }
1085 
1086   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
1087     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
1088     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
1089   }
1090 
1091   CeedRequest *rqst_;
1092   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
1093   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
1094   else rqst_ = &CeedRequest_dict[CeedRequest_count];
1095 
1096   *err = CeedOperatorLinearAssembleQFunction(CeedOperator_dict[*op],
1097          assembledvec_, rstr_, rqst_);
1098   if (*err) return;
1099   if (createRequest) {
1100     *rqst = CeedRequest_count++;
1101     CeedRequest_n++;
1102   }
1103 
1104   if (*err == 0) {
1105     *assembledrstr = CeedElemRestriction_count++;
1106     CeedElemRestriction_n++;
1107     *assembledvec = CeedVector_count++;
1108     CeedVector_n++;
1109   }
1110 }
1111 
1112 #define fCeedOperatorLinearAssembleDiagonal \
1113     FORTRAN_NAME(ceedoperatorlinearassemblediagonal, CEEDOPERATORLINEARASSEMBLEDIAGONAL)
1114 void fCeedOperatorLinearAssembleDiagonal(int *op, int *assembledvec,
1115     int *rqst, int *err) {
1116   int createRequest = 1;
1117   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
1118   if (*rqst == -1 || *rqst == -2) {
1119     createRequest = 0;
1120   }
1121 
1122   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
1123     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
1124     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
1125   }
1126 
1127   CeedRequest *rqst_;
1128   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
1129   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
1130   else rqst_ = &CeedRequest_dict[CeedRequest_count];
1131 
1132   *err = CeedOperatorLinearAssembleDiagonal(CeedOperator_dict[*op],
1133          CeedVector_dict[*assembledvec], rqst_);
1134   if (*err) return;
1135   if (createRequest) {
1136     *rqst = CeedRequest_count++;
1137     CeedRequest_n++;
1138   }
1139 }
1140 
1141 #define fCeedOperatorMultigridLevelCreate \
1142     FORTRAN_NAME(ceedoperatormultigridlevelcreate, CEEDOPERATORMULTIGRIDLEVELCREATE)
1143 void fCeedOperatorMultigridLevelCreate(int *opFine, int *pMultFine,
1144                                        int *rstrCoarse, int *basisCoarse, int *opCoarse,
1145                                        int *opProlong, int *opRestrict, int *err) {
1146   // Operators
1147   CeedOperator opCoarse_, opProlong_, opRestrict_;
1148 
1149   // C interface call
1150   *err = CeedOperatorMultigridLevelCreate(
1151            CeedOperator_dict[*opFine], CeedVector_dict[*pMultFine],
1152            CeedElemRestriction_dict[*rstrCoarse],
1153            CeedBasis_dict[*basisCoarse],
1154            &opCoarse_, &opProlong_, &opRestrict_);
1155 
1156   if (*err) return;
1157   while (CeedOperator_count + 2 >= CeedOperator_count_max) {
1158     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
1159   }
1160   CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
1161   CeedOperator_dict[CeedOperator_count] = opCoarse_;
1162   *opCoarse = CeedOperator_count++;
1163   CeedOperator_dict[CeedOperator_count] = opProlong_;
1164   *opProlong = CeedOperator_count++;
1165   CeedOperator_dict[CeedOperator_count] = opRestrict_;
1166   *opRestrict = CeedOperator_count++;
1167   CeedOperator_n += 3;
1168 }
1169 
1170 #define fCeedOperatorMultigridLevelCreateTensorH1 \
1171     FORTRAN_NAME(ceedoperatormultigridlevelcreatetensorh1, CEEDOPERATORMULTIGRIDLEVELCREATETENSORH1)
1172 void fCeedOperatorMultigridLevelCreateTensorH1(int *opFine, int *pMultFine,
1173     int *rstrCoarse, int *basisCoarse, const CeedScalar *interpCtoF,
1174     int *opCoarse, int *opProlong, int *opRestrict, int *err) {
1175   // Operators
1176   CeedOperator opCoarse_, opProlong_, opRestrict_;
1177 
1178   // C interface call
1179   *err = CeedOperatorMultigridLevelCreateTensorH1(
1180            CeedOperator_dict[*opFine], CeedVector_dict[*pMultFine],
1181            CeedElemRestriction_dict[*rstrCoarse], CeedBasis_dict[*basisCoarse],
1182            interpCtoF, &opCoarse_, &opProlong_, &opRestrict_);
1183 
1184   if (*err) return;
1185   while (CeedOperator_count + 2 >= CeedOperator_count_max) {
1186     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
1187   }
1188   CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
1189   CeedOperator_dict[CeedOperator_count] = opCoarse_;
1190   *opCoarse = CeedOperator_count++;
1191   CeedOperator_dict[CeedOperator_count] = opProlong_;
1192   *opProlong = CeedOperator_count++;
1193   CeedOperator_dict[CeedOperator_count] = opRestrict_;
1194   *opRestrict = CeedOperator_count++;
1195   CeedOperator_n += 3;
1196 }
1197 
1198 #define fCeedOperatorMultigridLevelCreateH1 \
1199     FORTRAN_NAME(ceedoperatormultigridlevelcreateh1, CEEDOPERATORMULTIGRIDLEVELCREATEH1)
1200 void fCeedOperatorMultigridLevelCreateH1(int *opFine, int *pMultFine,
1201     int *rstrCoarse, int *basisCoarse, const CeedScalar *interpCtoF,
1202     int *opCoarse, int *opProlong, int *opRestrict, int *err) {
1203   // Operators
1204   CeedOperator opCoarse_, opProlong_, opRestrict_;
1205 
1206   // C interface call
1207   *err = CeedOperatorMultigridLevelCreateH1(
1208            CeedOperator_dict[*opFine], CeedVector_dict[*pMultFine],
1209            CeedElemRestriction_dict[*rstrCoarse], CeedBasis_dict[*basisCoarse],
1210            interpCtoF, &opCoarse_, &opProlong_, &opRestrict_);
1211 
1212   if (*err) return;
1213   while (CeedOperator_count + 2 >= CeedOperator_count_max) {
1214     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
1215   }
1216   CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
1217   CeedOperator_dict[CeedOperator_count] = opCoarse_;
1218   *opCoarse = CeedOperator_count++;
1219   CeedOperator_dict[CeedOperator_count] = opProlong_;
1220   *opProlong = CeedOperator_count++;
1221   CeedOperator_dict[CeedOperator_count] = opRestrict_;
1222   *opRestrict = CeedOperator_count++;
1223   CeedOperator_n += 3;
1224 }
1225 
1226 #define fCeedOperatorView \
1227     FORTRAN_NAME(ceedoperatorview,CEEDOPERATORVIEW)
1228 void fCeedOperatorView(int *op, int *err) {
1229   CeedOperator op_ = CeedOperator_dict[*op];
1230 
1231   *err = CeedOperatorView(op_, stdout);
1232 }
1233 
1234 #define fCeedOperatorCreateFDMElementInverse \
1235     FORTRAN_NAME(ceedoperatorcreatefdmelementinverse, CEEDOPERATORCREATEFDMELEMENTINVERSE)
1236 void fCeedOperatorCreateFDMElementInverse(int *op, int *fdminv,
1237     int *rqst, int *err) {
1238   // Operator
1239   if (CeedOperator_count == CeedOperator_count_max) {
1240     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
1241     CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
1242   }
1243   CeedOperator *fdminv_ =
1244     &CeedOperator_dict[CeedOperator_count];
1245 
1246   int createRequest = 1;
1247   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
1248   if (*rqst == -1 || *rqst == -2) {
1249     createRequest = 0;
1250   }
1251 
1252   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
1253     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
1254     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
1255   }
1256 
1257   CeedRequest *rqst_;
1258   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
1259   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
1260   else rqst_ = &CeedRequest_dict[CeedRequest_count];
1261 
1262   *err = CeedOperatorCreateFDMElementInverse(CeedOperator_dict[*op],
1263          fdminv_, rqst_);
1264   if (*err) return;
1265   if (createRequest) {
1266     *rqst = CeedRequest_count++;
1267     CeedRequest_n++;
1268   }
1269 
1270   if (*err == 0) {
1271     *fdminv = CeedOperator_count++;
1272     CeedOperator_n++;
1273   }
1274 }
1275 
1276 #define fCeedOperatorApply FORTRAN_NAME(ceedoperatorapply, CEEDOPERATORAPPLY)
1277 void fCeedOperatorApply(int *op, int *ustatevec,
1278                         int *resvec, int *rqst, int *err) {
1279   CeedVector ustatevec_ = (*ustatevec == FORTRAN_NULL) ?
1280                           NULL : (*ustatevec == FORTRAN_VECTOR_NONE ?
1281                                   CEED_VECTOR_NONE : CeedVector_dict[*ustatevec]);
1282   CeedVector resvec_ = (*resvec == FORTRAN_NULL) ?
1283                        NULL : (*resvec == FORTRAN_VECTOR_NONE ?
1284                                CEED_VECTOR_NONE : CeedVector_dict[*resvec]);
1285 
1286   int createRequest = 1;
1287   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
1288   if (*rqst == -1 || *rqst == -2) {
1289     createRequest = 0;
1290   }
1291 
1292   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
1293     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
1294     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
1295   }
1296 
1297   CeedRequest *rqst_;
1298   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
1299   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
1300   else rqst_ = &CeedRequest_dict[CeedRequest_count];
1301 
1302   *err = CeedOperatorApply(CeedOperator_dict[*op],
1303                            ustatevec_, resvec_, rqst_);
1304   if (*err) return;
1305   if (createRequest) {
1306     *rqst = CeedRequest_count++;
1307     CeedRequest_n++;
1308   }
1309 }
1310 
1311 #define fCeedOperatorApplyAdd FORTRAN_NAME(ceedoperatorapplyadd, CEEDOPERATORAPPLYADD)
1312 void fCeedOperatorApplyAdd(int *op, int *ustatevec,
1313                            int *resvec, int *rqst, int *err) {
1314   CeedVector ustatevec_ = *ustatevec == FORTRAN_NULL
1315                           ? NULL : CeedVector_dict[*ustatevec];
1316   CeedVector resvec_ = *resvec == FORTRAN_NULL
1317                        ? NULL : CeedVector_dict[*resvec];
1318 
1319   int createRequest = 1;
1320   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
1321   if (*rqst == -1 || *rqst == -2) {
1322     createRequest = 0;
1323   }
1324 
1325   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
1326     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
1327     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
1328   }
1329 
1330   CeedRequest *rqst_;
1331   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
1332   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
1333   else rqst_ = &CeedRequest_dict[CeedRequest_count];
1334 
1335   *err = CeedOperatorApplyAdd(CeedOperator_dict[*op],
1336                               ustatevec_, resvec_, rqst_);
1337   if (*err) return;
1338   if (createRequest) {
1339     *rqst = CeedRequest_count++;
1340     CeedRequest_n++;
1341   }
1342 }
1343 
1344 #define fCeedOperatorApplyJacobian \
1345     FORTRAN_NAME(ceedoperatorapplyjacobian, CEEDOPERATORAPPLYJACOBIAN)
1346 void fCeedOperatorApplyJacobian(int *op, int *qdatavec, int *ustatevec,
1347                                 int *dustatevec, int *dresvec, int *rqst,
1348                                 int *err) {
1349 // TODO Uncomment this when CeedOperatorApplyJacobian is implemented
1350 //  *err = CeedOperatorApplyJacobian(CeedOperator_dict[*op], CeedVector_dict[*qdatavec],
1351 //             CeedVector_dict[*ustatevec], CeedVector_dict[*dustatevec],
1352 //             CeedVector_dict[*dresvec], &CeedRequest_dict[*rqst]);
1353 }
1354 
1355 #define fCeedOperatorDestroy \
1356     FORTRAN_NAME(ceedoperatordestroy, CEEDOPERATORDESTROY)
1357 void fCeedOperatorDestroy(int *op, int *err) {
1358   if (*op == FORTRAN_NULL) return;
1359   *err = CeedOperatorDestroy(&CeedOperator_dict[*op]);
1360   if (*err == 0) {
1361     *op = FORTRAN_NULL;
1362     CeedOperator_n--;
1363     if (CeedOperator_n == 0) {
1364       *err = CeedFree(&CeedOperator_dict);
1365       CeedOperator_count = 0;
1366       CeedOperator_count_max = 0;
1367     }
1368   }
1369 }
1370 
1371 // -----------------------------------------------------------------------------
1372