xref: /petsc/src/dm/impls/shell/dmshell.c (revision 607a6623fc3ebf1ec03868e90ff90ff3b0120740)
1 #include <petscdmshell.h>       /*I    "petscdmshell.h"  I*/
2 #include <petscmat.h>
3 #include <petsc-private/dmimpl.h>
4 
5 typedef struct  {
6   Vec        Xglobal;
7   Vec        Xlocal;
8   Mat        A;
9   VecScatter *gtol;
10   VecScatter *ltog;
11 } DM_Shell;
12 
13 #undef __FUNCT__
14 #define __FUNCT__ "DMGlobalToLocalBeginDefaultShell"
15 /*@
16    DMGlobalToLocalBeginDefaultShell - Uses the GlobalToLocal VecScatter context set by the user to begin a global to local scatter
17    Collective
18 
19    Input Arguments:
20 +  dm - shell DM
21 .  g - global vector
22 .  mode - InsertMode
23 -  l - local vector
24 
25    Level: advanced
26 
27    Note:  This is not normally called directly by user code, generally user code calls DMGlobalToLocalBegin() and DMGlobalToLocalEnd(). If the user provides their own custom routines to DMShellSetLocalToGlobal() then those routines might have reason to call this function.
28 
29 .seealso: DMGlobalToLocalEndDefaultShell()
30 @*/
31 PetscErrorCode DMGlobalToLocalBeginDefaultShell(DM dm,Vec g,InsertMode mode,Vec l)
32 {
33   PetscErrorCode ierr;
34   DM_Shell       *shell = (DM_Shell*)dm->data;
35 
36   PetscFunctionBegin;
37   if (!shell->gtol) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetGlobalToLocalVecScatter()");
38   ierr = VecScatterBegin(*(shell->gtol),g,l,mode,SCATTER_FORWARD);CHKERRQ(ierr);
39   PetscFunctionReturn(0);
40 }
41 
42 #undef __FUNCT__
43 #define __FUNCT__ "DMGlobalToLocalEndDefaultShell"
44 /*@
45    DMGlobalToLocalEndDefaultShell - Uses the GlobalToLocal VecScatter context set by the user to end a global to local scatter
46    Collective
47 
48    Input Arguments:
49 +  dm - shell DM
50 .  g - global vector
51 .  mode - InsertMode
52 -  l - local vector
53 
54    Level: advanced
55 
56 .seealso: DMGlobalToLocalBeginDefaultShell()
57 @*/
58 PetscErrorCode DMGlobalToLocalEndDefaultShell(DM dm,Vec g,InsertMode mode,Vec l)
59 {
60   PetscErrorCode ierr;
61   DM_Shell       *shell = (DM_Shell*)dm->data;
62 
63   PetscFunctionBegin;
64    if (!shell->gtol) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetGlobalToLocalVecScatter()");
65   ierr = VecScatterEnd(*(shell->gtol),g,l,mode,SCATTER_FORWARD);CHKERRQ(ierr);
66   PetscFunctionReturn(0);
67 }
68 
69 #undef __FUNCT__
70 #define __FUNCT__ "DMCreateMatrix_Shell"
71 static PetscErrorCode DMCreateMatrix_Shell(DM dm,MatType mtype,Mat *J)
72 {
73   PetscErrorCode ierr;
74   DM_Shell       *shell = (DM_Shell*)dm->data;
75   Mat            A;
76 
77   PetscFunctionBegin;
78   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
79   PetscValidPointer(J,3);
80   if (!shell->A) {
81     if (shell->Xglobal) {
82       PetscInt m,M;
83       ierr = PetscInfo(dm,"Naively creating matrix using global vector distribution without preallocation");CHKERRQ(ierr);
84       ierr = VecGetSize(shell->Xglobal,&M);CHKERRQ(ierr);
85       ierr = VecGetLocalSize(shell->Xglobal,&m);CHKERRQ(ierr);
86       ierr = MatCreate(PetscObjectComm((PetscObject)dm),&shell->A);CHKERRQ(ierr);
87       ierr = MatSetSizes(shell->A,m,m,M,M);CHKERRQ(ierr);
88       if (mtype) {ierr = MatSetType(shell->A,mtype);CHKERRQ(ierr);}
89       ierr = MatSetUp(shell->A);CHKERRQ(ierr);
90     } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMShellSetMatrix(), DMShellSetCreateMatrix(), or provide a vector");
91   }
92   A = shell->A;
93   /* the check below is tacky and incomplete */
94   if (mtype) {
95     PetscBool flg,aij,seqaij,mpiaij;
96     ierr = PetscObjectTypeCompare((PetscObject)A,mtype,&flg);CHKERRQ(ierr);
97     ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&seqaij);CHKERRQ(ierr);
98     ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&mpiaij);CHKERRQ(ierr);
99     ierr = PetscStrcmp(mtype,MATAIJ,&aij);CHKERRQ(ierr);
100     if (!flg) {
101       if (!(aij & (seqaij || mpiaij))) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_NOTSAMETYPE,"Requested matrix of type %s, but only %s available",mtype,((PetscObject)A)->type_name);
102     }
103   }
104   if (((PetscObject)A)->refct < 2) { /* We have an exclusive reference so we can give it out */
105     ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr);
106     ierr = MatZeroEntries(A);CHKERRQ(ierr);
107     *J   = A;
108   } else {                      /* Need to create a copy, could use MAT_SHARE_NONZERO_PATTERN in most cases */
109     ierr = MatDuplicate(A,MAT_DO_NOT_COPY_VALUES,J);CHKERRQ(ierr);
110     ierr = MatZeroEntries(*J);CHKERRQ(ierr);
111   }
112   PetscFunctionReturn(0);
113 }
114 
115 #undef __FUNCT__
116 #define __FUNCT__ "DMCreateGlobalVector_Shell"
117 PetscErrorCode DMCreateGlobalVector_Shell(DM dm,Vec *gvec)
118 {
119   PetscErrorCode ierr;
120   DM_Shell       *shell = (DM_Shell*)dm->data;
121   Vec            X;
122 
123   PetscFunctionBegin;
124   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
125   PetscValidPointer(gvec,2);
126   *gvec = 0;
127   X     = shell->Xglobal;
128   if (!X) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMShellSetGlobalVector() or DMShellSetCreateGlobalVector()");
129   if (((PetscObject)X)->refct < 2) { /* We have an exclusive reference so we can give it out */
130     ierr  = PetscObjectReference((PetscObject)X);CHKERRQ(ierr);
131     ierr  = VecZeroEntries(X);CHKERRQ(ierr);
132     *gvec = X;
133   } else {                      /* Need to create a copy, could use MAT_SHARE_NONZERO_PATTERN in most cases */
134     ierr = VecDuplicate(X,gvec);CHKERRQ(ierr);
135     ierr = VecZeroEntries(*gvec);CHKERRQ(ierr);
136   }
137   ierr = VecSetDM(*gvec,dm);CHKERRQ(ierr);
138   PetscFunctionReturn(0);
139 }
140 
141 #undef __FUNCT__
142 #define __FUNCT__ "DMCreateLocalVector_Shell"
143 PetscErrorCode DMCreateLocalVector_Shell(DM dm,Vec *gvec)
144 {
145   PetscErrorCode ierr;
146   DM_Shell       *shell = (DM_Shell*)dm->data;
147   Vec            X;
148 
149   PetscFunctionBegin;
150   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
151   PetscValidPointer(gvec,2);
152   *gvec = 0;
153   X     = shell->Xlocal;
154   if (!X) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMShellSetLocalVector() or DMShellSetCreateLocalVector()");
155   if (((PetscObject)X)->refct < 2) { /* We have an exclusive reference so we can give it out */
156     ierr  = PetscObjectReference((PetscObject)X);CHKERRQ(ierr);
157     ierr  = VecZeroEntries(X);CHKERRQ(ierr);
158     *gvec = X;
159   } else {                      /* Need to create a copy, could use MAT_SHARE_NONZERO_PATTERN in most cases */
160     ierr = VecDuplicate(X,gvec);CHKERRQ(ierr);
161     ierr = VecZeroEntries(*gvec);CHKERRQ(ierr);
162   }
163   ierr = VecSetDM(*gvec,dm);CHKERRQ(ierr);
164   PetscFunctionReturn(0);
165 }
166 
167 #undef __FUNCT__
168 #define __FUNCT__ "DMShellSetMatrix"
169 /*@
170    DMShellSetMatrix - sets a template matrix associated with the DMShell
171 
172    Collective
173 
174    Input Arguments:
175 +  dm - shell DM
176 -  J - template matrix
177 
178    Level: advanced
179 
180 .seealso: DMCreateMatrix(), DMShellSetCreateMatrix()
181 @*/
182 PetscErrorCode DMShellSetMatrix(DM dm,Mat J)
183 {
184   DM_Shell       *shell = (DM_Shell*)dm->data;
185   PetscErrorCode ierr;
186   PetscBool      isshell;
187 
188   PetscFunctionBegin;
189   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
190   PetscValidHeaderSpecific(J,MAT_CLASSID,2);
191   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
192   if (!isshell) PetscFunctionReturn(0);
193   ierr     = PetscObjectReference((PetscObject)J);CHKERRQ(ierr);
194   ierr     = MatDestroy(&shell->A);CHKERRQ(ierr);
195   shell->A = J;
196   PetscFunctionReturn(0);
197 }
198 
199 #undef __FUNCT__
200 #define __FUNCT__ "DMShellSetCreateMatrix"
201 /*@C
202    DMShellSetCreateMatrix - sets the routine to create a matrix associated with the shell DM
203 
204    Logically Collective on DM
205 
206    Input Arguments:
207 +  dm - the shell DM
208 -  func - the function to create a matrix
209 
210    Level: advanced
211 
212 .seealso: DMCreateMatrix(), DMShellSetMatrix()
213 @*/
214 PetscErrorCode DMShellSetCreateMatrix(DM dm,PetscErrorCode (*func)(DM,MatType,Mat*))
215 {
216 
217   PetscFunctionBegin;
218   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
219   dm->ops->creatematrix = func;
220   PetscFunctionReturn(0);
221 }
222 
223 #undef __FUNCT__
224 #define __FUNCT__ "DMShellSetGlobalVector"
225 /*@
226    DMShellSetGlobalVector - sets a template global vector associated with the DMShell
227 
228    Logically Collective on DM
229 
230    Input Arguments:
231 +  dm - shell DM
232 -  X - template vector
233 
234    Level: advanced
235 
236 .seealso: DMCreateGlobalVector(), DMShellSetMatrix(), DMShellSetCreateGlobalVector()
237 @*/
238 PetscErrorCode DMShellSetGlobalVector(DM dm,Vec X)
239 {
240   DM_Shell       *shell = (DM_Shell*)dm->data;
241   PetscErrorCode ierr;
242   PetscBool      isshell;
243 
244   PetscFunctionBegin;
245   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
246   PetscValidHeaderSpecific(X,VEC_CLASSID,2);
247   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
248   if (!isshell) PetscFunctionReturn(0);
249   ierr           = PetscObjectReference((PetscObject)X);CHKERRQ(ierr);
250   ierr           = VecDestroy(&shell->Xglobal);CHKERRQ(ierr);
251   shell->Xglobal = X;
252   PetscFunctionReturn(0);
253 }
254 
255 #undef __FUNCT__
256 #define __FUNCT__ "DMShellSetCreateGlobalVector"
257 /*@C
258    DMShellSetCreateGlobalVector - sets the routine to create a global vector associated with the shell DM
259 
260    Logically Collective
261 
262    Input Arguments:
263 +  dm - the shell DM
264 -  func - the creation routine
265 
266    Level: advanced
267 
268 .seealso: DMShellSetGlobalVector(), DMShellSetCreateMatrix()
269 @*/
270 PetscErrorCode DMShellSetCreateGlobalVector(DM dm,PetscErrorCode (*func)(DM,Vec*))
271 {
272 
273   PetscFunctionBegin;
274   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
275   dm->ops->createglobalvector = func;
276   PetscFunctionReturn(0);
277 }
278 
279 #undef __FUNCT__
280 #define __FUNCT__ "DMShellSetLocalVector"
281 /*@
282    DMShellSetLocalVector - sets a template local vector associated with the DMShell
283 
284    Logically Collective on DM
285 
286    Input Arguments:
287 +  dm - shell DM
288 -  X - template vector
289 
290    Level: advanced
291 
292 .seealso: DMCreateLocalVector(), DMShellSetMatrix(), DMShellSetCreateLocalVector()
293 @*/
294 PetscErrorCode DMShellSetLocalVector(DM dm,Vec X)
295 {
296   DM_Shell       *shell = (DM_Shell*)dm->data;
297   PetscErrorCode ierr;
298   PetscBool      isshell;
299 
300   PetscFunctionBegin;
301   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
302   PetscValidHeaderSpecific(X,VEC_CLASSID,2);
303   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
304   if (!isshell) PetscFunctionReturn(0);
305   ierr = PetscObjectReference((PetscObject)X);CHKERRQ(ierr);
306   ierr = VecDestroy(&shell->Xlocal);CHKERRQ(ierr);
307   shell->Xlocal = X;
308   PetscFunctionReturn(0);
309 }
310 
311 #undef __FUNCT__
312 #define __FUNCT__ "DMShellSetCreateLocalVector"
313 /*@C
314    DMShellSetCreateLocalVector - sets the routine to create a local vector associated with the shell DM
315 
316    Logically Collective
317 
318    Input Arguments:
319 +  dm - the shell DM
320 -  func - the creation routine
321 
322    Level: advanced
323 
324 .seealso: DMShellSetLocalVector(), DMShellSetCreateMatrix()
325 @*/
326 PetscErrorCode DMShellSetCreateLocalVector(DM dm,PetscErrorCode (*func)(DM,Vec*))
327 {
328 
329   PetscFunctionBegin;
330   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
331   dm->ops->createlocalvector = func;
332   PetscFunctionReturn(0);
333 }
334 
335 #undef __FUNCT__
336 #define __FUNCT__ "DMShellSetGlobalToLocal"
337 /*@C
338    DMShellSetGlobalToLocal - Sets the routines used to perform a global to local scatter
339 
340    Logically Collective on DM
341 
342    Input Arguments
343 +  dm - the shell DM
344 .  begin - the routine that begins the global to local scatter
345 -  end - the routine that ends the global to local scatter
346 
347    Notes: If these functions are not provided but DMShellSetGlobalToLocalVecScatter() is called then
348    DMGlobalToLocalBeginDefaultShell() are used to to perform the transfers DMGlobalToLocalEndDefaultShell()
349 
350    Level: advanced
351 
352 .seealso: DMShellSetLocalToGlobal(), DMGlobalToLocalBeginDefaultShell(), DMGlobalToLocalEndDefaultShell()
353 @*/
354 PetscErrorCode DMShellSetGlobalToLocal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec)) {
355   PetscFunctionBegin;
356   dm->ops->globaltolocalbegin = begin;
357   dm->ops->globaltolocalend = end;
358   PetscFunctionReturn(0);
359 }
360 
361 #undef __FUNCT__
362 #define __FUNCT__ "DMShellSetLocalToGlobal"
363 /*@C
364    DMShellSetLocalToGlobal - Sets the routines used to perform a local to global scatter
365 
366    Logically Collective on DM
367 
368    Input Arguments
369 +  dm - the shell DM
370 .  begin - the routine that begins the local to global scatter
371 -  end - the routine that ends the local to global scatter
372 
373    Level: advanced
374 
375 .seealso: DMShellSetGlobalToLocal()
376 @*/
377 PetscErrorCode DMShellSetLocalToGlobal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec)) {
378   PetscFunctionBegin;
379   dm->ops->localtoglobalbegin = begin;
380   dm->ops->localtoglobalend = end;
381   PetscFunctionReturn(0);
382 }
383 
384 #undef __FUNCT__
385 #define __FUNCT__ "DMShellSetGlobalToLocalVecScatter"
386 /*@
387    DMShellSetGlobalToLocalVecScatter - Sets a VecScatter context for global to local communication
388 
389    Logically Collective on DM
390 
391    Input Arguments
392 +  dm - the shell DM
393 -  gtol - the global to local VecScatter context
394 
395    Level: advanced
396 
397 .seealso: DMShellSetGlobalToLocal()
398 @*/
399 PetscErrorCode DMShellSetGlobalToLocalVecScatter(DM dm, VecScatter *gtol)
400 {
401   DM_Shell       *shell = (DM_Shell*)dm->data;
402 
403   PetscFunctionBegin;
404   shell->gtol = gtol;
405   PetscFunctionReturn(0);
406 }
407 
408 #undef __FUNCT__
409 #define __FUNCT__ "DMDestroy_Shell"
410 static PetscErrorCode DMDestroy_Shell(DM dm)
411 {
412   PetscErrorCode ierr;
413   DM_Shell       *shell = (DM_Shell*)dm->data;
414 
415   PetscFunctionBegin;
416   ierr = MatDestroy(&shell->A);CHKERRQ(ierr);
417   ierr = VecDestroy(&shell->Xglobal);CHKERRQ(ierr);
418   ierr = VecDestroy(&shell->Xlocal);CHKERRQ(ierr);
419   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
420   ierr = PetscFree(shell);CHKERRQ(ierr);
421   PetscFunctionReturn(0);
422 }
423 
424 #undef __FUNCT__
425 #define __FUNCT__ "DMView_Shell"
426 static PetscErrorCode DMView_Shell(DM dm,PetscViewer v)
427 {
428   PetscErrorCode ierr;
429   DM_Shell       *shell = (DM_Shell*)dm->data;
430 
431   PetscFunctionBegin;
432   ierr = VecView(shell->Xglobal,v);CHKERRQ(ierr);
433   PetscFunctionReturn(0);
434 }
435 
436 #undef __FUNCT__
437 #define __FUNCT__ "DMLoad_Shell"
438 static PetscErrorCode DMLoad_Shell(DM dm,PetscViewer v)
439 {
440   PetscErrorCode ierr;
441   DM_Shell       *shell = (DM_Shell*)dm->data;
442 
443   PetscFunctionBegin;
444   ierr = VecCreate(PetscObjectComm((PetscObject)dm),&shell->Xglobal);CHKERRQ(ierr);
445   ierr = VecLoad(shell->Xglobal,v);CHKERRQ(ierr);
446   PetscFunctionReturn(0);
447 }
448 
449 #undef __FUNCT__
450 #define __FUNCT__ "DMCreate_Shell"
451 PETSC_EXTERN PetscErrorCode DMCreate_Shell(DM dm)
452 {
453   PetscErrorCode ierr;
454   DM_Shell       *shell;
455 
456   PetscFunctionBegin;
457   ierr     = PetscNewLog(dm,DM_Shell,&shell);CHKERRQ(ierr);
458   dm->data = shell;
459 
460   ierr = PetscObjectChangeTypeName((PetscObject)dm,DMSHELL);CHKERRQ(ierr);
461 
462   dm->ops->destroy            = DMDestroy_Shell;
463   dm->ops->createglobalvector = DMCreateGlobalVector_Shell;
464   dm->ops->createlocalvector  = DMCreateLocalVector_Shell;
465   dm->ops->creatematrix       = DMCreateMatrix_Shell;
466   dm->ops->view               = DMView_Shell;
467   dm->ops->load               = DMLoad_Shell;
468   dm->ops->globaltolocalbegin = DMGlobalToLocalBeginDefaultShell;
469   dm->ops->globaltolocalend   = DMGlobalToLocalEndDefaultShell;
470   PetscFunctionReturn(0);
471 }
472 
473 #undef __FUNCT__
474 #define __FUNCT__ "DMShellCreate"
475 /*@
476     DMShellCreate - Creates a shell DM object, used to manage user-defined problem data
477 
478     Collective on MPI_Comm
479 
480     Input Parameter:
481 .   comm - the processors that will share the global vector
482 
483     Output Parameters:
484 .   shell - the shell DM
485 
486     Level: advanced
487 
488 .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateLocalVector()
489 @*/
490 PetscErrorCode  DMShellCreate(MPI_Comm comm,DM *dm)
491 {
492   PetscErrorCode ierr;
493 
494   PetscFunctionBegin;
495   PetscValidPointer(dm,2);
496   ierr = DMCreate(comm,dm);CHKERRQ(ierr);
497   ierr = DMSetType(*dm,DMSHELL);CHKERRQ(ierr);
498   PetscFunctionReturn(0);
499 }
500 
501