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