xref: /libCEED/interface/ceed-fortran.c (revision c8ed46e2e56df6c2b12db8c2ad7df9d3c2891a08)
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   CeedScalar *offsetArray = array + *offset;
197   *err = CeedVectorRestoreArray(CeedVector_dict[*vec], &offsetArray);
198   *offset = 0;
199 }
200 
201 #define fCeedVectorRestoreArrayRead \
202     FORTRAN_NAME(ceedvectorrestorearrayread,CEEDVECTORRESTOREARRAYREAD)
203 void fCeedVectorRestoreArrayRead(int *vec, const CeedScalar *array,
204                                  int64_t *offset, int *err) {
205   *err = CeedVectorRestoreArrayRead(CeedVector_dict[*vec], &array);
206   *offset = 0;
207 }
208 
209 #define fCeedVectorNorm \
210     FORTRAN_NAME(ceedvectornorm,CEEDVECTORNORM)
211 void fCeedVectorNorm(int *vec, int *type, CeedScalar *norm, int *err) {
212   *err = CeedVectorNorm(CeedVector_dict[*vec], (CeedNormType)*type, norm);
213 }
214 
215 #define fCeedVectorReciprocal \
216     FORTRAN_NAME(ceedvectorreciprocal,CEEDVECTORRECIPROCAL)
217 void fCeedVectorReciprocal(int *vec, int *err) {
218   *err = CeedVectorReciprocal(CeedVector_dict[*vec]);
219 }
220 
221 #define fCeedVectorView FORTRAN_NAME(ceedvectorview,CEEDVECTORVIEW)
222 void fCeedVectorView(int *vec, int *err) {
223   *err = CeedVectorView(CeedVector_dict[*vec], "%12.8f", stdout);
224 }
225 
226 #define fCeedVectorDestroy FORTRAN_NAME(ceedvectordestroy,CEEDVECTORDESTROY)
227 void fCeedVectorDestroy(int *vec, int *err) {
228   if (*vec == FORTRAN_NULL) return;
229   *err = CeedVectorDestroy(&CeedVector_dict[*vec]);
230 
231   if (*err == 0) {
232     *vec = FORTRAN_NULL;
233     CeedVector_n--;
234     if (CeedVector_n == 0) {
235       CeedFree(&CeedVector_dict);
236       CeedVector_count = 0;
237       CeedVector_count_max = 0;
238     }
239   }
240 }
241 
242 // -----------------------------------------------------------------------------
243 // CeedElemRestriction
244 // -----------------------------------------------------------------------------
245 static CeedElemRestriction *CeedElemRestriction_dict = NULL;
246 static int CeedElemRestriction_count = 0;
247 static int CeedElemRestriction_n = 0;
248 static int CeedElemRestriction_count_max = 0;
249 
250 #define fCeedElemRestrictionCreate \
251     FORTRAN_NAME(ceedelemrestrictioncreate, CEEDELEMRESTRICTIONCREATE)
252 void fCeedElemRestrictionCreate(int *ceed, int *nelements, int *esize,
253                                 int *ncomp, int *compstride, int *lsize,
254                                 int *memtype, int *copymode, const int *offsets,
255                                 int *elemrestriction, int *err) {
256   if (CeedElemRestriction_count == CeedElemRestriction_count_max) {
257     CeedElemRestriction_count_max += CeedElemRestriction_count_max/2 + 1;
258     CeedRealloc(CeedElemRestriction_count_max, &CeedElemRestriction_dict);
259   }
260 
261   const int *offsets_ = offsets;
262 
263   CeedElemRestriction *elemrestriction_ =
264     &CeedElemRestriction_dict[CeedElemRestriction_count];
265   *err = CeedElemRestrictionCreate(Ceed_dict[*ceed], *nelements, *esize,
266                                    *ncomp, *compstride, *lsize,
267                                    (CeedMemType)*memtype,
268                                    (CeedCopyMode)*copymode, offsets_,
269                                    elemrestriction_);
270 
271   if (*err == 0) {
272     *elemrestriction = CeedElemRestriction_count++;
273     CeedElemRestriction_n++;
274   }
275 }
276 
277 #define fCeedElemRestrictionCreateStrided \
278     FORTRAN_NAME(ceedelemrestrictioncreatestrided, CEEDELEMRESTRICTIONCREATESTRIDED)
279 void fCeedElemRestrictionCreateStrided(int *ceed, int *nelements, int *esize,
280                                        int *ncomp, int *lsize, int *strides,
281                                        int *elemrestriction, int *err) {
282   if (CeedElemRestriction_count == CeedElemRestriction_count_max) {
283     CeedElemRestriction_count_max += CeedElemRestriction_count_max/2 + 1;
284     CeedRealloc(CeedElemRestriction_count_max, &CeedElemRestriction_dict);
285   }
286 
287   CeedElemRestriction *elemrestriction_ =
288     &CeedElemRestriction_dict[CeedElemRestriction_count];
289   *err = CeedElemRestrictionCreateStrided(Ceed_dict[*ceed], *nelements, *esize,
290                                           *ncomp, *lsize,
291                                           *strides == FORTRAN_STRIDES_BACKEND ?
292                                           CEED_STRIDES_BACKEND : strides,
293                                           elemrestriction_);
294   if (*err == 0) {
295     *elemrestriction = CeedElemRestriction_count++;
296     CeedElemRestriction_n++;
297   }
298 }
299 
300 #define fCeedElemRestrictionCreateBlocked \
301     FORTRAN_NAME(ceedelemrestrictioncreateblocked,CEEDELEMRESTRICTIONCREATEBLOCKED)
302 void fCeedElemRestrictionCreateBlocked(int *ceed, int *nelements, int *esize,
303                                        int *blocksize, int *ncomp,
304                                        int *compstride, int *lsize,
305                                        int *mtype, int *cmode,
306                                        int *blkindices, int *elemrestriction,
307                                        int *err) {
308 
309   if (CeedElemRestriction_count == CeedElemRestriction_count_max) {
310     CeedElemRestriction_count_max += CeedElemRestriction_count_max/2 + 1;
311     CeedRealloc(CeedElemRestriction_count_max, &CeedElemRestriction_dict);
312   }
313 
314   CeedElemRestriction *elemrestriction_ =
315     &CeedElemRestriction_dict[CeedElemRestriction_count];
316   *err = CeedElemRestrictionCreateBlocked(Ceed_dict[*ceed],
317                                           *nelements, *esize, *blocksize,
318                                           *ncomp, *compstride, *lsize,
319                                           (CeedMemType)*mtype,
320                                           (CeedCopyMode)*cmode, blkindices,
321                                           elemrestriction_);
322 
323   if (*err == 0) {
324     *elemrestriction = CeedElemRestriction_count++;
325     CeedElemRestriction_n++;
326   }
327 }
328 
329 #define fCeedElemRestrictionCreateBlockedStrided \
330     FORTRAN_NAME(ceedelemrestrictioncreateblockedstrided, CEEDELEMRESTRICTIONCREATEBLOCKEDSTRIDED)
331 void fCeedElemRestrictionCreateBlockedStrided(int *ceed, int *nelements,
332     int *esize, int *blksize, int *ncomp, int *lsize, int *strides,
333     int *elemrestriction, int *err) {
334   if (CeedElemRestriction_count == CeedElemRestriction_count_max) {
335     CeedElemRestriction_count_max += CeedElemRestriction_count_max/2 + 1;
336     CeedRealloc(CeedElemRestriction_count_max, &CeedElemRestriction_dict);
337   }
338 
339   CeedElemRestriction *elemrestriction_ =
340     &CeedElemRestriction_dict[CeedElemRestriction_count];
341   *err = CeedElemRestrictionCreateBlockedStrided(Ceed_dict[*ceed], *nelements,
342          *esize, *blksize, *ncomp, *lsize, strides, elemrestriction_);
343   if (*err == 0) {
344     *elemrestriction = CeedElemRestriction_count++;
345     CeedElemRestriction_n++;
346   }
347 }
348 
349 static CeedRequest *CeedRequest_dict = NULL;
350 static int CeedRequest_count = 0;
351 static int CeedRequest_n = 0;
352 static int CeedRequest_count_max = 0;
353 
354 #define fCeedElemRestrictionApply \
355     FORTRAN_NAME(ceedelemrestrictionapply,CEEDELEMRESTRICTIONAPPLY)
356 void fCeedElemRestrictionApply(int *elemr, int *tmode, int *uvec, int *ruvec,
357                                int *rqst, int *err) {
358   int createRequest = 1;
359   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
360   if (*rqst == FORTRAN_REQUEST_IMMEDIATE || *rqst == FORTRAN_REQUEST_ORDERED)
361     createRequest = 0;
362 
363   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
364     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
365     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
366   }
367 
368   CeedRequest *rqst_;
369   if      (*rqst == FORTRAN_REQUEST_IMMEDIATE) rqst_ = CEED_REQUEST_IMMEDIATE;
370   else if (*rqst == FORTRAN_REQUEST_ORDERED  ) rqst_ = CEED_REQUEST_ORDERED;
371   else rqst_ = &CeedRequest_dict[CeedRequest_count];
372 
373   *err = CeedElemRestrictionApply(CeedElemRestriction_dict[*elemr],
374                                   (CeedTransposeMode)*tmode,
375                                   CeedVector_dict[*uvec],
376                                   CeedVector_dict[*ruvec], rqst_);
377 
378   if (*err == 0 && createRequest) {
379     *rqst = CeedRequest_count++;
380     CeedRequest_n++;
381   }
382 }
383 
384 #define fCeedElemRestrictionApplyBlock \
385     FORTRAN_NAME(ceedelemrestrictionapplyblock,CEEDELEMRESTRICTIONAPPLYBLOCK)
386 void fCeedElemRestrictionApplyBlock(int *elemr, int *block, int *tmode,
387                                     int *uvec, int *ruvec, int *rqst, int *err) {
388   int createRequest = 1;
389   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
390   if (*rqst == FORTRAN_REQUEST_IMMEDIATE || *rqst == FORTRAN_REQUEST_ORDERED)
391     createRequest = 0;
392 
393   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
394     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
395     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
396   }
397 
398   CeedRequest *rqst_;
399   if      (*rqst == FORTRAN_REQUEST_IMMEDIATE) rqst_ = CEED_REQUEST_IMMEDIATE;
400   else if (*rqst == FORTRAN_REQUEST_ORDERED  ) rqst_ = CEED_REQUEST_ORDERED;
401   else rqst_ = &CeedRequest_dict[CeedRequest_count];
402 
403   *err = CeedElemRestrictionApplyBlock(CeedElemRestriction_dict[*elemr], *block,
404                                        (CeedTransposeMode)*tmode, CeedVector_dict[*uvec],
405                                        CeedVector_dict[*ruvec], rqst_);
406 
407   if (*err == 0 && createRequest) {
408     *rqst = CeedRequest_count++;
409     CeedRequest_n++;
410   }
411 }
412 
413 #define fCeedElemRestrictionGetMultiplicity \
414     FORTRAN_NAME(ceedelemrestrictiongetmultiplicity,CEEDELEMRESTRICTIONGETMULTIPLICITY)
415 void fCeedElemRestrictionGetMultiplicity(int *elemr, int *mult, int *err) {
416   *err = CeedElemRestrictionGetMultiplicity(CeedElemRestriction_dict[*elemr],
417          CeedVector_dict[*mult]);
418 }
419 
420 #define fCeedElemRestrictionGetELayout \
421     FORTRAN_NAME(ceedelemrestrictiongetelayout,CEEDELEMRESTRICTIONGETELAYOUT)
422 void fCeedElemRestrictionGetELayout(int *elemr, int *layout, int *err) {
423   CeedInt layout_c[3];
424   *err = CeedElemRestrictionGetELayout(CeedElemRestriction_dict[*elemr],
425                                        &layout_c);
426   for (int i=0; i<3; i++)
427     layout[i] = layout_c[i];
428 }
429 
430 #define fCeedElemRestrictionView \
431     FORTRAN_NAME(ceedelemrestrictionview,CEEDELEMRESTRICTIONVIEW)
432 void fCeedElemRestrictionView(int *elemr, int *err) {
433   *err = CeedElemRestrictionView(CeedElemRestriction_dict[*elemr], stdout);
434 }
435 
436 #define fCeedRequestWait FORTRAN_NAME(ceedrequestwait, CEEDREQUESTWAIT)
437 void fCeedRequestWait(int *rqst, int *err) {
438   // TODO Uncomment this once CeedRequestWait is implemented
439   //*err = CeedRequestWait(&CeedRequest_dict[*rqst]);
440 
441   if (*err == 0) {
442     CeedRequest_n--;
443     if (CeedRequest_n == 0) {
444       CeedFree(&CeedRequest_dict);
445       CeedRequest_count = 0;
446       CeedRequest_count_max = 0;
447     }
448   }
449 }
450 
451 #define fCeedElemRestrictionDestroy \
452     FORTRAN_NAME(ceedelemrestrictiondestroy,CEEDELEMRESTRICTIONDESTROY)
453 void fCeedElemRestrictionDestroy(int *elem, int *err) {
454   if (*elem == FORTRAN_NULL) return;
455   *err = CeedElemRestrictionDestroy(&CeedElemRestriction_dict[*elem]);
456 
457   if (*err == 0) {
458     *elem = FORTRAN_NULL;
459     CeedElemRestriction_n--;
460     if (CeedElemRestriction_n == 0) {
461       CeedFree(&CeedElemRestriction_dict);
462       CeedElemRestriction_count = 0;
463       CeedElemRestriction_count_max = 0;
464     }
465   }
466 }
467 
468 // -----------------------------------------------------------------------------
469 // CeedBasis
470 // -----------------------------------------------------------------------------
471 static CeedBasis *CeedBasis_dict = NULL;
472 static int CeedBasis_count = 0;
473 static int CeedBasis_n = 0;
474 static int CeedBasis_count_max = 0;
475 
476 #define fCeedBasisCreateTensorH1Lagrange \
477     FORTRAN_NAME(ceedbasiscreatetensorh1lagrange, CEEDBASISCREATETENSORH1LAGRANGE)
478 void fCeedBasisCreateTensorH1Lagrange(int *ceed, int *dim,
479                                       int *ncomp, int *P, int *Q, int *quadmode,
480                                       int *basis, int *err) {
481   if (CeedBasis_count == CeedBasis_count_max) {
482     CeedBasis_count_max += CeedBasis_count_max/2 + 1;
483     CeedRealloc(CeedBasis_count_max, &CeedBasis_dict);
484   }
485 
486   *err = CeedBasisCreateTensorH1Lagrange(Ceed_dict[*ceed], *dim, *ncomp, *P, *Q,
487                                          (CeedQuadMode)*quadmode,
488                                          &CeedBasis_dict[CeedBasis_count]);
489 
490   if (*err == 0) {
491     *basis = CeedBasis_count++;
492     CeedBasis_n++;
493   }
494 }
495 
496 #define fCeedBasisCreateTensorH1 \
497     FORTRAN_NAME(ceedbasiscreatetensorh1, CEEDBASISCREATETENSORH1)
498 void fCeedBasisCreateTensorH1(int *ceed, int *dim, int *ncomp, int *P1d,
499                               int *Q1d, const CeedScalar *interp1d,
500                               const CeedScalar *grad1d,
501                               const CeedScalar *qref1d,
502                               const CeedScalar *qweight1d, int *basis,
503                               int *err) {
504   if (CeedBasis_count == CeedBasis_count_max) {
505     CeedBasis_count_max += CeedBasis_count_max/2 + 1;
506     CeedRealloc(CeedBasis_count_max, &CeedBasis_dict);
507   }
508 
509   *err = CeedBasisCreateTensorH1(Ceed_dict[*ceed], *dim, *ncomp, *P1d, *Q1d,
510                                  interp1d, grad1d, qref1d, qweight1d,
511                                  &CeedBasis_dict[CeedBasis_count]);
512 
513   if (*err == 0) {
514     *basis = CeedBasis_count++;
515     CeedBasis_n++;
516   }
517 }
518 
519 #define fCeedBasisCreateH1 \
520     FORTRAN_NAME(ceedbasiscreateh1, CEEDBASISCREATEH1)
521 void fCeedBasisCreateH1(int *ceed, int *topo, int *ncomp, int *nnodes,
522                         int *nqpts, const CeedScalar *interp,
523                         const CeedScalar *grad, const CeedScalar *qref,
524                         const CeedScalar *qweight, int *basis, int *err) {
525   if (CeedBasis_count == CeedBasis_count_max) {
526     CeedBasis_count_max += CeedBasis_count_max/2 + 1;
527     CeedRealloc(CeedBasis_count_max, &CeedBasis_dict);
528   }
529 
530   *err = CeedBasisCreateH1(Ceed_dict[*ceed], (CeedElemTopology)*topo, *ncomp,
531                            *nnodes, *nqpts, interp, grad, qref, qweight,
532                            &CeedBasis_dict[CeedBasis_count]);
533 
534   if (*err == 0) {
535     *basis = CeedBasis_count++;
536     CeedBasis_n++;
537   }
538 }
539 
540 #define fCeedBasisView FORTRAN_NAME(ceedbasisview, CEEDBASISVIEW)
541 void fCeedBasisView(int *basis, int *err) {
542   *err = CeedBasisView(CeedBasis_dict[*basis], stdout);
543 }
544 
545 #define fCeedQRFactorization \
546     FORTRAN_NAME(ceedqrfactorization, CEEDQRFACTORIZATION)
547 void fCeedQRFactorization(int *ceed, CeedScalar *mat, CeedScalar *tau, int *m,
548                           int *n, int *err) {
549   *err = CeedQRFactorization(Ceed_dict[*ceed], mat, tau, *m, *n);
550 }
551 
552 #define fCeedSymmetricSchurDecomposition \
553     FORTRAN_NAME(ceedsymmetricschurdecomposition, CEEDSYMMETRICSCHURDECOMPOSITION)
554 void fCeedSymmetricSchurDecomposition(int *ceed, CeedScalar *mat,
555                                       CeedScalar *lambda, int *n, int *err) {
556   *err = CeedSymmetricSchurDecomposition(Ceed_dict[*ceed], mat, lambda, *n);
557 }
558 
559 #define fCeedSimultaneousDiagonalization \
560     FORTRAN_NAME(ceedsimultaneousdiagonalization, CEEDSIMULTANEOUSDIAGONALIZATION)
561 void fCeedSimultaneousDiagonalization(int *ceed, CeedScalar *matA,
562                                       CeedScalar *matB, CeedScalar *x,
563                                       CeedScalar *lambda, int *n, int *err) {
564   *err = CeedSimultaneousDiagonalization(Ceed_dict[*ceed], matA, matB, x,
565                                          lambda, *n);
566 }
567 
568 #define fCeedBasisGetCollocatedGrad \
569     FORTRAN_NAME(ceedbasisgetcollocatedgrad, CEEDBASISGETCOLLOCATEDGRAD)
570 void fCeedBasisGetCollocatedGrad(int *basis, CeedScalar *colograd1d,
571                                  int *err) {
572   *err = CeedBasisGetCollocatedGrad(CeedBasis_dict[*basis], colograd1d);
573 }
574 
575 #define fCeedBasisApply FORTRAN_NAME(ceedbasisapply, CEEDBASISAPPLY)
576 void fCeedBasisApply(int *basis, int *nelem, int *tmode, int *emode,
577                      int *u, int *v, int *err) {
578   *err = CeedBasisApply(CeedBasis_dict[*basis], *nelem, (CeedTransposeMode)*tmode,
579                         (CeedEvalMode)*emode,
580                         *u == FORTRAN_VECTOR_NONE ? CEED_VECTOR_NONE : CeedVector_dict[*u],
581                         CeedVector_dict[*v]);
582 }
583 
584 #define fCeedBasisGetNumNodes \
585     FORTRAN_NAME(ceedbasisgetnumnodes, CEEDBASISGETNUMNODES)
586 void fCeedBasisGetNumNodes(int *basis, int *P, int *err) {
587   *err = CeedBasisGetNumNodes(CeedBasis_dict[*basis], P);
588 }
589 
590 #define fCeedBasisGetNumQuadraturePoints \
591     FORTRAN_NAME(ceedbasisgetnumquadraturepoints, CEEDBASISGETNUMQUADRATUREPOINTS)
592 void fCeedBasisGetNumQuadraturePoints(int *basis, int *Q, int *err) {
593   *err = CeedBasisGetNumQuadraturePoints(CeedBasis_dict[*basis], Q);
594 }
595 
596 #define fCeedBasisGetInterp1D \
597     FORTRAN_NAME(ceedbasisgetinterp1d, CEEDBASISGETINTERP1D)
598 void fCeedBasisGetInterp1D(int *basis, CeedScalar *interp1d, int64_t *offset,
599                            int *err) {
600   const CeedScalar *interp1d_;
601   CeedBasis basis_ = CeedBasis_dict[*basis];
602   *err = CeedBasisGetInterp1D(basis_, &interp1d_);
603   *offset = interp1d_ - interp1d;
604 }
605 
606 #define fCeedBasisDestroy FORTRAN_NAME(ceedbasisdestroy,CEEDBASISDESTROY)
607 void fCeedBasisDestroy(int *basis, int *err) {
608   if (*basis == FORTRAN_NULL) return;
609   *err = CeedBasisDestroy(&CeedBasis_dict[*basis]);
610 
611   if (*err == 0) {
612     *basis = FORTRAN_NULL;
613     CeedBasis_n--;
614     if (CeedBasis_n == 0) {
615       CeedFree(&CeedBasis_dict);
616       CeedBasis_count = 0;
617       CeedBasis_count_max = 0;
618     }
619   }
620 }
621 
622 #define fCeedGaussQuadrature FORTRAN_NAME(ceedgaussquadrature, CEEDGAUSSQUADRATURE)
623 void fCeedGaussQuadrature(int *Q, CeedScalar *qref1d, CeedScalar *qweight1d,
624                           int *err) {
625   *err = CeedGaussQuadrature(*Q, qref1d, qweight1d);
626 }
627 
628 #define fCeedLobattoQuadrature \
629     FORTRAN_NAME(ceedlobattoquadrature, CEEDLOBATTOQUADRATURE)
630 void fCeedLobattoQuadrature(int *Q, CeedScalar *qref1d, CeedScalar *qweight1d,
631                             int *err) {
632   *err = CeedLobattoQuadrature(*Q, qref1d, qweight1d);
633 }
634 
635 // -----------------------------------------------------------------------------
636 // CeedQFunctionContext
637 // -----------------------------------------------------------------------------
638 static CeedQFunctionContext *CeedQFunctionContext_dict = NULL;
639 static int CeedQFunctionContext_count = 0;
640 static int CeedQFunctionContext_n = 0;
641 static int CeedQFunctionContext_count_max = 0;
642 
643 #define fCeedQFunctionContextCreate \
644     FORTRAN_NAME(ceedqfunctioncontextcreate,CEEDQFUNCTIONCONTEXTCREATE)
645 void fCeedQFunctionContextCreate(int *ceed, int *ctx, int *err) {
646   if (CeedQFunctionContext_count == CeedQFunctionContext_count_max) {
647     CeedQFunctionContext_count_max += CeedQFunctionContext_count_max/2 + 1;
648     CeedRealloc(CeedQFunctionContext_count_max, &CeedQFunctionContext_dict);
649   }
650 
651   CeedQFunctionContext *ctx_ =
652     &CeedQFunctionContext_dict[CeedQFunctionContext_count];
653 
654   *err = CeedQFunctionContextCreate(Ceed_dict[*ceed], ctx_);
655   if (*err) return;
656   *ctx = CeedQFunctionContext_count++;
657   CeedQFunctionContext_n++;
658 }
659 
660 #define fCeedQFunctionContextSetData \
661     FORTRAN_NAME(ceedqfunctioncontextsetdata,CEEDQFUNCTIONCONTEXTSETDATA)
662 void fCeedQFunctionContextSetData(int *ctx, int *memtype, int *copymode,
663                                   CeedInt *n,
664                                   CeedScalar *data, int64_t *offset, int *err) {
665   size_t ctxsize = ((size_t) *n)*sizeof(CeedScalar);
666   *err = CeedQFunctionContextSetData(CeedQFunctionContext_dict[*ctx],
667                                      (CeedMemType)*memtype,
668                                      (CeedCopyMode)*copymode, ctxsize,
669                                      data + *offset);
670 }
671 
672 #define fCeedQFunctionContextGetData \
673     FORTRAN_NAME(ceedqfunctioncontextgetdata,CEEDQFUNCTIONCONTEXTGETDATA)
674 void fCeedQFunctionContextGetData(int *ctx, int *memtype, CeedScalar *data,
675                                   int64_t *offset, int *err) {
676   CeedScalar *b;
677   CeedQFunctionContext ctx_ = CeedQFunctionContext_dict[*ctx];
678   *err = CeedQFunctionContextGetData(ctx_, (CeedMemType)*memtype, &b);
679   *offset = b - data;
680 }
681 
682 #define fCeedQFunctionContextRestoreData \
683     FORTRAN_NAME(ceedqfunctioncontextrestoredata,CEEDQFUNCTIONCONTEXTRESTOREDATA)
684 void fCeedQFunctionContextRestoreData(int *ctx, CeedScalar *data,
685                                       int64_t *offset, int *err) {
686   *err = CeedQFunctionContextRestoreData(CeedQFunctionContext_dict[*ctx],
687                                          (void **)&data);
688   *offset = 0;
689 }
690 
691 #define fCeedQFunctionContextView \
692     FORTRAN_NAME(ceedqfunctioncontextview,CEEDQFUNCTIONCONTEXTVIEW)
693 void fCeedQFunctionContextView(int *ctx, int *err) {
694   *err = CeedQFunctionContextView(CeedQFunctionContext_dict[*ctx], stdout);
695 }
696 
697 #define fCeedQFunctionContextDestroy \
698     FORTRAN_NAME(ceedqfunctioncontextdestroy,CEEDQFUNCTIONCONTEXTDESTROY)
699 void fCeedQFunctionContextDestroy(int *ctx, int *err) {
700   if (*ctx == FORTRAN_NULL) return;
701   *err = CeedQFunctionContextDestroy(&CeedQFunctionContext_dict[*ctx]);
702 
703   if (*err == 0) {
704     *ctx = FORTRAN_NULL;
705     CeedQFunctionContext_n--;
706     if (CeedQFunctionContext_n == 0) {
707       CeedFree(&CeedQFunctionContext_dict);
708       CeedQFunctionContext_count = 0;
709       CeedQFunctionContext_count_max = 0;
710     }
711   }
712 }
713 
714 // -----------------------------------------------------------------------------
715 // CeedQFunction
716 // -----------------------------------------------------------------------------
717 static CeedQFunction *CeedQFunction_dict = NULL;
718 static int CeedQFunction_count = 0;
719 static int CeedQFunction_n = 0;
720 static int CeedQFunction_count_max = 0;
721 
722 static int CeedQFunctionFortranStub(void *ctx, int nq,
723                                     const CeedScalar *const *u,
724                                     CeedScalar *const *v) {
725   CeedFortranContext fctx = ctx;
726   CeedQFunctionContext innerctx = fctx->innerctx;
727   int ierr;
728 
729   CeedScalar *ctx_ = NULL;
730   // Note: Device backends are generating their own kernels from
731   //         single source files, so only Host backends need to
732   //         use this Fortran stub.
733   if (innerctx) {
734     ierr = CeedQFunctionContextGetData(innerctx, CEED_MEM_HOST, &ctx_);
735     CeedChk(ierr);
736   }
737 
738   fctx->f((void *)ctx_,&nq,u[0],u[1],u[2],u[3],u[4],u[5],u[6],
739           u[7],u[8],u[9],u[10],u[11],u[12],u[13],u[14],u[15],
740           v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],
741           v[10],v[11],v[12],v[13],v[14],v[15],&ierr);
742 
743   if (innerctx) {
744     ierr = CeedQFunctionContextRestoreData(innerctx, (void *)&ctx_);
745     CeedChk(ierr);
746   }
747 
748   return ierr;
749 }
750 
751 #define fCeedQFunctionCreateInterior \
752     FORTRAN_NAME(ceedqfunctioncreateinterior, CEEDQFUNCTIONCREATEINTERIOR)
753 void fCeedQFunctionCreateInterior(int *ceed, int *vlength,
754                                   void (*f)(void *ctx, int *nq,
755                                       const CeedScalar *u,const CeedScalar *u1,
756                                       const CeedScalar *u2,const CeedScalar *u3,
757                                       const CeedScalar *u4,const CeedScalar *u5,
758                                       const CeedScalar *u6,const CeedScalar *u7,
759                                       const CeedScalar *u8,const CeedScalar *u9,
760                                       const CeedScalar *u10,const CeedScalar *u11,
761                                       const CeedScalar *u12,const CeedScalar *u13,
762                                       const CeedScalar *u14,const CeedScalar *u15,
763                                       CeedScalar *v,CeedScalar *v1,CeedScalar *v2,
764                                       CeedScalar *v3,CeedScalar *v4,
765                                       CeedScalar *v5,CeedScalar *v6,
766                                       CeedScalar *v7,CeedScalar *v8,
767                                       CeedScalar *v9,CeedScalar *v10,
768                                       CeedScalar *v11,CeedScalar *v12,
769                                       CeedScalar *v13,CeedScalar *v14,
770                                       CeedScalar *v15,int *err),
771                                   const char *source, int *qf, int *err,
772                                   fortran_charlen_t source_len) {
773   FIX_STRING(source);
774   if (CeedQFunction_count == CeedQFunction_count_max) {
775     CeedQFunction_count_max += CeedQFunction_count_max/2 + 1;
776     CeedRealloc(CeedQFunction_count_max, &CeedQFunction_dict);
777   }
778 
779   CeedQFunction *qf_ = &CeedQFunction_dict[CeedQFunction_count];
780   *err = CeedQFunctionCreateInterior(Ceed_dict[*ceed], *vlength,
781                                      CeedQFunctionFortranStub, source_c, qf_);
782 
783   if (*err == 0) {
784     *qf = CeedQFunction_count++;
785     CeedQFunction_n++;
786   }
787 
788   CeedFortranContext fctxdata;
789   *err = CeedCalloc(1, &fctxdata);
790   if (*err) return;
791   fctxdata->f = f; fctxdata->innerctx = NULL;
792   CeedQFunctionContext fctx;
793   *err = CeedQFunctionContextCreate(Ceed_dict[*ceed], &fctx);
794   if (*err) return;
795   *err = CeedQFunctionContextSetData(fctx, CEED_MEM_HOST, CEED_OWN_POINTER,
796                                      sizeof(*fctxdata), fctxdata);
797   if (*err) return;
798   *err = CeedQFunctionSetContext(*qf_, fctx);
799   if (*err) return;
800   CeedQFunctionContextDestroy(&fctx);
801   if (*err) return;
802 
803   *err = CeedQFunctionSetFortranStatus(*qf_, true);
804 }
805 
806 #define fCeedQFunctionCreateInteriorByName \
807     FORTRAN_NAME(ceedqfunctioncreateinteriorbyname, CEEDQFUNCTIONCREATEINTERIORBYNAME)
808 void fCeedQFunctionCreateInteriorByName(int *ceed, const char *name, int *qf,
809                                         int *err, fortran_charlen_t name_len) {
810   FIX_STRING(name);
811   if (CeedQFunction_count == CeedQFunction_count_max) {
812     CeedQFunction_count_max += CeedQFunction_count_max/2 + 1;
813     CeedRealloc(CeedQFunction_count_max, &CeedQFunction_dict);
814   }
815 
816   CeedQFunction *qf_ = &CeedQFunction_dict[CeedQFunction_count];
817   *err = CeedQFunctionCreateInteriorByName(Ceed_dict[*ceed], name_c, qf_);
818 
819   if (*err == 0) {
820     *qf = CeedQFunction_count++;
821     CeedQFunction_n++;
822   }
823 }
824 
825 #define fCeedQFunctionCreateIdentity \
826     FORTRAN_NAME(ceedqfunctioncreateidentity, CEEDQFUNCTIONCREATEIDENTITY)
827 void fCeedQFunctionCreateIdentity(int *ceed, int *size, int *inmode,
828                                   int *outmode, int *qf, int *err) {
829   if (CeedQFunction_count == CeedQFunction_count_max) {
830     CeedQFunction_count_max += CeedQFunction_count_max/2 + 1;
831     CeedRealloc(CeedQFunction_count_max, &CeedQFunction_dict);
832   }
833 
834   CeedQFunction *qf_ = &CeedQFunction_dict[CeedQFunction_count];
835   *err = CeedQFunctionCreateIdentity(Ceed_dict[*ceed], *size,
836                                      (CeedEvalMode)*inmode,
837                                      (CeedEvalMode)*outmode, qf_);
838 
839   if (*err == 0) {
840     *qf = CeedQFunction_count++;
841     CeedQFunction_n++;
842   }
843 }
844 
845 #define fCeedQFunctionAddInput \
846     FORTRAN_NAME(ceedqfunctionaddinput,CEEDQFUNCTIONADDINPUT)
847 void fCeedQFunctionAddInput(int *qf, const char *fieldname,
848                             CeedInt *ncomp, CeedEvalMode *emode, int *err,
849                             fortran_charlen_t fieldname_len) {
850   FIX_STRING(fieldname);
851   CeedQFunction qf_ = CeedQFunction_dict[*qf];
852 
853   *err = CeedQFunctionAddInput(qf_, fieldname_c, *ncomp, *emode);
854 }
855 
856 #define fCeedQFunctionAddOutput \
857     FORTRAN_NAME(ceedqfunctionaddoutput,CEEDQFUNCTIONADDOUTPUT)
858 void fCeedQFunctionAddOutput(int *qf, const char *fieldname,
859                              CeedInt *ncomp, CeedEvalMode *emode, int *err,
860                              fortran_charlen_t fieldname_len) {
861   FIX_STRING(fieldname);
862   CeedQFunction qf_ = CeedQFunction_dict[*qf];
863 
864   *err = CeedQFunctionAddOutput(qf_, fieldname_c, *ncomp, *emode);
865 }
866 
867 #define fCeedQFunctionSetContext \
868     FORTRAN_NAME(ceedqfunctionsetcontext,CEEDQFUNCTIONSETCONTEXT)
869 void fCeedQFunctionSetContext(int *qf, int *ctx, int *err) {
870   CeedQFunction qf_ = CeedQFunction_dict[*qf];
871   CeedQFunctionContext ctx_ = CeedQFunctionContext_dict[*ctx];
872 
873   CeedQFunctionContext fctx;
874   *err = CeedQFunctionGetContext(qf_, &fctx);
875   if (*err) return;
876   CeedFortranContext fctxdata;
877   *err = CeedQFunctionContextGetData(fctx, CEED_MEM_HOST, &fctxdata);
878   if (*err) return;
879   fctxdata->innerctx = ctx_;
880   *err = CeedQFunctionContextRestoreData(fctx, (void **)&fctxdata);
881 }
882 
883 #define fCeedQFunctionView \
884     FORTRAN_NAME(ceedqfunctionview,CEEDQFUNCTIONVIEW)
885 void fCeedQFunctionView(int *qf, int *err) {
886   CeedQFunction qf_ = CeedQFunction_dict[*qf];
887 
888   *err = CeedQFunctionView(qf_, stdout);
889 }
890 
891 #define fCeedQFunctionApply \
892     FORTRAN_NAME(ceedqfunctionapply,CEEDQFUNCTIONAPPLY)
893 //TODO Need Fixing, double pointer
894 void fCeedQFunctionApply(int *qf, int *Q,
895                          int *u, int *u1, int *u2, int *u3,
896                          int *u4, int *u5, int *u6, int *u7,
897                          int *u8, int *u9, int *u10, int *u11,
898                          int *u12, int *u13, int *u14, int *u15,
899                          int *v, int *v1, int *v2, int *v3,
900                          int *v4, int *v5, int *v6, int *v7,
901                          int *v8, int *v9, int *v10, int *v11,
902                          int *v12, int *v13, int *v14, int *v15, int *err) {
903   CeedQFunction qf_ = CeedQFunction_dict[*qf];
904   CeedVector *in;
905   *err = CeedCalloc(16, &in);
906   if (*err) return;
907   in[0] = *u==FORTRAN_NULL?NULL:CeedVector_dict[*u];
908   in[1] = *u1==FORTRAN_NULL?NULL:CeedVector_dict[*u1];
909   in[2] = *u2==FORTRAN_NULL?NULL:CeedVector_dict[*u2];
910   in[3] = *u3==FORTRAN_NULL?NULL:CeedVector_dict[*u3];
911   in[4] = *u4==FORTRAN_NULL?NULL:CeedVector_dict[*u4];
912   in[5] = *u5==FORTRAN_NULL?NULL:CeedVector_dict[*u5];
913   in[6] = *u6==FORTRAN_NULL?NULL:CeedVector_dict[*u6];
914   in[7] = *u7==FORTRAN_NULL?NULL:CeedVector_dict[*u7];
915   in[8] = *u8==FORTRAN_NULL?NULL:CeedVector_dict[*u8];
916   in[9] = *u9==FORTRAN_NULL?NULL:CeedVector_dict[*u9];
917   in[10] = *u10==FORTRAN_NULL?NULL:CeedVector_dict[*u10];
918   in[11] = *u11==FORTRAN_NULL?NULL:CeedVector_dict[*u11];
919   in[12] = *u12==FORTRAN_NULL?NULL:CeedVector_dict[*u12];
920   in[13] = *u13==FORTRAN_NULL?NULL:CeedVector_dict[*u13];
921   in[14] = *u14==FORTRAN_NULL?NULL:CeedVector_dict[*u14];
922   in[15] = *u15==FORTRAN_NULL?NULL:CeedVector_dict[*u15];
923   CeedVector *out;
924   *err = CeedCalloc(16, &out);
925   if (*err) return;
926   out[0] = *v==FORTRAN_NULL?NULL:CeedVector_dict[*v];
927   out[1] = *v1==FORTRAN_NULL?NULL:CeedVector_dict[*v1];
928   out[2] = *v2==FORTRAN_NULL?NULL:CeedVector_dict[*v2];
929   out[3] = *v3==FORTRAN_NULL?NULL:CeedVector_dict[*v3];
930   out[4] = *v4==FORTRAN_NULL?NULL:CeedVector_dict[*v4];
931   out[5] = *v5==FORTRAN_NULL?NULL:CeedVector_dict[*v5];
932   out[6] = *v6==FORTRAN_NULL?NULL:CeedVector_dict[*v6];
933   out[7] = *v7==FORTRAN_NULL?NULL:CeedVector_dict[*v7];
934   out[8] = *v8==FORTRAN_NULL?NULL:CeedVector_dict[*v8];
935   out[9] = *v9==FORTRAN_NULL?NULL:CeedVector_dict[*v9];
936   out[10] = *v10==FORTRAN_NULL?NULL:CeedVector_dict[*v10];
937   out[11] = *v11==FORTRAN_NULL?NULL:CeedVector_dict[*v11];
938   out[12] = *v12==FORTRAN_NULL?NULL:CeedVector_dict[*v12];
939   out[13] = *v13==FORTRAN_NULL?NULL:CeedVector_dict[*v13];
940   out[14] = *v14==FORTRAN_NULL?NULL:CeedVector_dict[*v14];
941   out[15] = *v15==FORTRAN_NULL?NULL:CeedVector_dict[*v15];
942   *err = CeedQFunctionApply(qf_, *Q, in, out);
943   if (*err) return;
944 
945   *err = CeedFree(&in);
946   if (*err) return;
947   *err = CeedFree(&out);
948 }
949 
950 #define fCeedQFunctionDestroy \
951     FORTRAN_NAME(ceedqfunctiondestroy,CEEDQFUNCTIONDESTROY)
952 void fCeedQFunctionDestroy(int *qf, int *err) {
953   if (*qf == FORTRAN_NULL) return;
954 
955   *err = CeedQFunctionDestroy(&CeedQFunction_dict[*qf]);
956   if (*err == 0) {
957     *qf = FORTRAN_NULL;
958     CeedQFunction_n--;
959     if (CeedQFunction_n == 0) {
960       *err = CeedFree(&CeedQFunction_dict);
961       CeedQFunction_count = 0;
962       CeedQFunction_count_max = 0;
963     }
964   }
965 }
966 
967 // -----------------------------------------------------------------------------
968 // CeedOperator
969 // -----------------------------------------------------------------------------
970 static CeedOperator *CeedOperator_dict = NULL;
971 static int CeedOperator_count = 0;
972 static int CeedOperator_n = 0;
973 static int CeedOperator_count_max = 0;
974 
975 #define fCeedOperatorCreate \
976     FORTRAN_NAME(ceedoperatorcreate, CEEDOPERATORCREATE)
977 void fCeedOperatorCreate(int *ceed,
978                          int *qf, int *dqf, int *dqfT, int *op, int *err) {
979   if (CeedOperator_count == CeedOperator_count_max) {
980     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
981     CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
982   }
983 
984   CeedOperator *op_ = &CeedOperator_dict[CeedOperator_count];
985 
986   CeedQFunction dqf_  = CEED_QFUNCTION_NONE, dqfT_ = CEED_QFUNCTION_NONE;
987   if (*dqf  != FORTRAN_QFUNCTION_NONE) dqf_  = CeedQFunction_dict[*dqf ];
988   if (*dqfT != FORTRAN_QFUNCTION_NONE) dqfT_ = CeedQFunction_dict[*dqfT];
989 
990   *err = CeedOperatorCreate(Ceed_dict[*ceed], CeedQFunction_dict[*qf], dqf_,
991                             dqfT_, op_);
992   if (*err) return;
993   *op = CeedOperator_count++;
994   CeedOperator_n++;
995 }
996 
997 #define fCeedCompositeOperatorCreate \
998     FORTRAN_NAME(ceedcompositeoperatorcreate, CEEDCOMPOSITEOPERATORCREATE)
999 void fCeedCompositeOperatorCreate(int *ceed, int *op, int *err) {
1000   if (CeedOperator_count == CeedOperator_count_max) {
1001     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
1002     CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
1003   }
1004 
1005   CeedOperator *op_ = &CeedOperator_dict[CeedOperator_count];
1006 
1007   *err = CeedCompositeOperatorCreate(Ceed_dict[*ceed], op_);
1008   if (*err) return;
1009   *op = CeedOperator_count++;
1010   CeedOperator_n++;
1011 }
1012 
1013 #define fCeedOperatorSetField \
1014     FORTRAN_NAME(ceedoperatorsetfield,CEEDOPERATORSETFIELD)
1015 void fCeedOperatorSetField(int *op, const char *fieldname, int *r, int *b,
1016                            int *v, int *err, fortran_charlen_t fieldname_len) {
1017   FIX_STRING(fieldname);
1018   CeedElemRestriction r_;
1019   CeedBasis b_;
1020   CeedVector v_;
1021 
1022   CeedOperator op_ = CeedOperator_dict[*op];
1023 
1024   if (*r == FORTRAN_NULL) {
1025     r_ = NULL;
1026   } else if (*r == FORTRAN_ELEMRESTRICTION_NONE) {
1027     r_ = CEED_ELEMRESTRICTION_NONE;
1028   } else {
1029     r_ = CeedElemRestriction_dict[*r];
1030   }
1031 
1032   if (*b == FORTRAN_NULL) {
1033     b_ = NULL;
1034   } else if (*b == FORTRAN_BASIS_COLLOCATED) {
1035     b_ = CEED_BASIS_COLLOCATED;
1036   } else {
1037     b_ = CeedBasis_dict[*b];
1038   }
1039   if (*v == FORTRAN_NULL) {
1040     v_ = NULL;
1041   } else if (*v == FORTRAN_VECTOR_ACTIVE) {
1042     v_ = CEED_VECTOR_ACTIVE;
1043   } else if (*v == FORTRAN_VECTOR_NONE) {
1044     v_ = CEED_VECTOR_NONE;
1045   } else {
1046     v_ = CeedVector_dict[*v];
1047   }
1048 
1049   *err = CeedOperatorSetField(op_, fieldname_c, r_, b_, v_);
1050 }
1051 
1052 #define fCeedCompositeOperatorAddSub \
1053     FORTRAN_NAME(ceedcompositeoperatoraddsub, CEEDCOMPOSITEOPERATORADDSUB)
1054 void fCeedCompositeOperatorAddSub(int *compositeop, int *subop, int *err) {
1055   CeedOperator compositeop_ = CeedOperator_dict[*compositeop];
1056   CeedOperator subop_ = CeedOperator_dict[*subop];
1057 
1058   *err = CeedCompositeOperatorAddSub(compositeop_, subop_);
1059   if (*err) return;
1060 }
1061 
1062 #define fCeedOperatorLinearAssembleQFunction \
1063     FORTRAN_NAME(ceedoperatorlinearassembleqfunction, CEEDOPERATORLINEARASSEMBLEQFUNCTION)
1064 void fCeedOperatorLinearAssembleQFunction(int *op, int *assembledvec,
1065     int *assembledrstr, int *rqst, int *err) {
1066   // Vector
1067   if (CeedVector_count == CeedVector_count_max) {
1068     CeedVector_count_max += CeedVector_count_max/2 + 1;
1069     CeedRealloc(CeedVector_count_max, &CeedVector_dict);
1070   }
1071   CeedVector *assembledvec_ = &CeedVector_dict[CeedVector_count];
1072 
1073   // Restriction
1074   if (CeedElemRestriction_count == CeedElemRestriction_count_max) {
1075     CeedElemRestriction_count_max += CeedElemRestriction_count_max/2 + 1;
1076     CeedRealloc(CeedElemRestriction_count_max, &CeedElemRestriction_dict);
1077   }
1078   CeedElemRestriction *rstr_ =
1079     &CeedElemRestriction_dict[CeedElemRestriction_count];
1080 
1081   int createRequest = 1;
1082   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
1083   if (*rqst == -1 || *rqst == -2) {
1084     createRequest = 0;
1085   }
1086 
1087   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
1088     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
1089     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
1090   }
1091 
1092   CeedRequest *rqst_;
1093   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
1094   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
1095   else rqst_ = &CeedRequest_dict[CeedRequest_count];
1096 
1097   *err = CeedOperatorLinearAssembleQFunction(CeedOperator_dict[*op],
1098          assembledvec_, rstr_, rqst_);
1099   if (*err) return;
1100   if (createRequest) {
1101     *rqst = CeedRequest_count++;
1102     CeedRequest_n++;
1103   }
1104 
1105   if (*err == 0) {
1106     *assembledrstr = CeedElemRestriction_count++;
1107     CeedElemRestriction_n++;
1108     *assembledvec = CeedVector_count++;
1109     CeedVector_n++;
1110   }
1111 }
1112 
1113 #define fCeedOperatorLinearAssembleDiagonal \
1114     FORTRAN_NAME(ceedoperatorlinearassemblediagonal, CEEDOPERATORLINEARASSEMBLEDIAGONAL)
1115 void fCeedOperatorLinearAssembleDiagonal(int *op, int *assembledvec,
1116     int *rqst, int *err) {
1117   int createRequest = 1;
1118   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
1119   if (*rqst == -1 || *rqst == -2) {
1120     createRequest = 0;
1121   }
1122 
1123   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
1124     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
1125     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
1126   }
1127 
1128   CeedRequest *rqst_;
1129   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
1130   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
1131   else rqst_ = &CeedRequest_dict[CeedRequest_count];
1132 
1133   *err = CeedOperatorLinearAssembleDiagonal(CeedOperator_dict[*op],
1134          CeedVector_dict[*assembledvec], rqst_);
1135   if (*err) return;
1136   if (createRequest) {
1137     *rqst = CeedRequest_count++;
1138     CeedRequest_n++;
1139   }
1140 }
1141 
1142 #define fCeedOperatorMultigridLevelCreate \
1143     FORTRAN_NAME(ceedoperatormultigridlevelcreate, CEEDOPERATORMULTIGRIDLEVELCREATE)
1144 void fCeedOperatorMultigridLevelCreate(int *opFine, int *pMultFine,
1145                                        int *rstrCoarse, int *basisCoarse, int *opCoarse,
1146                                        int *opProlong, int *opRestrict, int *err) {
1147   // Operators
1148   CeedOperator opCoarse_, opProlong_, opRestrict_;
1149 
1150   // C interface call
1151   *err = CeedOperatorMultigridLevelCreate(
1152            CeedOperator_dict[*opFine], CeedVector_dict[*pMultFine],
1153            CeedElemRestriction_dict[*rstrCoarse],
1154            CeedBasis_dict[*basisCoarse],
1155            &opCoarse_, &opProlong_, &opRestrict_);
1156 
1157   if (*err) return;
1158   while (CeedOperator_count + 2 >= CeedOperator_count_max) {
1159     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
1160   }
1161   CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
1162   CeedOperator_dict[CeedOperator_count] = opCoarse_;
1163   *opCoarse = CeedOperator_count++;
1164   CeedOperator_dict[CeedOperator_count] = opProlong_;
1165   *opProlong = CeedOperator_count++;
1166   CeedOperator_dict[CeedOperator_count] = opRestrict_;
1167   *opRestrict = CeedOperator_count++;
1168   CeedOperator_n += 3;
1169 }
1170 
1171 #define fCeedOperatorMultigridLevelCreateTensorH1 \
1172     FORTRAN_NAME(ceedoperatormultigridlevelcreatetensorh1, CEEDOPERATORMULTIGRIDLEVELCREATETENSORH1)
1173 void fCeedOperatorMultigridLevelCreateTensorH1(int *opFine, int *pMultFine,
1174     int *rstrCoarse, int *basisCoarse, const CeedScalar *interpCtoF,
1175     int *opCoarse, int *opProlong, int *opRestrict, int *err) {
1176   // Operators
1177   CeedOperator opCoarse_, opProlong_, opRestrict_;
1178 
1179   // C interface call
1180   *err = CeedOperatorMultigridLevelCreateTensorH1(
1181            CeedOperator_dict[*opFine], CeedVector_dict[*pMultFine],
1182            CeedElemRestriction_dict[*rstrCoarse], CeedBasis_dict[*basisCoarse],
1183            interpCtoF, &opCoarse_, &opProlong_, &opRestrict_);
1184 
1185   if (*err) return;
1186   while (CeedOperator_count + 2 >= CeedOperator_count_max) {
1187     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
1188   }
1189   CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
1190   CeedOperator_dict[CeedOperator_count] = opCoarse_;
1191   *opCoarse = CeedOperator_count++;
1192   CeedOperator_dict[CeedOperator_count] = opProlong_;
1193   *opProlong = CeedOperator_count++;
1194   CeedOperator_dict[CeedOperator_count] = opRestrict_;
1195   *opRestrict = CeedOperator_count++;
1196   CeedOperator_n += 3;
1197 }
1198 
1199 #define fCeedOperatorMultigridLevelCreateH1 \
1200     FORTRAN_NAME(ceedoperatormultigridlevelcreateh1, CEEDOPERATORMULTIGRIDLEVELCREATEH1)
1201 void fCeedOperatorMultigridLevelCreateH1(int *opFine, int *pMultFine,
1202     int *rstrCoarse, int *basisCoarse, const CeedScalar *interpCtoF,
1203     int *opCoarse, int *opProlong, int *opRestrict, int *err) {
1204   // Operators
1205   CeedOperator opCoarse_, opProlong_, opRestrict_;
1206 
1207   // C interface call
1208   *err = CeedOperatorMultigridLevelCreateH1(
1209            CeedOperator_dict[*opFine], CeedVector_dict[*pMultFine],
1210            CeedElemRestriction_dict[*rstrCoarse], CeedBasis_dict[*basisCoarse],
1211            interpCtoF, &opCoarse_, &opProlong_, &opRestrict_);
1212 
1213   if (*err) return;
1214   while (CeedOperator_count + 2 >= CeedOperator_count_max) {
1215     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
1216   }
1217   CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
1218   CeedOperator_dict[CeedOperator_count] = opCoarse_;
1219   *opCoarse = CeedOperator_count++;
1220   CeedOperator_dict[CeedOperator_count] = opProlong_;
1221   *opProlong = CeedOperator_count++;
1222   CeedOperator_dict[CeedOperator_count] = opRestrict_;
1223   *opRestrict = CeedOperator_count++;
1224   CeedOperator_n += 3;
1225 }
1226 
1227 #define fCeedOperatorView \
1228     FORTRAN_NAME(ceedoperatorview,CEEDOPERATORVIEW)
1229 void fCeedOperatorView(int *op, int *err) {
1230   CeedOperator op_ = CeedOperator_dict[*op];
1231 
1232   *err = CeedOperatorView(op_, stdout);
1233 }
1234 
1235 #define fCeedOperatorCreateFDMElementInverse \
1236     FORTRAN_NAME(ceedoperatorcreatefdmelementinverse, CEEDOPERATORCREATEFDMELEMENTINVERSE)
1237 void fCeedOperatorCreateFDMElementInverse(int *op, int *fdminv,
1238     int *rqst, int *err) {
1239   // Operator
1240   if (CeedOperator_count == CeedOperator_count_max) {
1241     CeedOperator_count_max += CeedOperator_count_max/2 + 1;
1242     CeedRealloc(CeedOperator_count_max, &CeedOperator_dict);
1243   }
1244   CeedOperator *fdminv_ =
1245     &CeedOperator_dict[CeedOperator_count];
1246 
1247   int createRequest = 1;
1248   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
1249   if (*rqst == -1 || *rqst == -2) {
1250     createRequest = 0;
1251   }
1252 
1253   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
1254     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
1255     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
1256   }
1257 
1258   CeedRequest *rqst_;
1259   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
1260   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
1261   else rqst_ = &CeedRequest_dict[CeedRequest_count];
1262 
1263   *err = CeedOperatorCreateFDMElementInverse(CeedOperator_dict[*op],
1264          fdminv_, rqst_);
1265   if (*err) return;
1266   if (createRequest) {
1267     *rqst = CeedRequest_count++;
1268     CeedRequest_n++;
1269   }
1270 
1271   if (*err == 0) {
1272     *fdminv = CeedOperator_count++;
1273     CeedOperator_n++;
1274   }
1275 }
1276 
1277 #define fCeedOperatorApply FORTRAN_NAME(ceedoperatorapply, CEEDOPERATORAPPLY)
1278 void fCeedOperatorApply(int *op, int *ustatevec,
1279                         int *resvec, int *rqst, int *err) {
1280   CeedVector ustatevec_ = (*ustatevec == FORTRAN_NULL) ?
1281                           NULL : (*ustatevec == FORTRAN_VECTOR_NONE ?
1282                                   CEED_VECTOR_NONE : CeedVector_dict[*ustatevec]);
1283   CeedVector resvec_ = (*resvec == FORTRAN_NULL) ?
1284                        NULL : (*resvec == FORTRAN_VECTOR_NONE ?
1285                                CEED_VECTOR_NONE : CeedVector_dict[*resvec]);
1286 
1287   int createRequest = 1;
1288   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
1289   if (*rqst == -1 || *rqst == -2) {
1290     createRequest = 0;
1291   }
1292 
1293   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
1294     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
1295     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
1296   }
1297 
1298   CeedRequest *rqst_;
1299   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
1300   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
1301   else rqst_ = &CeedRequest_dict[CeedRequest_count];
1302 
1303   *err = CeedOperatorApply(CeedOperator_dict[*op],
1304                            ustatevec_, resvec_, rqst_);
1305   if (*err) return;
1306   if (createRequest) {
1307     *rqst = CeedRequest_count++;
1308     CeedRequest_n++;
1309   }
1310 }
1311 
1312 #define fCeedOperatorApplyAdd FORTRAN_NAME(ceedoperatorapplyadd, CEEDOPERATORAPPLYADD)
1313 void fCeedOperatorApplyAdd(int *op, int *ustatevec,
1314                            int *resvec, int *rqst, int *err) {
1315   CeedVector ustatevec_ = *ustatevec == FORTRAN_NULL
1316                           ? NULL : CeedVector_dict[*ustatevec];
1317   CeedVector resvec_ = *resvec == FORTRAN_NULL
1318                        ? NULL : CeedVector_dict[*resvec];
1319 
1320   int createRequest = 1;
1321   // Check if input is CEED_REQUEST_ORDERED(-2) or CEED_REQUEST_IMMEDIATE(-1)
1322   if (*rqst == -1 || *rqst == -2) {
1323     createRequest = 0;
1324   }
1325 
1326   if (createRequest && CeedRequest_count == CeedRequest_count_max) {
1327     CeedRequest_count_max += CeedRequest_count_max/2 + 1;
1328     CeedRealloc(CeedRequest_count_max, &CeedRequest_dict);
1329   }
1330 
1331   CeedRequest *rqst_;
1332   if (*rqst == -1) rqst_ = CEED_REQUEST_IMMEDIATE;
1333   else if (*rqst == -2) rqst_ = CEED_REQUEST_ORDERED;
1334   else rqst_ = &CeedRequest_dict[CeedRequest_count];
1335 
1336   *err = CeedOperatorApplyAdd(CeedOperator_dict[*op],
1337                               ustatevec_, resvec_, rqst_);
1338   if (*err) return;
1339   if (createRequest) {
1340     *rqst = CeedRequest_count++;
1341     CeedRequest_n++;
1342   }
1343 }
1344 
1345 #define fCeedOperatorApplyJacobian \
1346     FORTRAN_NAME(ceedoperatorapplyjacobian, CEEDOPERATORAPPLYJACOBIAN)
1347 void fCeedOperatorApplyJacobian(int *op, int *qdatavec, int *ustatevec,
1348                                 int *dustatevec, int *dresvec, int *rqst,
1349                                 int *err) {
1350 // TODO Uncomment this when CeedOperatorApplyJacobian is implemented
1351 //  *err = CeedOperatorApplyJacobian(CeedOperator_dict[*op], CeedVector_dict[*qdatavec],
1352 //             CeedVector_dict[*ustatevec], CeedVector_dict[*dustatevec],
1353 //             CeedVector_dict[*dresvec], &CeedRequest_dict[*rqst]);
1354 }
1355 
1356 #define fCeedOperatorDestroy \
1357     FORTRAN_NAME(ceedoperatordestroy, CEEDOPERATORDESTROY)
1358 void fCeedOperatorDestroy(int *op, int *err) {
1359   if (*op == FORTRAN_NULL) return;
1360   *err = CeedOperatorDestroy(&CeedOperator_dict[*op]);
1361   if (*err == 0) {
1362     *op = FORTRAN_NULL;
1363     CeedOperator_n--;
1364     if (CeedOperator_n == 0) {
1365       *err = CeedFree(&CeedOperator_dict);
1366       CeedOperator_count = 0;
1367       CeedOperator_count_max = 0;
1368     }
1369   }
1370 }
1371 
1372 // -----------------------------------------------------------------------------
1373