xref: /petsc/src/vec/pf/interface/pf.c (revision 27f49a208b01d2e827ab9db411a2d16003fe9262)
1 /*
2     The PF mathematical functions interface routines, callable by users.
3 */
4 #include <../src/vec/pf/pfimpl.h> /*I "petscpf.h" I*/
5 
6 PetscClassId      PF_CLASSID          = 0;
7 PetscFunctionList PFList              = NULL; /* list of all registered PD functions */
8 PetscBool         PFRegisterAllCalled = PETSC_FALSE;
9 
10 /*@C
11    PFSet - Sets the C/C++/Fortran functions to be used by the PF function
12 
13    Collective
14 
15    Input Parameters:
16 +  pf - the function context
17 .  apply - function to apply to an array
18 .  applyvec - function to apply to a Vec
19 .  view - function that prints information about the PF
20 .  destroy - function to free the private function context
21 -  ctx - private function context
22 
23    Level: beginner
24 
25 .seealso: `PF`, `PFCreate()`, `PFDestroy()`, `PFSetType()`, `PFApply()`, `PFApplyVec()`
26 @*/
27 PetscErrorCode PFSet(PF pf, PetscErrorCode (*apply)(void *, PetscInt, const PetscScalar *, PetscScalar *), PetscErrorCode (*applyvec)(void *, Vec, Vec), PetscErrorCode (*view)(void *, PetscViewer), PetscErrorCode (*destroy)(void *), void *ctx)
28 {
29   PetscFunctionBegin;
30   PetscValidHeaderSpecific(pf, PF_CLASSID, 1);
31   pf->data          = ctx;
32   pf->ops->destroy  = destroy;
33   pf->ops->apply    = apply;
34   pf->ops->applyvec = applyvec;
35   pf->ops->view     = view;
36   PetscFunctionReturn(PETSC_SUCCESS);
37 }
38 
39 /*@C
40    PFDestroy - Destroys `PF` context that was created with `PFCreate()`.
41 
42    Collective
43 
44    Input Parameter:
45 .  pf - the function context
46 
47    Level: beginner
48 
49 .seealso: `PF`, `PFCreate()`, `PFSet()`, `PFSetType()`
50 @*/
51 PetscErrorCode PFDestroy(PF *pf)
52 {
53   PetscFunctionBegin;
54   if (!*pf) PetscFunctionReturn(PETSC_SUCCESS);
55   PetscValidHeaderSpecific((*pf), PF_CLASSID, 1);
56   if (--((PetscObject)(*pf))->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
57 
58   PetscCall(PFViewFromOptions(*pf, NULL, "-pf_view"));
59   /* if memory was published with SAWs then destroy it */
60   PetscCall(PetscObjectSAWsViewOff((PetscObject)*pf));
61 
62   if ((*pf)->ops->destroy) PetscCall((*(*pf)->ops->destroy)((*pf)->data));
63   PetscCall(PetscHeaderDestroy(pf));
64   PetscFunctionReturn(PETSC_SUCCESS);
65 }
66 
67 /*@C
68    PFCreate - Creates a mathematical function context.
69 
70    Collective
71 
72    Input Parameters:
73 +  comm - MPI communicator
74 .  dimin - dimension of the space you are mapping from
75 -  dimout - dimension of the space you are mapping to
76 
77    Output Parameter:
78 .  pf - the function context
79 
80    Level: developer
81 
82 .seealso: `PF`, `PFSet()`, `PFApply()`, `PFDestroy()`, `PFApplyVec()`
83 @*/
84 PetscErrorCode PFCreate(MPI_Comm comm, PetscInt dimin, PetscInt dimout, PF *pf)
85 {
86   PF newpf;
87 
88   PetscFunctionBegin;
89   PetscValidPointer(pf, 4);
90   *pf = NULL;
91   PetscCall(PFInitializePackage());
92 
93   PetscCall(PetscHeaderCreate(newpf, PF_CLASSID, "PF", "Mathematical functions", "Vec", comm, PFDestroy, PFView));
94   newpf->data          = NULL;
95   newpf->ops->destroy  = NULL;
96   newpf->ops->apply    = NULL;
97   newpf->ops->applyvec = NULL;
98   newpf->ops->view     = NULL;
99   newpf->dimin         = dimin;
100   newpf->dimout        = dimout;
101 
102   *pf = newpf;
103   PetscFunctionReturn(PETSC_SUCCESS);
104 }
105 
106 /* -------------------------------------------------------------------------------*/
107 
108 /*@
109    PFApplyVec - Applies the mathematical function to a vector
110 
111    Collective
112 
113    Input Parameters:
114 +  pf - the function context
115 -  x - input vector (or NULL for the vector (0,1, .... N-1)
116 
117    Output Parameter:
118 .  y - output vector
119 
120    Level: beginner
121 
122 .seealso: `PF`, `PFApply()`, `PFCreate()`, `PFDestroy()`, `PFSetType()`, `PFSet()`
123 @*/
124 PetscErrorCode PFApplyVec(PF pf, Vec x, Vec y)
125 {
126   PetscInt  i, rstart, rend, n, p;
127   PetscBool nox = PETSC_FALSE;
128 
129   PetscFunctionBegin;
130   PetscValidHeaderSpecific(pf, PF_CLASSID, 1);
131   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
132   if (x) {
133     PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
134     PetscCheck(x != y, PETSC_COMM_SELF, PETSC_ERR_ARG_IDN, "x and y must be different vectors");
135   } else {
136     PetscScalar *xx;
137     PetscInt     lsize;
138 
139     PetscCall(VecGetLocalSize(y, &lsize));
140     lsize = pf->dimin * lsize / pf->dimout;
141     PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)y), lsize, PETSC_DETERMINE, &x));
142     nox = PETSC_TRUE;
143     PetscCall(VecGetOwnershipRange(x, &rstart, &rend));
144     PetscCall(VecGetArray(x, &xx));
145     for (i = rstart; i < rend; i++) xx[i - rstart] = (PetscScalar)i;
146     PetscCall(VecRestoreArray(x, &xx));
147   }
148 
149   PetscCall(VecGetLocalSize(x, &n));
150   PetscCall(VecGetLocalSize(y, &p));
151   PetscCheck((pf->dimin * (n / pf->dimin)) == n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local input vector length %" PetscInt_FMT " not divisible by dimin %" PetscInt_FMT " of function", n, pf->dimin);
152   PetscCheck((pf->dimout * (p / pf->dimout)) == p, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local output vector length %" PetscInt_FMT " not divisible by dimout %" PetscInt_FMT " of function", p, pf->dimout);
153   PetscCheck((n / pf->dimin) == (p / pf->dimout), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local vector lengths %" PetscInt_FMT " %" PetscInt_FMT " are wrong for dimin and dimout %" PetscInt_FMT " %" PetscInt_FMT " of function", n, p, pf->dimin, pf->dimout);
154 
155   if (pf->ops->applyvec) PetscCall((*pf->ops->applyvec)(pf->data, x, y));
156   else {
157     PetscScalar *xx, *yy;
158 
159     PetscCall(VecGetLocalSize(x, &n));
160     n = n / pf->dimin;
161     PetscCall(VecGetArray(x, &xx));
162     PetscCall(VecGetArray(y, &yy));
163     PetscCall((*pf->ops->apply)(pf->data, n, xx, yy));
164     PetscCall(VecRestoreArray(x, &xx));
165     PetscCall(VecRestoreArray(y, &yy));
166   }
167   if (nox) PetscCall(VecDestroy(&x));
168   PetscFunctionReturn(PETSC_SUCCESS);
169 }
170 
171 /*@
172    PFApply - Applies the mathematical function to an array of values.
173 
174    Collective
175 
176    Input Parameters:
177 +  pf - the function context
178 .  n - number of pointwise function evaluations to perform, each pointwise function evaluation
179        is a function of dimin variables and computes dimout variables where dimin and dimout are defined
180        in the call to PFCreate()
181 -  x - input array
182 
183    Output Parameter:
184 .  y - output array
185 
186    Level: beginner
187 
188    Notes:
189 
190 .seealso: `PF`, `PFApplyVec()`, `PFCreate()`, `PFDestroy()`, `PFSetType()`, `PFSet()`
191 @*/
192 PetscErrorCode PFApply(PF pf, PetscInt n, const PetscScalar *x, PetscScalar *y)
193 {
194   PetscFunctionBegin;
195   PetscValidHeaderSpecific(pf, PF_CLASSID, 1);
196   PetscValidScalarPointer(x, 3);
197   PetscValidScalarPointer(y, 4);
198   PetscCheck(x != y, PETSC_COMM_SELF, PETSC_ERR_ARG_IDN, "x and y must be different arrays");
199 
200   PetscCall((*pf->ops->apply)(pf->data, n, x, y));
201   PetscFunctionReturn(PETSC_SUCCESS);
202 }
203 
204 /*@C
205    PFViewFromOptions - View a `PF` based on options set in the options database
206 
207    Collective
208 
209    Input Parameters:
210 +  A - the `PF` context
211 .  obj - Optional object that provides the prefix used to search the options database
212 -  name - command line option
213 
214    Level: intermediate
215 
216    Note:
217   See `PetscObjectViewFromOptions()` for the variety of viewer options available
218 
219 .seealso: `PF`, `PFView`, `PetscObjectViewFromOptions()`, `PFCreate()`
220 @*/
221 PetscErrorCode PFViewFromOptions(PF A, PetscObject obj, const char name[])
222 {
223   PetscFunctionBegin;
224   PetscValidHeaderSpecific(A, PF_CLASSID, 1);
225   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
226   PetscFunctionReturn(PETSC_SUCCESS);
227 }
228 
229 /*@
230    PFView - Prints information about a mathematical function
231 
232    Collective unless `viewer` is `PETSC_VIEWER_STDOUT_SELF`
233 
234    Input Parameters:
235 +  PF - the `PF` context
236 -  viewer - optional visualization context
237 
238    Level: developer
239 
240    Note:
241    The available visualization contexts include
242 +     `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
243 -     `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard
244          output where only the first processor opens
245          the file.  All other processors send their
246          data to the first processor to print.
247 
248    The user can open an alternative visualization contexts with
249    `PetscViewerASCIIOpen()` (output to a specified file).
250 
251 .seealso: `PF`, `PetscViewerCreate()`, `PetscViewerASCIIOpen()`
252 @*/
253 PetscErrorCode PFView(PF pf, PetscViewer viewer)
254 {
255   PetscBool         iascii;
256   PetscViewerFormat format;
257 
258   PetscFunctionBegin;
259   PetscValidHeaderSpecific(pf, PF_CLASSID, 1);
260   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)pf), &viewer));
261   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
262   PetscCheckSameComm(pf, 1, viewer, 2);
263 
264   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
265   if (iascii) {
266     PetscCall(PetscViewerGetFormat(viewer, &format));
267     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)pf, viewer));
268     if (pf->ops->view) {
269       PetscCall(PetscViewerASCIIPushTab(viewer));
270       PetscCall((*pf->ops->view)(pf->data, viewer));
271       PetscCall(PetscViewerASCIIPopTab(viewer));
272     }
273   }
274   PetscFunctionReturn(PETSC_SUCCESS);
275 }
276 
277 /*@C
278    PFRegister - Adds a method to the mathematical function package.
279 
280    Not Collective
281 
282    Input Parameters:
283 +  sname - name of a new user-defined solver
284 -  function - routine to create method context
285 
286    Sample usage:
287 .vb
288    PFRegister("my_function",MyFunctionSetCreate);
289 .ve
290 
291    Then, your solver can be chosen with the procedural interface via
292 $     PFSetType(pf,"my_function")
293    or at runtime via the option
294 $     -pf_type my_function
295 
296    Level: advanced
297 
298    Note:
299    `PFRegister()` may be called multiple times to add several user-defined functions
300 
301 .seealso: `PF`, `PFRegisterAll()`, `PFRegisterDestroy()`, `PFRegister()`
302 @*/
303 PetscErrorCode PFRegister(const char sname[], PetscErrorCode (*function)(PF, void *))
304 {
305   PetscFunctionBegin;
306   PetscCall(PFInitializePackage());
307   PetscCall(PetscFunctionListAdd(&PFList, sname, function));
308   PetscFunctionReturn(PETSC_SUCCESS);
309 }
310 
311 /*@C
312    PFGetType - Gets the `PFType` name (as a string) from the `PF`
313    context.
314 
315    Not Collective
316 
317    Input Parameter:
318 .  pf - the function context
319 
320    Output Parameter:
321 .  type - name of function
322 
323    Level: intermediate
324 
325 .seealso: `PF`, `PFSetType()`
326 @*/
327 PetscErrorCode PFGetType(PF pf, PFType *type)
328 {
329   PetscFunctionBegin;
330   PetscValidHeaderSpecific(pf, PF_CLASSID, 1);
331   PetscValidPointer(type, 2);
332   *type = ((PetscObject)pf)->type_name;
333   PetscFunctionReturn(PETSC_SUCCESS);
334 }
335 
336 /*@C
337    PFSetType - Builds `PF` for a particular function
338 
339    Collective
340 
341    Input Parameters:
342 +  pf - the function context.
343 .  type - a known method
344 -  ctx - optional type dependent context
345 
346    Options Database Key:
347 .  -pf_type <type> - Sets PF type
348 
349   Level: intermediate
350 
351   Note:
352   See "petsc/include/petscpf.h" for available methods (for instance, `PFCONSTANT`)
353 
354 .seealso: `PF`, `PFSet()`, `PFRegister()`, `PFCreate()`, `DMDACreatePF()`
355 @*/
356 PetscErrorCode PFSetType(PF pf, PFType type, void *ctx)
357 {
358   PetscBool match;
359   PetscErrorCode (*r)(PF, void *);
360 
361   PetscFunctionBegin;
362   PetscValidHeaderSpecific(pf, PF_CLASSID, 1);
363   PetscValidCharPointer(type, 2);
364 
365   PetscCall(PetscObjectTypeCompare((PetscObject)pf, type, &match));
366   if (match) PetscFunctionReturn(PETSC_SUCCESS);
367 
368   PetscTryTypeMethod(pf, destroy);
369   pf->data = NULL;
370 
371   /* Determine the PFCreateXXX routine for a particular function */
372   PetscCall(PetscFunctionListFind(PFList, type, &r));
373   PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested PF type %s", type);
374   pf->ops->destroy  = NULL;
375   pf->ops->view     = NULL;
376   pf->ops->apply    = NULL;
377   pf->ops->applyvec = NULL;
378 
379   /* Call the PFCreateXXX routine for this particular function */
380   PetscCall((*r)(pf, ctx));
381 
382   PetscCall(PetscObjectChangeTypeName((PetscObject)pf, type));
383   PetscFunctionReturn(PETSC_SUCCESS);
384 }
385 
386 /*@
387    PFSetFromOptions - Sets `PF` options from the options database.
388 
389    Collective
390 
391    Input Parameters:
392 .  pf - the mathematical function context
393 
394    Level: intermediate
395 
396    Notes:
397    To see all options, run your program with the -help option
398    or consult the users manual.
399 
400 .seealso: `PF`
401 @*/
402 PetscErrorCode PFSetFromOptions(PF pf)
403 {
404   char      type[256];
405   PetscBool flg;
406 
407   PetscFunctionBegin;
408   PetscValidHeaderSpecific(pf, PF_CLASSID, 1);
409 
410   PetscObjectOptionsBegin((PetscObject)pf);
411   PetscCall(PetscOptionsFList("-pf_type", "Type of function", "PFSetType", PFList, NULL, type, 256, &flg));
412   if (flg) PetscCall(PFSetType(pf, type, NULL));
413   PetscTryTypeMethod(pf, setfromoptions, PetscOptionsObject);
414 
415   /* process any options handlers added with PetscObjectAddOptionsHandler() */
416   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)pf, PetscOptionsObject));
417   PetscOptionsEnd();
418   PetscFunctionReturn(PETSC_SUCCESS);
419 }
420 
421 static PetscBool PFPackageInitialized = PETSC_FALSE;
422 /*@C
423   PFFinalizePackage - This function destroys everything in the PETSc `PF` package. It is
424   called from `PetscFinalize()`.
425 
426   Level: developer
427 
428 .seealso: `PF`, `PetscFinalize()`
429 @*/
430 PetscErrorCode PFFinalizePackage(void)
431 {
432   PetscFunctionBegin;
433   PetscCall(PetscFunctionListDestroy(&PFList));
434   PFPackageInitialized = PETSC_FALSE;
435   PFRegisterAllCalled  = PETSC_FALSE;
436   PetscFunctionReturn(PETSC_SUCCESS);
437 }
438 
439 /*@C
440   PFInitializePackage - This function initializes everything in the `PF` package. It is called
441   from PetscDLLibraryRegister_petscvec() when using dynamic libraries, and on the first call to `PFCreate()`
442   when using shared or static libraries.
443 
444   Level: developer
445 
446 .seealso: `PF`, `PetscInitialize()`
447 @*/
448 PetscErrorCode PFInitializePackage(void)
449 {
450   char      logList[256];
451   PetscBool opt, pkg;
452 
453   PetscFunctionBegin;
454   if (PFPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS);
455   PFPackageInitialized = PETSC_TRUE;
456   /* Register Classes */
457   PetscCall(PetscClassIdRegister("PointFunction", &PF_CLASSID));
458   /* Register Constructors */
459   PetscCall(PFRegisterAll());
460   /* Process Info */
461   {
462     PetscClassId classids[1];
463 
464     classids[0] = PF_CLASSID;
465     PetscCall(PetscInfoProcessClass("pf", 1, classids));
466   }
467   /* Process summary exclusions */
468   PetscCall(PetscOptionsGetString(NULL, NULL, "-log_exclude", logList, sizeof(logList), &opt));
469   if (opt) {
470     PetscCall(PetscStrInList("pf", logList, ',', &pkg));
471     if (pkg) PetscCall(PetscLogEventExcludeClass(PF_CLASSID));
472   }
473   /* Register package finalizer */
474   PetscCall(PetscRegisterFinalize(PFFinalizePackage));
475   PetscFunctionReturn(PETSC_SUCCESS);
476 }
477