xref: /petsc/src/dm/impls/shell/dmshell.c (revision 988ea7d6cfcd11ddb37e50f03b34575f4eb92bde)
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__ "DMShellSetLocalToGlobalVecScatter"
410 /*@
411    DMShellSetLocalToGlobalVecScatter - Sets a VecScatter context for local to global communication
412 
413    Logically Collective on DM
414 
415    Input Arguments
416 +  dm - the shell DM
417 -  ltog - the local to global VecScatter context
418 
419    Level: advanced
420 
421 .seealso: DMShellSetLocalToGlobal()
422 @*/
423 PetscErrorCode DMShellSetLocalToGlobalVecScatter(DM dm, VecScatter *ltog)
424 {
425   DM_Shell       *shell = (DM_Shell*)dm->data;
426 
427   PetscFunctionBegin;
428   shell->ltog = ltog;
429   PetscFunctionReturn(0);
430 }
431 
432 #undef __FUNCT__
433 #define __FUNCT__ "DMDestroy_Shell"
434 static PetscErrorCode DMDestroy_Shell(DM dm)
435 {
436   PetscErrorCode ierr;
437   DM_Shell       *shell = (DM_Shell*)dm->data;
438 
439   PetscFunctionBegin;
440   ierr = MatDestroy(&shell->A);CHKERRQ(ierr);
441   ierr = VecDestroy(&shell->Xglobal);CHKERRQ(ierr);
442   ierr = VecDestroy(&shell->Xlocal);CHKERRQ(ierr);
443   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
444   ierr = PetscFree(shell);CHKERRQ(ierr);
445   PetscFunctionReturn(0);
446 }
447 
448 #undef __FUNCT__
449 #define __FUNCT__ "DMView_Shell"
450 static PetscErrorCode DMView_Shell(DM dm,PetscViewer v)
451 {
452   PetscErrorCode ierr;
453   DM_Shell       *shell = (DM_Shell*)dm->data;
454 
455   PetscFunctionBegin;
456   ierr = VecView(shell->Xglobal,v);CHKERRQ(ierr);
457   PetscFunctionReturn(0);
458 }
459 
460 #undef __FUNCT__
461 #define __FUNCT__ "DMLoad_Shell"
462 static PetscErrorCode DMLoad_Shell(DM dm,PetscViewer v)
463 {
464   PetscErrorCode ierr;
465   DM_Shell       *shell = (DM_Shell*)dm->data;
466 
467   PetscFunctionBegin;
468   ierr = VecCreate(PetscObjectComm((PetscObject)dm),&shell->Xglobal);CHKERRQ(ierr);
469   ierr = VecLoad(shell->Xglobal,v);CHKERRQ(ierr);
470   PetscFunctionReturn(0);
471 }
472 
473 #undef __FUNCT__
474 #define __FUNCT__ "DMCreate_Shell"
475 PETSC_EXTERN PetscErrorCode DMCreate_Shell(DM dm)
476 {
477   PetscErrorCode ierr;
478   DM_Shell       *shell;
479 
480   PetscFunctionBegin;
481   ierr     = PetscNewLog(dm,DM_Shell,&shell);CHKERRQ(ierr);
482   dm->data = shell;
483 
484   ierr = PetscObjectChangeTypeName((PetscObject)dm,DMSHELL);CHKERRQ(ierr);
485 
486   dm->ops->destroy            = DMDestroy_Shell;
487   dm->ops->createglobalvector = DMCreateGlobalVector_Shell;
488   dm->ops->createlocalvector  = DMCreateLocalVector_Shell;
489   dm->ops->creatematrix       = DMCreateMatrix_Shell;
490   dm->ops->view               = DMView_Shell;
491   dm->ops->load               = DMLoad_Shell;
492   dm->ops->globaltolocalbegin = DMGlobalToLocalBeginDefaultShell;
493   dm->ops->globaltolocalend   = DMGlobalToLocalEndDefaultShell;
494   PetscFunctionReturn(0);
495 }
496 
497 #undef __FUNCT__
498 #define __FUNCT__ "DMShellCreate"
499 /*@
500     DMShellCreate - Creates a shell DM object, used to manage user-defined problem data
501 
502     Collective on MPI_Comm
503 
504     Input Parameter:
505 .   comm - the processors that will share the global vector
506 
507     Output Parameters:
508 .   shell - the shell DM
509 
510     Level: advanced
511 
512 .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateLocalVector()
513 @*/
514 PetscErrorCode  DMShellCreate(MPI_Comm comm,DM *dm)
515 {
516   PetscErrorCode ierr;
517 
518   PetscFunctionBegin;
519   PetscValidPointer(dm,2);
520   ierr = DMCreate(comm,dm);CHKERRQ(ierr);
521   ierr = DMSetType(*dm,DMSHELL);CHKERRQ(ierr);
522   PetscFunctionReturn(0);
523 }
524 
525