xref: /libCEED/interface/ceed-operator.c (revision 8b067b84f843731ea3f7eb73e31f61efee53b5f0)
1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3 // 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 #include <ceed-impl.h>
18 #include <ceed-backend.h>
19 #include <string.h>
20 
21 /// @file
22 /// Implementation of public CeedOperator interfaces
23 ///
24 /// @addtogroup CeedOperator
25 ///   @{
26 
27 /**
28   @brief Create an operator from element restriction, basis, and QFunction
29 
30   @param ceed    A Ceed object where the CeedOperator will be created
31   @param qf      QFunction defining the action of the operator at quadrature points
32   @param dqf     QFunction defining the action of the Jacobian of @a qf (or NULL)
33   @param dqfT    QFunction defining the action of the transpose of the Jacobian
34                    of @a qf (or NULL)
35   @param[out] op Address of the variable where the newly created
36                      CeedOperator will be stored
37 
38   @return An error code: 0 - success, otherwise - failure
39 
40   @ref Basic
41  */
42 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
43                        CeedQFunction dqfT, CeedOperator *op) {
44   int ierr;
45 
46   if (!ceed->OperatorCreate) {
47     Ceed delegate;
48     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
49 
50     if (!delegate)
51       return CeedError(ceed, 1, "Backend does not support OperatorCreate");
52 
53     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
54     return 0;
55   }
56 
57   ierr = CeedCalloc(1,op); CeedChk(ierr);
58   (*op)->ceed = ceed;
59   ceed->refcount++;
60   (*op)->refcount = 1;
61   (*op)->qf = qf;
62   qf->refcount++;
63   (*op)->dqf = dqf;
64   if (dqf) dqf->refcount++;
65   (*op)->dqfT = dqfT;
66   if (dqfT) dqfT->refcount++;
67   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
68   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
69   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
70   return 0;
71 }
72 
73 /**
74   @brief Create an operator that composes the action of several operators
75 
76   @param ceed    A Ceed object where the CeedOperator will be created
77   @param[out] op Address of the variable where the newly created
78                      Composite CeedOperator will be stored
79 
80   @return An error code: 0 - success, otherwise - failure
81 
82   @ref Basic
83  */
84 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
85   int ierr;
86 
87   if (!ceed->CompositeOperatorCreate) {
88     Ceed delegate;
89     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
90 
91     if (!delegate)
92       return CeedError(ceed, 1, "Backend does not support \
93                                    CompositeOperatorCreate");
94 
95     ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
96     return 0;
97   }
98 
99   ierr = CeedCalloc(1,op); CeedChk(ierr);
100   (*op)->ceed = ceed;
101   ceed->refcount++;
102   (*op)->composite = true;
103   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
104   ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
105   return 0;
106 }
107 
108 /**
109   @brief Provide a field to a CeedOperator for use by its CeedQFunction
110 
111   This function is used to specify both active and passive fields to a
112   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
113   fields can inputs or outputs (updated in-place when operator is applied).
114 
115   Active fields must be specified using this function, but their data (in a
116   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
117   input and at most one active output.
118 
119   @param op         CeedOperator on which to provide the field
120   @param fieldname  Name of the field (to be matched with the name used by
121                       CeedQFunction)
122   @param r          CeedElemRestriction
123   @param lmode      CeedTransposeMode which specifies the ordering of the
124                       components of the l-vector used by this CeedOperatorField,
125                       CEED_NOTRANSPOSE indicates the component is the
126                       outermost index and CEED_TRANSPOSE indicates the component
127                       is the innermost index in ordering of the l-vector
128   @param b          CeedBasis in which the field resides or CEED_BASIS_COLLOCATED
129                       if collocated with quadrature points
130   @param v          CeedVector to be used by CeedOperator or CEED_VECTOR_ACTIVE
131                       if field is active or CEED_VECTOR_NONE if using
132                       CEED_EVAL_WEIGHT in the QFunction
133 
134   @return An error code: 0 - success, otherwise - failure
135 
136   @ref Basic
137 **/
138 int CeedOperatorSetField(CeedOperator op, const char *fieldname,
139                          CeedElemRestriction r, CeedTransposeMode lmode,
140                          CeedBasis b, CeedVector v) {
141   int ierr;
142   if (op->composite)
143     return CeedError(op->ceed, 1, "Cannot add field to composite operator.");
144   if (!r)
145     return CeedError(op->ceed, 1, "ElemRestriction r for field \"%s\" must be non-NULL.", fieldname);
146   if (!b)
147     return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.", fieldname);
148   if (!v)
149     return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.", fieldname);
150 
151   CeedInt numelements;
152   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
153   if (op->numelements && op->numelements != numelements)
154     return CeedError(op->ceed, 1,
155                      "ElemRestriction with %d elements incompatible with prior %d elements",
156                      numelements, op->numelements);
157   op->numelements = numelements;
158 
159   if (b != CEED_BASIS_COLLOCATED) {
160     CeedInt numqpoints;
161     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
162     if (op->numqpoints && op->numqpoints != numqpoints)
163       return CeedError(op->ceed, 1,
164                        "Basis with %d quadrature points incompatible with prior %d points",
165                        numqpoints, op->numqpoints);
166     op->numqpoints = numqpoints;
167   }
168   CeedOperatorField *ofield;
169   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
170     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
171       ofield = &op->inputfields[i];
172       goto found;
173     }
174   }
175   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
176     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
177       ofield = &op->outputfields[i];
178       goto found;
179     }
180   }
181   return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'",
182                    fieldname);
183 found:
184   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
185   (*ofield)->Erestrict = r;
186   (*ofield)->lmode = lmode;
187   (*ofield)->basis = b;
188   (*ofield)->vec = v;
189   op->nfields += 1;
190   return 0;
191 }
192 
193 /**
194   @brief Add a sub-operator to a composite CeedOperator
195 
196   @param[out] compositeop Address of the composite CeedOperator
197   @param      subop       Address of the sub-operator CeedOperator
198 
199   @return An error code: 0 - success, otherwise - failure
200 
201   @ref Basic
202  */
203 int CeedCompositeOperatorAddSub(CeedOperator compositeop,
204                                 CeedOperator subop) {
205   if (!compositeop->composite)
206     return CeedError(compositeop->ceed, 1,
207                      "CeedOperator is not a composite operator");
208 
209   if (compositeop->numsub == CEED_COMPOSITE_MAX)
210     return CeedError(compositeop->ceed, 1,
211                      "Cannot add additional suboperators");
212 
213   compositeop->suboperators[compositeop->numsub] = subop;
214   subop->refcount++;
215   compositeop->numsub++;
216   return 0;
217 }
218 
219 /**
220   @brief Apply CeedOperator to a vector
221 
222   This computes the action of the operator on the specified (active) input,
223   yielding its (active) output.  All inputs and outputs must be specified using
224   CeedOperatorSetField().
225 
226   @param op        CeedOperator to apply
227   @param[in] in    CeedVector containing input state or NULL if there are no
228                      active inputs
229   @param[out] out  CeedVector to store result of applying operator (must be
230                      distinct from @a in) or NULL if there are no active outputs
231   @param request   Address of CeedRequest for non-blocking completion, else
232                      CEED_REQUEST_IMMEDIATE
233 
234   @return An error code: 0 - success, otherwise - failure
235 
236   @ref Basic
237 **/
238 int CeedOperatorApply(CeedOperator op, CeedVector in,
239                       CeedVector out, CeedRequest *request) {
240   int ierr;
241   Ceed ceed = op->ceed;
242   CeedQFunction qf = op->qf;
243 
244   if (op->composite) {
245     if (!op->numsub) return CeedError(ceed, 1, "No suboperators set");
246   } else {
247     if (op->nfields == 0) return CeedError(ceed, 1, "No operator fields set");
248     if (op->nfields < qf->numinputfields + qf->numoutputfields) return CeedError(
249             ceed, 1, "Not all operator fields set");
250     if (op->numelements == 0) return CeedError(ceed, 1,
251                                        "At least one restriction required");
252     if (op->numqpoints == 0) return CeedError(ceed, 1,
253                                       "At least one non-collocated basis required");
254   }
255   ierr = op->Apply(op, in, out, request); CeedChk(ierr);
256   return 0;
257 }
258 
259 /**
260   @brief Get the Ceed associated with a CeedOperator
261 
262   @param op              CeedOperator
263   @param[out] ceed       Variable to store Ceed
264 
265   @return An error code: 0 - success, otherwise - failure
266 
267   @ref Advanced
268 **/
269 
270 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
271   *ceed = op->ceed;
272   return 0;
273 }
274 
275 /**
276   @brief Get the number of elements associated with a CeedOperator
277 
278   @param op              CeedOperator
279   @param[out] numelem    Variable to store number of elements
280 
281   @return An error code: 0 - success, otherwise - failure
282 
283   @ref Advanced
284 **/
285 
286 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
287   if (op->composite)
288     return CeedError(op->ceed, 1, "Not defined for composite operator");
289 
290   *numelem = op->numelements;
291   return 0;
292 }
293 
294 /**
295   @brief Get the number of quadrature points associated with a CeedOperator
296 
297   @param op              CeedOperator
298   @param[out] numqpts    Variable to store vector number of quadrature points
299 
300   @return An error code: 0 - success, otherwise - failure
301 
302   @ref Advanced
303 **/
304 
305 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
306   if (op->composite)
307     return CeedError(op->ceed, 1, "Not defined for composite operator");
308 
309   *numqpts = op->numqpoints;
310   return 0;
311 }
312 
313 /**
314   @brief Get the number of arguments associated with a CeedOperator
315 
316   @param op              CeedOperator
317   @param[out] numargs    Variable to store vector number of arguments
318 
319   @return An error code: 0 - success, otherwise - failure
320 
321   @ref Advanced
322 **/
323 
324 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
325   if (op->composite)
326     return CeedError(op->ceed, 1, "Not defined for composite operators");
327   *numargs = op->nfields;
328   return 0;
329 }
330 
331 /**
332   @brief Get the setup status of a CeedOperator
333 
334   @param op             CeedOperator
335   @param[out] setupdone Variable to store setup status
336 
337   @return An error code: 0 - success, otherwise - failure
338 
339   @ref Advanced
340 **/
341 
342 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
343   *setupdone = op->setupdone;
344   return 0;
345 }
346 
347 /**
348   @brief Get the QFunction associated with a CeedOperator
349 
350   @param op              CeedOperator
351   @param[out] qf         Variable to store QFunction
352 
353   @return An error code: 0 - success, otherwise - failure
354 
355   @ref Advanced
356 **/
357 
358 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
359   if (op->composite)
360     return CeedError(op->ceed, 1, "Not defined for composite operator");
361 
362   *qf = op->qf;
363   return 0;
364 }
365 
366 /**
367   @brief Get the number of suboperators associated with a CeedOperator
368 
369   @param op              CeedOperator
370   @param[out] numsub     Variable to store number of suboperators
371 
372   @return An error code: 0 - success, otherwise - failure
373 
374   @ref Advanced
375 **/
376 
377 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
378   Ceed ceed = op->ceed;
379   if (!op->composite) return CeedError(ceed, 1, "Not a composite operator");
380 
381   *numsub = op->numsub;
382   return 0;
383 }
384 
385 /**
386   @brief Get the list of suboperators associated with a CeedOperator
387 
388   @param op                CeedOperator
389   @param[out] suboperators Variable to store list of suboperators
390 
391   @return An error code: 0 - success, otherwise - failure
392 
393   @ref Advanced
394 **/
395 
396 int CeedOperatorGetSubList(CeedOperator op, CeedOperator* *suboperators) {
397   Ceed ceed = op->ceed;
398   if (!op->composite) return CeedError(ceed, 1, "Not a composite operator");
399 
400   *suboperators = op->suboperators;
401   return 0;
402 }
403 
404 /**
405   @brief Set the backend data of a CeedOperator
406 
407   @param[out] op         CeedOperator
408   @param data            Data to set
409 
410   @return An error code: 0 - success, otherwise - failure
411 
412   @ref Advanced
413 **/
414 
415 int CeedOperatorSetData(CeedOperator op, void* *data) {
416   op->data = *data;
417   return 0;
418 }
419 
420 /**
421   @brief Get the backend data of a CeedOperator
422 
423   @param op              CeedOperator
424   @param[out] data       Variable to store data
425 
426   @return An error code: 0 - success, otherwise - failure
427 
428   @ref Advanced
429 **/
430 
431 int CeedOperatorGetData(CeedOperator op, void* *data) {
432   *data = op->data;
433   return 0;
434 }
435 
436 /**
437   @brief Set the setup flag of a CeedOperator to True
438 
439   @param op              CeedOperator
440 
441   @return An error code: 0 - success, otherwise - failure
442 
443   @ref Advanced
444 **/
445 
446 int CeedOperatorSetSetupDone(CeedOperator op) {
447   op->setupdone = 1;
448   return 0;
449 }
450 
451 /**
452   @brief Get the CeedOperatorFields of a CeedOperator
453 
454   @param op                 CeedOperator
455   @param[out] inputfields   Variable to store inputfields
456   @param[out] outputfields  Variable to store outputfields
457 
458   @return An error code: 0 - success, otherwise - failure
459 
460   @ref Advanced
461 **/
462 
463 int CeedOperatorGetFields(CeedOperator op,
464                           CeedOperatorField* *inputfields,
465                           CeedOperatorField* *outputfields) {
466   if (op->composite)
467     return CeedError(op->ceed, 1, "Not defined for composite operator");
468 
469   if (inputfields) *inputfields = op->inputfields;
470   if (outputfields) *outputfields = op->outputfields;
471   return 0;
472 }
473 
474 /**
475   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
476 
477   @param opfield         CeedOperatorField
478   @param[out] lmode      Variable to store CeedTransposeMode
479 
480   @return An error code: 0 - success, otherwise - failure
481 
482   @ref Advanced
483 **/
484 
485 int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
486                               CeedTransposeMode *lmode) {
487   *lmode = opfield->lmode;
488   return 0;
489 }/**
490   @brief Get the CeedElemRestriction of a CeedOperatorField
491 
492   @param opfield         CeedOperatorField
493   @param[out] rstr       Variable to store CeedElemRestriction
494 
495   @return An error code: 0 - success, otherwise - failure
496 
497   @ref Advanced
498 **/
499 
500 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
501                                         CeedElemRestriction *rstr) {
502   *rstr = opfield->Erestrict;
503   return 0;
504 }
505 
506 /**
507   @brief Get the CeedBasis of a CeedOperatorField
508 
509   @param opfield         CeedOperatorField
510   @param[out] basis      Variable to store CeedBasis
511 
512   @return An error code: 0 - success, otherwise - failure
513 
514   @ref Advanced
515 **/
516 
517 int CeedOperatorFieldGetBasis(CeedOperatorField opfield,
518                               CeedBasis *basis) {
519   *basis = opfield->basis;
520   return 0;
521 }
522 
523 /**
524   @brief Get the CeedVector of a CeedOperatorField
525 
526   @param opfield         CeedOperatorField
527   @param[out] vec        Variable to store CeedVector
528 
529   @return An error code: 0 - success, otherwise - failure
530 
531   @ref Advanced
532 **/
533 
534 int CeedOperatorFieldGetVector(CeedOperatorField opfield,
535                                CeedVector *vec) {
536   *vec = opfield->vec;
537   return 0;
538 }
539 
540 /**
541   @brief Destroy a CeedOperator
542 
543   @param op CeedOperator to destroy
544 
545   @return An error code: 0 - success, otherwise - failure
546 
547   @ref Basic
548 **/
549 int CeedOperatorDestroy(CeedOperator *op) {
550   int ierr;
551 
552   if (!*op || --(*op)->refcount > 0) return 0;
553   if ((*op)->Destroy) {
554     ierr = (*op)->Destroy(*op); CeedChk(ierr);
555   }
556   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
557   // Free fields
558   for (int i=0; i<(*op)->nfields; i++) {
559     if ((*op)->inputfields[i]) {
560       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
561     }
562   }
563   for (int i=0; i<(*op)->nfields; i++) {
564     if ((*op)->outputfields[i]) {
565       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
566     }
567   }
568   // Destroy suboperators
569   for (int i=0; i<(*op)->numsub; i++) {
570     if ((*op)->suboperators[i]) {
571       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
572     }
573   }
574   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
575   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
576   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
577 
578   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
579   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
580   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
581   ierr = CeedFree(op); CeedChk(ierr);
582   return 0;
583 }
584 
585 /// @}
586