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