xref: /petsc/src/dm/interface/dmget.c (revision f1580f4e3ce5d5b2393648fd039d0d41b440385d)
1 #include <petsc/private/dmimpl.h> /*I "petscdm.h" I*/
2 
3 /*@
4    DMGetLocalVector - Gets a PETSc vector that may be used with the DM local routines. This vector has spaces for the ghost values.
5 
6    Not Collective
7 
8    Input Parameter:
9 .  dm - the dm
10 
11    Output Parameter:
12 .  g - the local vector
13 
14    Level: beginner
15 
16    Note:
17    The vector values are NOT initialized and may have garbage in them, so you may need
18    to zero them.
19 
20    The output parameter, g, is a regular PETSc vector that should be returned with
21    DMRestoreLocalVector() DO NOT call VecDestroy() on it.
22 
23    This is intended to be used for vectors you need for a short time, like within a single function call.
24    For vectors that you intend to keep around (for example in a C struct) or pass around large parts of your
25    code you should use DMCreateLocalVector().
26 
27    VecStride*() operations can be useful when using DM with dof > 1
28 
29 .seealso: `DMCreateGlobalVector()`, `VecDuplicate()`, `VecDuplicateVecs()`,
30           `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMGlobalToLocalBegin()`,
31           `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMCreateLocalVector()`, `DMRestoreLocalVector()`,
32           `VecStrideMax()`, `VecStrideMin()`, `VecStrideNorm()`
33 @*/
34 PetscErrorCode DMGetLocalVector(DM dm, Vec *g) {
35   PetscFunctionBegin;
36   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37   PetscValidPointer(g, 2);
38   for (PetscInt i = 0; i < DM_MAX_WORK_VECTORS; i++) {
39     if (dm->localin[i]) {
40       DM vdm;
41 
42       *g             = dm->localin[i];
43       dm->localin[i] = NULL;
44 
45       PetscCall(VecGetDM(*g, &vdm));
46       PetscCheck(!vdm, PetscObjectComm((PetscObject)vdm), PETSC_ERR_LIB, "Invalid vector");
47       PetscCall(VecSetDM(*g, dm));
48       goto alldone;
49     }
50   }
51   PetscCall(DMCreateLocalVector(dm, g));
52 
53 alldone:
54   for (PetscInt i = 0; i < DM_MAX_WORK_VECTORS; i++) {
55     if (!dm->localout[i]) {
56       dm->localout[i] = *g;
57       break;
58     }
59   }
60   PetscFunctionReturn(0);
61 }
62 
63 /*@
64    DMRestoreLocalVector - Returns a PETSc vector that was
65      obtained from DMGetLocalVector(). Do not use with vector obtained via
66      DMCreateLocalVector().
67 
68    Not Collective
69 
70    Input Parameters:
71 +  dm - the dm
72 -  g - the local vector
73 
74    Level: beginner
75 
76 .seealso: `DMCreateGlobalVector()`, `VecDuplicate()`, `VecDuplicateVecs()`,
77           `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMGlobalToLocalBegin()`,
78           `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMCreateLocalVector()`, `DMGetLocalVector()`
79 @*/
80 PetscErrorCode DMRestoreLocalVector(DM dm, Vec *g) {
81   PetscInt i, j;
82 
83   PetscFunctionBegin;
84   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
85   PetscValidPointer(g, 2);
86   for (j = 0; j < DM_MAX_WORK_VECTORS; j++) {
87     if (*g == dm->localout[j]) {
88       DM vdm;
89 
90       PetscCall(VecGetDM(*g, &vdm));
91       PetscCheck(vdm == dm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Invalid vector");
92       PetscCall(VecSetDM(*g, NULL));
93       dm->localout[j] = NULL;
94       for (i = 0; i < DM_MAX_WORK_VECTORS; i++) {
95         if (!dm->localin[i]) {
96           dm->localin[i] = *g;
97           goto alldone;
98         }
99       }
100     }
101   }
102   PetscCall(VecDestroy(g));
103 alldone:
104   *g = NULL;
105   PetscFunctionReturn(0);
106 }
107 
108 /*@
109    DMGetGlobalVector - Gets a PETSc vector that may be used with the DM global routines.
110 
111    Collective on dm
112 
113    Input Parameter:
114 .  dm - the dm
115 
116    Output Parameter:
117 .  g - the global vector
118 
119    Level: beginner
120 
121    Note:
122    The vector values are NOT initialized and may have garbage in them, so you may need
123    to zero them.
124 
125    The output parameter, g, is a regular PETSc vector that should be returned with
126    DMRestoreGlobalVector() DO NOT call VecDestroy() on it.
127 
128    This is intended to be used for vectors you need for a short time, like within a single function call.
129    For vectors that you intend to keep around (for example in a C struct) or pass around large parts of your
130    code you should use DMCreateGlobalVector().
131 
132    VecStride*() operations can be useful when using DM with dof > 1
133 
134 .seealso: `DMCreateGlobalVector()`, `VecDuplicate()`, `VecDuplicateVecs()`,
135           `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMGlobalToLocalBegin()`,
136           `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMCreateLocalVector()`, `DMRestoreLocalVector()`
137           `VecStrideMax()`, `VecStrideMin()`, `VecStrideNorm()`
138 @*/
139 PetscErrorCode DMGetGlobalVector(DM dm, Vec *g) {
140   PetscInt i;
141 
142   PetscFunctionBegin;
143   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
144   PetscValidPointer(g, 2);
145   for (i = 0; i < DM_MAX_WORK_VECTORS; i++) {
146     if (dm->globalin[i]) {
147       DM vdm;
148 
149       *g              = dm->globalin[i];
150       dm->globalin[i] = NULL;
151 
152       PetscCall(VecGetDM(*g, &vdm));
153       PetscCheck(!vdm, PetscObjectComm((PetscObject)vdm), PETSC_ERR_LIB, "Invalid vector");
154       PetscCall(VecSetDM(*g, dm));
155       goto alldone;
156     }
157   }
158   PetscCall(DMCreateGlobalVector(dm, g));
159 
160 alldone:
161   for (i = 0; i < DM_MAX_WORK_VECTORS; i++) {
162     if (!dm->globalout[i]) {
163       dm->globalout[i] = *g;
164       break;
165     }
166   }
167   PetscFunctionReturn(0);
168 }
169 
170 /*@
171    DMClearGlobalVectors - Destroys all the global vectors that have been stashed in this DM
172 
173    Collective on dm
174 
175    Input Parameter:
176 .  dm - the dm
177 
178    Level: developer
179 
180 .seealso: `DMCreateGlobalVector()`, `VecDuplicate()`, `VecDuplicateVecs()`,
181           `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMGlobalToLocalBegin()`,
182           `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMCreateLocalVector()`, `DMRestoreLocalVector()`
183           `VecStrideMax()`, `VecStrideMin()`, `VecStrideNorm()`
184 @*/
185 PetscErrorCode DMClearGlobalVectors(DM dm) {
186   PetscInt i;
187 
188   PetscFunctionBegin;
189   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
190   for (i = 0; i < DM_MAX_WORK_VECTORS; i++) {
191     Vec g;
192 
193     PetscCheck(!dm->globalout[i], PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Clearing DM of global vectors that has a global vector obtained with DMGetGlobalVector()");
194     g               = dm->globalin[i];
195     dm->globalin[i] = NULL;
196     if (g) {
197       DM vdm;
198 
199       PetscCall(VecGetDM(g, &vdm));
200       PetscCheck(!vdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Clearing global vector that has a DM attached");
201     }
202     PetscCall(VecDestroy(&g));
203   }
204   PetscFunctionReturn(0);
205 }
206 
207 /*@
208    DMClearLocalVectors - Destroys all the local vectors that have been stashed in this DM
209 
210    Collective on dm
211 
212    Input Parameter:
213 .  dm - the dm
214 
215    Level: developer
216 
217 .seealso: `DMCreateLocalVector()`, `VecDuplicate()`, `VecDuplicateVecs()`,
218           `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMLocalToLocalBegin()`,
219           `DMLocalToLocalEnd()`, `DMLocalToLocalBegin()`, `DMCreateLocalVector()`, `DMRestoreLocalVector()`
220           `VecStrideMax()`, `VecStrideMin()`, `VecStrideNorm()`
221 @*/
222 PetscErrorCode DMClearLocalVectors(DM dm) {
223   PetscInt i;
224 
225   PetscFunctionBegin;
226   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
227   for (i = 0; i < DM_MAX_WORK_VECTORS; i++) {
228     Vec g;
229 
230     PetscCheck(!dm->localout[i], PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Clearing DM of local vectors that has a local vector obtained with DMGetLocalVector()");
231     g              = dm->localin[i];
232     dm->localin[i] = NULL;
233     if (g) {
234       DM vdm;
235 
236       PetscCall(VecGetDM(g, &vdm));
237       PetscCheck(!vdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Clearing local vector that has a DM attached");
238     }
239     PetscCall(VecDestroy(&g));
240   }
241   PetscFunctionReturn(0);
242 }
243 
244 /*@
245    DMRestoreGlobalVector - Returns a PETSc vector that
246      obtained from DMGetGlobalVector(). Do not use with vector obtained via
247      DMCreateGlobalVector().
248 
249    Not Collective
250 
251    Input Parameters:
252 +  dm - the dm
253 -  g - the global vector
254 
255    Level: beginner
256 
257 .seealso: `DMCreateGlobalVector()`, `VecDuplicate()`, `VecDuplicateVecs()`,
258           `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMGlobalToGlobalBegin()`,
259           `DMGlobalToGlobalEnd()`, `DMGlobalToGlobal()`, `DMCreateLocalVector()`, `DMGetGlobalVector()`
260 @*/
261 PetscErrorCode DMRestoreGlobalVector(DM dm, Vec *g) {
262   PetscInt i, j;
263 
264   PetscFunctionBegin;
265   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
266   PetscValidPointer(g, 2);
267   PetscCall(VecSetErrorIfLocked(*g, 2));
268   for (j = 0; j < DM_MAX_WORK_VECTORS; j++) {
269     if (*g == dm->globalout[j]) {
270       DM vdm;
271 
272       PetscCall(VecGetDM(*g, &vdm));
273       PetscCheck(vdm == dm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Invalid vector");
274       PetscCall(VecSetDM(*g, NULL));
275       dm->globalout[j] = NULL;
276       for (i = 0; i < DM_MAX_WORK_VECTORS; i++) {
277         if (!dm->globalin[i]) {
278           dm->globalin[i] = *g;
279           goto alldone;
280         }
281       }
282     }
283   }
284   PetscCall(VecDestroy(g));
285 alldone:
286   *g = NULL;
287   PetscFunctionReturn(0);
288 }
289 
290 /*@C
291    DMHasNamedGlobalVector - check for a named, persistent global vector
292 
293    Not Collective
294 
295    Input Parameters:
296 +  dm - DM to hold named vectors
297 -  name - unique name for Vec
298 
299    Output Parameter:
300 .  exists - true if the vector was previously created
301 
302    Level: developer
303 
304    Note: If a Vec with the given name does not exist, it is created.
305 
306 .seealso: `DMGetNamedGlobalVector()`, `DMRestoreNamedLocalVector()`
307 @*/
308 PetscErrorCode DMHasNamedGlobalVector(DM dm, const char *name, PetscBool *exists) {
309   DMNamedVecLink link;
310 
311   PetscFunctionBegin;
312   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
313   PetscValidCharPointer(name, 2);
314   PetscValidBoolPointer(exists, 3);
315   *exists = PETSC_FALSE;
316   for (link = dm->namedglobal; link; link = link->next) {
317     PetscBool match;
318     PetscCall(PetscStrcmp(name, link->name, &match));
319     if (match) {
320       *exists = PETSC_TRUE;
321       break;
322     }
323   }
324   PetscFunctionReturn(0);
325 }
326 
327 /*@C
328    DMGetNamedGlobalVector - get access to a named, persistent global vector
329 
330    Collective on dm
331 
332    Input Parameters:
333 +  dm - DM to hold named vectors
334 -  name - unique name for Vec
335 
336    Output Parameter:
337 .  X - named Vec
338 
339    Level: developer
340 
341    Note: If a Vec with the given name does not exist, it is created.
342 
343 .seealso: `DMRestoreNamedGlobalVector()`
344 @*/
345 PetscErrorCode DMGetNamedGlobalVector(DM dm, const char *name, Vec *X) {
346   DMNamedVecLink link;
347 
348   PetscFunctionBegin;
349   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
350   PetscValidCharPointer(name, 2);
351   PetscValidPointer(X, 3);
352   for (link = dm->namedglobal; link; link = link->next) {
353     PetscBool match;
354 
355     PetscCall(PetscStrcmp(name, link->name, &match));
356     if (match) {
357       DM vdm;
358 
359       PetscCheck(link->status == DMVEC_STATUS_IN, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Vec name '%s' already checked out", name);
360       PetscCall(VecGetDM(link->X, &vdm));
361       PetscCheck(!vdm, PetscObjectComm((PetscObject)vdm), PETSC_ERR_LIB, "Invalid vector");
362       PetscCall(VecSetDM(link->X, dm));
363       goto found;
364     }
365   }
366 
367   /* Create the Vec */
368   PetscCall(PetscNew(&link));
369   PetscCall(PetscStrallocpy(name, &link->name));
370   PetscCall(DMCreateGlobalVector(dm, &link->X));
371   link->next      = dm->namedglobal;
372   dm->namedglobal = link;
373 
374 found:
375   *X           = link->X;
376   link->status = DMVEC_STATUS_OUT;
377   PetscFunctionReturn(0);
378 }
379 
380 /*@C
381    DMRestoreNamedGlobalVector - restore access to a named, persistent global vector
382 
383    Collective on dm
384 
385    Input Parameters:
386 +  dm - DM on which the vector was gotten
387 .  name - name under which the vector was gotten
388 -  X - Vec to restore
389 
390    Level: developer
391 
392 .seealso: `DMGetNamedGlobalVector()`
393 @*/
394 PetscErrorCode DMRestoreNamedGlobalVector(DM dm, const char *name, Vec *X) {
395   DMNamedVecLink link;
396 
397   PetscFunctionBegin;
398   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
399   PetscValidCharPointer(name, 2);
400   PetscValidPointer(X, 3);
401   PetscValidHeaderSpecific(*X, VEC_CLASSID, 3);
402   for (link = dm->namedglobal; link; link = link->next) {
403     PetscBool match;
404 
405     PetscCall(PetscStrcmp(name, link->name, &match));
406     if (match) {
407       DM vdm;
408 
409       PetscCall(VecGetDM(*X, &vdm));
410       PetscCheck(link->status == DMVEC_STATUS_OUT, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Vec name '%s' was not checked out", name);
411       PetscCheck(link->X == *X, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP, "Attempt to restore Vec name '%s', but Vec does not match the cache", name);
412       PetscCheck(vdm == dm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Invalid vector");
413 
414       link->status = DMVEC_STATUS_IN;
415       PetscCall(VecSetDM(link->X, NULL));
416       *X = NULL;
417       PetscFunctionReturn(0);
418     }
419   }
420   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP, "Could not find Vec name '%s' to restore", name);
421 }
422 
423 /*@C
424    DMHasNamedLocalVector - check for a named, persistent local vector
425 
426    Not Collective
427 
428    Input Parameters:
429 +  dm - DM to hold named vectors
430 -  name - unique name for Vec
431 
432    Output Parameter:
433 .  exists - true if the vector was previously created
434 
435    Level: developer
436 
437    Note: If a Vec with the given name does not exist, it is created.
438 
439 .seealso: `DMGetNamedGlobalVector()`, `DMRestoreNamedLocalVector()`
440 @*/
441 PetscErrorCode DMHasNamedLocalVector(DM dm, const char *name, PetscBool *exists) {
442   DMNamedVecLink link;
443 
444   PetscFunctionBegin;
445   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
446   PetscValidCharPointer(name, 2);
447   PetscValidBoolPointer(exists, 3);
448   *exists = PETSC_FALSE;
449   for (link = dm->namedlocal; link; link = link->next) {
450     PetscBool match;
451     PetscCall(PetscStrcmp(name, link->name, &match));
452     if (match) {
453       *exists = PETSC_TRUE;
454       break;
455     }
456   }
457   PetscFunctionReturn(0);
458 }
459 
460 /*@C
461    DMGetNamedLocalVector - get access to a named, persistent local vector
462 
463    Not Collective
464 
465    Input Parameters:
466 +  dm - DM to hold named vectors
467 -  name - unique name for Vec
468 
469    Output Parameter:
470 .  X - named Vec
471 
472    Level: developer
473 
474    Note: If a Vec with the given name does not exist, it is created.
475 
476 .seealso: `DMGetNamedGlobalVector()`, `DMRestoreNamedLocalVector()`
477 @*/
478 PetscErrorCode DMGetNamedLocalVector(DM dm, const char *name, Vec *X) {
479   DMNamedVecLink link;
480 
481   PetscFunctionBegin;
482   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
483   PetscValidCharPointer(name, 2);
484   PetscValidPointer(X, 3);
485   for (link = dm->namedlocal; link; link = link->next) {
486     PetscBool match;
487 
488     PetscCall(PetscStrcmp(name, link->name, &match));
489     if (match) {
490       DM vdm;
491 
492       PetscCheck(link->status == DMVEC_STATUS_IN, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Vec name '%s' already checked out", name);
493       PetscCall(VecGetDM(link->X, &vdm));
494       PetscCheck(!vdm, PetscObjectComm((PetscObject)vdm), PETSC_ERR_LIB, "Invalid vector");
495       PetscCall(VecSetDM(link->X, dm));
496       goto found;
497     }
498   }
499 
500   /* Create the Vec */
501   PetscCall(PetscNew(&link));
502   PetscCall(PetscStrallocpy(name, &link->name));
503   PetscCall(DMCreateLocalVector(dm, &link->X));
504   link->next     = dm->namedlocal;
505   dm->namedlocal = link;
506 
507 found:
508   *X           = link->X;
509   link->status = DMVEC_STATUS_OUT;
510   PetscFunctionReturn(0);
511 }
512 
513 /*@C
514    DMRestoreNamedLocalVector - restore access to a named, persistent local vector
515 
516    Not Collective
517 
518    Input Parameters:
519 +  dm - DM on which the vector was gotten
520 .  name - name under which the vector was gotten
521 -  X - Vec to restore
522 
523    Level: developer
524 
525 .seealso: `DMRestoreNamedGlobalVector()`, `DMGetNamedLocalVector()`
526 @*/
527 PetscErrorCode DMRestoreNamedLocalVector(DM dm, const char *name, Vec *X) {
528   DMNamedVecLink link;
529 
530   PetscFunctionBegin;
531   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
532   PetscValidCharPointer(name, 2);
533   PetscValidPointer(X, 3);
534   PetscValidHeaderSpecific(*X, VEC_CLASSID, 3);
535   for (link = dm->namedlocal; link; link = link->next) {
536     PetscBool match;
537 
538     PetscCall(PetscStrcmp(name, link->name, &match));
539     if (match) {
540       DM vdm;
541 
542       PetscCall(VecGetDM(*X, &vdm));
543       PetscCheck(link->status == DMVEC_STATUS_OUT, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Vec name '%s' was not checked out", name);
544       PetscCheck(link->X == *X, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP, "Attempt to restore Vec name '%s', but Vec does not match the cache", name);
545       PetscCheck(vdm == dm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Invalid vector");
546 
547       link->status = DMVEC_STATUS_IN;
548       PetscCall(VecSetDM(link->X, NULL));
549       *X = NULL;
550       PetscFunctionReturn(0);
551     }
552   }
553   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP, "Could not find Vec name '%s' to restore", name);
554 }
555