xref: /petsc/src/snes/utils/dmlocalsnes.c (revision b00a91154f763f12aa55f3d53a3f2776f15f49e3)
1 #include <petsc-private/dmimpl.h>
2 #include <petsc-private/snesimpl.h>   /*I "petscsnes.h" I*/
3 
4 typedef struct {
5   PetscErrorCode (*residuallocal)(DM,Vec,Vec,void*);
6   PetscErrorCode (*jacobianlocal)(DM,Vec,Mat,Mat,MatStructure*,void*);
7   void *residuallocalctx;
8   void *jacobianlocalctx;
9 } DMSNES_Local;
10 
11 #undef __FUNCT__
12 #define __FUNCT__ "DMSNESDestroy_DMLocal"
13 static PetscErrorCode DMSNESDestroy_DMLocal(DMSNES sdm)
14 {
15   PetscErrorCode ierr;
16 
17   PetscFunctionBegin;
18   ierr = PetscFree(sdm->data);CHKERRQ(ierr);
19   PetscFunctionReturn(0);
20 }
21 
22 #undef __FUNCT__
23 #define __FUNCT__ "DMSNESDuplicate_DMLocal"
24 static PetscErrorCode DMSNESDuplicate_DMLocal(DMSNES oldsdm,DMSNES sdm)
25 {
26   PetscErrorCode ierr;
27 
28   PetscFunctionBegin;
29   ierr = PetscNewLog(sdm,(DMSNES_Local**)&sdm->data);CHKERRQ(ierr);
30   if (oldsdm->data) {
31     ierr = PetscMemcpy(sdm->data,oldsdm->data,sizeof(DMSNES_Local));CHKERRQ(ierr);
32   }
33   PetscFunctionReturn(0);
34 }
35 
36 #undef __FUNCT__
37 #define __FUNCT__ "DMLocalSNESGetContext"
38 static PetscErrorCode DMLocalSNESGetContext(DM dm,DMSNES sdm,DMSNES_Local **dmlocalsnes)
39 {
40   PetscErrorCode ierr;
41 
42   PetscFunctionBegin;
43   *dmlocalsnes = NULL;
44   if (!sdm->data) {
45     ierr = PetscNewLog(dm,(DMSNES_Local**)&sdm->data);CHKERRQ(ierr);
46 
47     sdm->ops->destroy   = DMSNESDestroy_DMLocal;
48     sdm->ops->duplicate = DMSNESDuplicate_DMLocal;
49   }
50   *dmlocalsnes = (DMSNES_Local*)sdm->data;
51   PetscFunctionReturn(0);
52 }
53 
54 #undef __FUNCT__
55 #define __FUNCT__ "SNESComputeFunction_DMLocal"
56 static PetscErrorCode SNESComputeFunction_DMLocal(SNES snes,Vec X,Vec F,void *ctx)
57 {
58   PetscErrorCode ierr;
59   DM             dm;
60   DMSNES_Local   *dmlocalsnes = (DMSNES_Local*)ctx;
61   Vec            Xloc,Floc;
62 
63   PetscFunctionBegin;
64   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
65   PetscValidHeaderSpecific(X,VEC_CLASSID,2);
66   PetscValidHeaderSpecific(F,VEC_CLASSID,3);
67   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
68   ierr = DMGetLocalVector(dm,&Xloc);CHKERRQ(ierr);
69   ierr = DMGetLocalVector(dm,&Floc);CHKERRQ(ierr);
70   ierr = VecZeroEntries(Xloc);CHKERRQ(ierr);
71   ierr = VecZeroEntries(Floc);CHKERRQ(ierr);
72   ierr = DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
73   ierr = DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
74   CHKMEMQ;
75   ierr = (*dmlocalsnes->residuallocal)(dm,Xloc,Floc,dmlocalsnes->residuallocalctx);CHKERRQ(ierr);
76   CHKMEMQ;
77   ierr = VecZeroEntries(F);CHKERRQ(ierr);
78   ierr = DMLocalToGlobalBegin(dm,Floc,ADD_VALUES,F);CHKERRQ(ierr);
79   ierr = DMLocalToGlobalEnd(dm,Floc,ADD_VALUES,F);CHKERRQ(ierr);
80   ierr = DMRestoreLocalVector(dm,&Floc);CHKERRQ(ierr);
81   ierr = DMRestoreLocalVector(dm,&Xloc);CHKERRQ(ierr);
82   PetscFunctionReturn(0);
83 }
84 
85 #undef __FUNCT__
86 #define __FUNCT__ "SNESComputeJacobian_DMLocal"
87 static PetscErrorCode SNESComputeJacobian_DMLocal(SNES snes,Vec X,Mat *A,Mat *B,MatStructure *mstr,void *ctx)
88 {
89   PetscErrorCode ierr;
90   DM             dm;
91   DMSNES_Local   *dmlocalsnes = (DMSNES_Local*)ctx;
92   Vec            Xloc;
93 
94   PetscFunctionBegin;
95   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
96   if (dmlocalsnes->jacobianlocal) {
97     ierr = DMGetLocalVector(dm,&Xloc);CHKERRQ(ierr);
98     ierr = VecZeroEntries(Xloc);CHKERRQ(ierr);
99     ierr = DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
100     ierr = DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
101     CHKMEMQ;
102     ierr = (*dmlocalsnes->jacobianlocal)(dm,Xloc,*A,*B,mstr,dmlocalsnes->jacobianlocalctx);CHKERRQ(ierr);
103     CHKMEMQ;
104     ierr = DMRestoreLocalVector(dm,&Xloc);CHKERRQ(ierr);
105   } else {
106     MatFDColoring fdcoloring;
107     ierr = PetscObjectQuery((PetscObject)dm,"DMDASNES_FDCOLORING",(PetscObject*)&fdcoloring);CHKERRQ(ierr);
108     if (!fdcoloring) {
109       ISColoring coloring;
110 
111       ierr = DMCreateColoring(dm,dm->coloringtype,&coloring);CHKERRQ(ierr);
112       ierr = MatFDColoringCreate(*B,coloring,&fdcoloring);CHKERRQ(ierr);
113       ierr = ISColoringDestroy(&coloring);CHKERRQ(ierr);
114       switch (dm->coloringtype) {
115       case IS_COLORING_GLOBAL:
116         ierr = MatFDColoringSetFunction(fdcoloring,(PetscErrorCode (*)(void))SNESComputeFunction_DMLocal,dmlocalsnes);CHKERRQ(ierr);
117         break;
118       default: SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_SUP,"No support for coloring type '%s'",ISColoringTypes[dm->coloringtype]);
119       }
120       ierr = PetscObjectSetOptionsPrefix((PetscObject)fdcoloring,((PetscObject)dm)->prefix);CHKERRQ(ierr);
121       ierr = MatFDColoringSetFromOptions(fdcoloring);CHKERRQ(ierr);
122       ierr = MatFDColoringSetUp(*B,coloring,fdcoloring);CHKERRQ(ierr);
123       ierr = PetscObjectCompose((PetscObject)dm,"DMDASNES_FDCOLORING",(PetscObject)fdcoloring);CHKERRQ(ierr);
124       ierr = PetscObjectDereference((PetscObject)fdcoloring);CHKERRQ(ierr);
125 
126       /* The following breaks an ugly reference counting loop that deserves a paragraph. MatFDColoringApply() will call
127        * VecDuplicate() with the state Vec and store inside the MatFDColoring. This Vec will duplicate the Vec, but the
128        * MatFDColoring is composed with the DM. We dereference the DM here so that the reference count will eventually
129        * drop to 0. Note the code in DMDestroy() that exits early for a negative reference count. That code path will be
130        * taken when the PetscObjectList for the Vec inside MatFDColoring is destroyed.
131        */
132       ierr = PetscObjectDereference((PetscObject)dm);CHKERRQ(ierr);
133     }
134     *mstr = SAME_NONZERO_PATTERN;
135     ierr  = MatFDColoringApply(*B,fdcoloring,X,mstr,snes);CHKERRQ(ierr);
136   }
137   /* This will be redundant if the user called both, but it's too common to forget. */
138   if (*A != *B) {
139     ierr = MatAssemblyBegin(*A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
140     ierr = MatAssemblyEnd(*A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
141   }
142   PetscFunctionReturn(0);
143 }
144 
145 #undef __FUNCT__
146 #define __FUNCT__ "DMSNESSetFunctionLocal"
147 /*@C
148    DMSNESSetFunctionLocal - set a local residual evaluation function. This function is called with local vector
149       containing the local vector information PLUS ghost point information. It should compute a result for all local
150       elements and DMSNES will automatically accumulate the overlapping values.
151 
152    Logically Collective
153 
154    Input Arguments:
155 +  dm - DM to associate callback with
156 .  func - local residual evaluation
157 -  ctx - optional context for local residual evaluation
158 
159    Level: beginner
160 
161 .seealso: DMSNESSetFunction(), DMDASNESSetJacobianLocal(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
162 @*/
163 PetscErrorCode DMSNESSetFunctionLocal(DM dm,PetscErrorCode (*func)(DM,Vec,Vec,void*),void *ctx)
164 {
165   PetscErrorCode ierr;
166   DMSNES         sdm;
167   DMSNES_Local   *dmlocalsnes;
168 
169   PetscFunctionBegin;
170   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
171   ierr = DMGetDMSNESWrite(dm,&sdm);CHKERRQ(ierr);
172   ierr = DMLocalSNESGetContext(dm,sdm,&dmlocalsnes);CHKERRQ(ierr);
173 
174   dmlocalsnes->residuallocal    = func;
175   dmlocalsnes->residuallocalctx = ctx;
176 
177   ierr = DMSNESSetFunction(dm,SNESComputeFunction_DMLocal,dmlocalsnes);CHKERRQ(ierr);
178   if (!sdm->ops->computejacobian) {  /* Call us for the Jacobian too, can be overridden by the user. */
179     ierr = DMSNESSetJacobian(dm,SNESComputeJacobian_DMLocal,dmlocalsnes);CHKERRQ(ierr);
180   }
181   PetscFunctionReturn(0);
182 }
183 
184 #undef __FUNCT__
185 #define __FUNCT__ "DMSNESSetJacobianLocal"
186 /*@C
187    DMSNESSetJacobianLocal - set a local Jacobian evaluation function
188 
189    Logically Collective
190 
191    Input Arguments:
192 +  dm - DM to associate callback with
193 .  func - local Jacobian evaluation
194 -  ctx - optional context for local Jacobian evaluation
195 
196    Level: beginner
197 
198 .seealso: DMSNESSetJacobian(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
199 @*/
200 PetscErrorCode DMSNESSetJacobianLocal(DM dm,PetscErrorCode (*func)(DM,Vec,Mat,Mat,MatStructure*,void*),void *ctx)
201 {
202   PetscErrorCode ierr;
203   DMSNES         sdm;
204   DMSNES_Local   *dmlocalsnes;
205 
206   PetscFunctionBegin;
207   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
208   ierr = DMGetDMSNESWrite(dm,&sdm);CHKERRQ(ierr);
209   ierr = DMLocalSNESGetContext(dm,sdm,&dmlocalsnes);CHKERRQ(ierr);
210 
211   dmlocalsnes->jacobianlocal    = func;
212   dmlocalsnes->jacobianlocalctx = ctx;
213 
214   ierr = DMSNESSetJacobian(dm,SNESComputeJacobian_DMLocal,dmlocalsnes);CHKERRQ(ierr);
215   PetscFunctionReturn(0);
216 }
217 
218