xref: /libCEED/interface/ceed-operator.c (revision 288c044332e33f37503f09b6484fec9d0a55fba1)
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 
145   CeedInt numelements;
146   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
147   if (op->numelements && op->numelements != numelements)
148     return CeedError(op->ceed, 1,
149                      "ElemRestriction with %d elements incompatible with prior %d elements",
150                      numelements, op->numelements);
151   op->numelements = numelements;
152 
153   if (b != CEED_BASIS_COLLOCATED) {
154     CeedInt numqpoints;
155     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
156     if (op->numqpoints && op->numqpoints != numqpoints)
157       return CeedError(op->ceed, 1,
158                        "Basis with %d quadrature points incompatible with prior %d points",
159                        numqpoints, op->numqpoints);
160     op->numqpoints = numqpoints;
161   }
162   CeedOperatorField *ofield;
163   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
164     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
165       ofield = &op->inputfields[i];
166       goto found;
167     }
168   }
169   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
170     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
171       ofield = &op->outputfields[i];
172       goto found;
173     }
174   }
175   return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'",
176                    fieldname);
177 found:
178   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
179   (*ofield)->Erestrict = r;
180   (*ofield)->lmode = lmode;
181   (*ofield)->basis = b;
182   (*ofield)->vec = v;
183   op->nfields += 1;
184   return 0;
185 }
186 
187 /**
188   @brief Add a sub-operator to a composite CeedOperator
189 
190   @param[out] compositeop Address of the composite CeedOperator
191   @param      subop       Address of the sub-operator CeedOperator
192 
193   @return An error code: 0 - success, otherwise - failure
194 
195   @ref Basic
196  */
197 int CeedCompositeOperatorAddSub(CeedOperator compositeop,
198                                 CeedOperator subop) {
199   if (!compositeop->composite)
200     return CeedError(compositeop->ceed, 1,
201                      "CeedOperator is not a composite operator");
202 
203   if (compositeop->numsub == CEED_COMPOSITE_MAX)
204     return CeedError(compositeop->ceed, 1,
205                      "Cannot add additional suboperators");
206 
207   compositeop->suboperators[compositeop->numsub] = subop;
208   subop->refcount++;
209   compositeop->numsub++;
210   return 0;
211 }
212 
213 /**
214   @brief Apply CeedOperator to a vector
215 
216   This computes the action of the operator on the specified (active) input,
217   yielding its (active) output.  All inputs and outputs must be specified using
218   CeedOperatorSetField().
219 
220   @param op        CeedOperator to apply
221   @param[in] in    CeedVector containing input state or NULL if there are no
222                      active inputs
223   @param[out] out  CeedVector to store result of applying operator (must be
224                      distinct from @a in) or NULL if there are no active outputs
225   @param request   Address of CeedRequest for non-blocking completion, else
226                      CEED_REQUEST_IMMEDIATE
227 
228   @return An error code: 0 - success, otherwise - failure
229 
230   @ref Basic
231 **/
232 int CeedOperatorApply(CeedOperator op, CeedVector in,
233                       CeedVector out, CeedRequest *request) {
234   int ierr;
235   Ceed ceed = op->ceed;
236   CeedQFunction qf = op->qf;
237 
238   if (op->composite) {
239     if (!op->numsub) return CeedError(ceed, 1, "No suboperators set");
240   } else {
241     if (op->nfields == 0) return CeedError(ceed, 1, "No operator fields set");
242     if (op->nfields < qf->numinputfields + qf->numoutputfields) return CeedError(
243             ceed, 1, "Not all operator fields set");
244     if (op->numelements == 0) return CeedError(ceed, 1,
245                                        "At least one restriction required");
246     if (op->numqpoints == 0) return CeedError(ceed, 1,
247                                       "At least one non-collocated basis required");
248   }
249   ierr = op->Apply(op, in, out, request); CeedChk(ierr);
250   return 0;
251 }
252 
253 /**
254   @brief Get the Ceed associated with a CeedOperator
255 
256   @param op              CeedOperator
257   @param[out] ceed       Variable to store Ceed
258 
259   @return An error code: 0 - success, otherwise - failure
260 
261   @ref Advanced
262 **/
263 
264 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
265   *ceed = op->ceed;
266   return 0;
267 }
268 
269 /**
270   @brief Get the number of elements associated with a CeedOperator
271 
272   @param op              CeedOperator
273   @param[out] numelem    Variable to store number of elements
274 
275   @return An error code: 0 - success, otherwise - failure
276 
277   @ref Advanced
278 **/
279 
280 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
281   if (op->composite)
282     return CeedError(op->ceed, 1, "Not defined for composite operator");
283 
284   *numelem = op->numelements;
285   return 0;
286 }
287 
288 /**
289   @brief Get the number of quadrature points associated with a CeedOperator
290 
291   @param op              CeedOperator
292   @param[out] numqpts    Variable to store vector number of quadrature points
293 
294   @return An error code: 0 - success, otherwise - failure
295 
296   @ref Advanced
297 **/
298 
299 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
300   if (op->composite)
301     return CeedError(op->ceed, 1, "Not defined for composite operator");
302 
303   *numqpts = op->numqpoints;
304   return 0;
305 }
306 
307 /**
308   @brief Get the number of arguments associated with a CeedOperator
309 
310   @param op              CeedOperator
311   @param[out] numargs    Variable to store vector number of arguments
312 
313   @return An error code: 0 - success, otherwise - failure
314 
315   @ref Advanced
316 **/
317 
318 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
319   if (op->composite)
320     return CeedError(op->ceed, 1, "Not defined for composite operators");
321   *numargs = op->nfields;
322   return 0;
323 }
324 
325 /**
326   @brief Get the setup status of a CeedOperator
327 
328   @param op             CeedOperator
329   @param[out] setupdone Variable to store setup status
330 
331   @return An error code: 0 - success, otherwise - failure
332 
333   @ref Advanced
334 **/
335 
336 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
337   *setupdone = op->setupdone;
338   return 0;
339 }
340 
341 /**
342   @brief Get the QFunction associated with a CeedOperator
343 
344   @param op              CeedOperator
345   @param[out] qf         Variable to store QFunction
346 
347   @return An error code: 0 - success, otherwise - failure
348 
349   @ref Advanced
350 **/
351 
352 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
353   if (op->composite)
354     return CeedError(op->ceed, 1, "Not defined for composite operator");
355 
356   *qf = op->qf;
357   return 0;
358 }
359 
360 /**
361   @brief Get the number of suboperators associated with a CeedOperator
362 
363   @param op              CeedOperator
364   @param[out] numsub     Variable to store number of suboperators
365 
366   @return An error code: 0 - success, otherwise - failure
367 
368   @ref Advanced
369 **/
370 
371 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
372   Ceed ceed = op->ceed;
373   if (!op->composite) return CeedError(ceed, 1, "Not a composite operator");
374 
375   *numsub = op->numsub;
376   return 0;
377 }
378 
379 /**
380   @brief Get the list of suboperators associated with a CeedOperator
381 
382   @param op                CeedOperator
383   @param[out] suboperators Variable to store list of suboperators
384 
385   @return An error code: 0 - success, otherwise - failure
386 
387   @ref Advanced
388 **/
389 
390 int CeedOperatorGetSubList(CeedOperator op, CeedOperator* *suboperators) {
391   Ceed ceed = op->ceed;
392   if (!op->composite) return CeedError(ceed, 1, "Not a composite operator");
393 
394   *suboperators = op->suboperators;
395   return 0;
396 }
397 
398 /**
399   @brief Set the backend data of a CeedOperator
400 
401   @param[out] op         CeedOperator
402   @param data            Data to set
403 
404   @return An error code: 0 - success, otherwise - failure
405 
406   @ref Advanced
407 **/
408 
409 int CeedOperatorSetData(CeedOperator op, void* *data) {
410   op->data = *data;
411   return 0;
412 }
413 
414 /**
415   @brief Get the backend data of a CeedOperator
416 
417   @param op              CeedOperator
418   @param[out] data       Variable to store data
419 
420   @return An error code: 0 - success, otherwise - failure
421 
422   @ref Advanced
423 **/
424 
425 int CeedOperatorGetData(CeedOperator op, void* *data) {
426   *data = op->data;
427   return 0;
428 }
429 
430 /**
431   @brief Set the setup flag of a CeedOperator to True
432 
433   @param op              CeedOperator
434 
435   @return An error code: 0 - success, otherwise - failure
436 
437   @ref Advanced
438 **/
439 
440 int CeedOperatorSetSetupDone(CeedOperator op) {
441   op->setupdone = 1;
442   return 0;
443 }
444 
445 /**
446   @brief Get the CeedOperatorFields of a CeedOperator
447 
448   @param op                 CeedOperator
449   @param[out] inputfields   Variable to store inputfields
450   @param[out] outputfields  Variable to store outputfields
451 
452   @return An error code: 0 - success, otherwise - failure
453 
454   @ref Advanced
455 **/
456 
457 int CeedOperatorGetFields(CeedOperator op,
458                           CeedOperatorField* *inputfields,
459                           CeedOperatorField* *outputfields) {
460   if (op->composite)
461     return CeedError(op->ceed, 1, "Not defined for composite operator");
462 
463   if (inputfields) *inputfields = op->inputfields;
464   if (outputfields) *outputfields = op->outputfields;
465   return 0;
466 }
467 
468 /**
469   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
470 
471   @param opfield         CeedOperatorField
472   @param[out] lmode      Variable to store CeedTransposeMode
473 
474   @return An error code: 0 - success, otherwise - failure
475 
476   @ref Advanced
477 **/
478 
479 int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
480                               CeedTransposeMode *lmode) {
481   *lmode = opfield->lmode;
482   return 0;
483 }/**
484   @brief Get the CeedElemRestriction of a CeedOperatorField
485 
486   @param opfield         CeedOperatorField
487   @param[out] rstr       Variable to store CeedElemRestriction
488 
489   @return An error code: 0 - success, otherwise - failure
490 
491   @ref Advanced
492 **/
493 
494 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
495                                         CeedElemRestriction *rstr) {
496   *rstr = opfield->Erestrict;
497   return 0;
498 }
499 
500 /**
501   @brief Get the CeedBasis of a CeedOperatorField
502 
503   @param opfield         CeedOperatorField
504   @param[out] basis      Variable to store CeedBasis
505 
506   @return An error code: 0 - success, otherwise - failure
507 
508   @ref Advanced
509 **/
510 
511 int CeedOperatorFieldGetBasis(CeedOperatorField opfield,
512                               CeedBasis *basis) {
513   *basis = opfield->basis;
514   return 0;
515 }
516 
517 /**
518   @brief Get the CeedVector of a CeedOperatorField
519 
520   @param opfield         CeedOperatorField
521   @param[out] vec        Variable to store CeedVector
522 
523   @return An error code: 0 - success, otherwise - failure
524 
525   @ref Advanced
526 **/
527 
528 int CeedOperatorFieldGetVector(CeedOperatorField opfield,
529                                CeedVector *vec) {
530   *vec = opfield->vec;
531   return 0;
532 }
533 
534 /**
535   @brief Destroy a CeedOperator
536 
537   @param op CeedOperator to destroy
538 
539   @return An error code: 0 - success, otherwise - failure
540 
541   @ref Basic
542 **/
543 int CeedOperatorDestroy(CeedOperator *op) {
544   int ierr;
545 
546   if (!*op || --(*op)->refcount > 0) return 0;
547   if ((*op)->Destroy) {
548     ierr = (*op)->Destroy(*op); CeedChk(ierr);
549   }
550   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
551   // Free fields
552   for (int i=0; i<(*op)->nfields; i++) {
553     if ((*op)->inputfields[i]) {
554       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
555     }
556   }
557   for (int i=0; i<(*op)->nfields; i++) {
558     if ((*op)->outputfields[i]) {
559       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
560     }
561   }
562   // Destroy suboperators
563   for (int i=0; i<(*op)->numsub; i++) {
564     if ((*op)->suboperators[i]) {
565       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
566     }
567   }
568   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
569   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
570   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
571 
572   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
573   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
574   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
575   ierr = CeedFree(op); CeedChk(ierr);
576   return 0;
577 }
578 
579 /// @}
580