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