xref: /petsc/src/dm/dt/space/impls/sum/spacesum.c (revision ccb4e88a40f0b86eaeca07ff64c64e4de2fae686)
1 #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/
2 /*@
3   PetscSpaceSumGetNumSubspaces - Get the number of spaces in the sum
4 
5   Input Parameter:
6   . sp  - the function space object
7 
8   Output Parameter:
9   . numSumSpaces - the number of spaces
10 
11 Level: intermediate
12 
13 .seealso: PetscSpaceSumSetNumSubspaces(), PetscSpaceSetDegree(), PetscSpaceSetNumVariables()
14 @*/
15 PetscErrorCode PetscSpaceSumGetNumSubspaces(PetscSpace sp,PetscInt *numSumSpaces)
16 {
17   PetscErrorCode ierr;
18 
19   PetscFunctionBegin;
20   PetscValidHeaderSpecific(sp,PETSCSPACE_CLASSID,1);
21   PetscValidIntPointer(numSumSpaces,2);
22   ierr = PetscTryMethod(sp,"PetscSpaceSumGetNumSubspaces_C",(PetscSpace,PetscInt*),(sp,numSumSpaces));CHKERRQ(ierr);
23   PetscFunctionReturn(0);
24 }
25 
26 /*@
27   PetscSpaceSumSetNumSubspaces - Set the number of spaces in the sum
28 
29   Input Parameters:
30   + sp  - the function space object
31   - numSumSpaces - the number of spaces
32 
33 Level: intermediate
34 
35 .seealso: PetscSpaceSumGetNumSubspaces(), PetscSpaceSetDegree(), PetscSpaceSetNumVariables()
36 @*/
37 PetscErrorCode PetscSpaceSumSetNumSubspaces(PetscSpace sp,PetscInt numSumSpaces)
38 {
39   PetscErrorCode ierr;
40 
41   PetscFunctionBegin;
42   PetscValidHeaderSpecific(sp,PETSCSPACE_CLASSID,1);
43   ierr = PetscTryMethod(sp,"PetscSpaceSumSetNumSubspaces_C",(PetscSpace,PetscInt),(sp,numSumSpaces));CHKERRQ(ierr);
44   PetscFunctionReturn(0);
45 }
46 
47 /*@
48  PetscSpaceSumGetConcatenate - Get the concatenate flag for this space.
49  A concatenated sum space will have number of components equal to the sum of the number of components of all subspaces.A non-concatenated,
50  or direct sum space will have the same number of components as its subspaces .
51 
52  Input Parameters:
53  . sp - the function space object
54 
55  Output Parameters:
56  . concatenate - flag indicating whether subspaces are concatenated.
57 
58 Level: intermediate
59 
60 .seealso: PetscSpaceSumSetConcatenate()
61 @*/
62 PetscErrorCode PetscSpaceSumGetConcatenate(PetscSpace sp,PetscBool *concatenate)
63 {
64   PetscErrorCode ierr;
65 
66   PetscFunctionBegin;
67   PetscValidHeaderSpecific(sp,PETSCSPACE_CLASSID,1);
68   ierr = PetscTryMethod(sp,"PetscSpaceSumGetConcatenate_C",(PetscSpace,PetscBool*),(sp,concatenate));CHKERRQ(ierr);
69   PetscFunctionReturn(0);
70 }
71 
72 /*@
73   PetscSpaceSumSetConcatenate - Sets the concatenate flag for this space.
74  A concatenated sum space will have number of components equal to the sum of the number of components of all subspaces.A non-concatenated,
75  or direct sum space will have the same number of components as its subspaces .
76 
77  Input Parameters:
78   + sp - the function space object
79   - concatenate - are subspaces concatenated components (true) or direct summands (false)
80 
81 Level: intermediate
82 .seealso: PetscSpaceSumGetConcatenate()
83 @*/
84 PetscErrorCode PetscSpaceSumSetConcatenate(PetscSpace sp,PetscBool concatenate)
85 {
86   PetscErrorCode ierr;
87 
88   PetscFunctionBegin;
89   PetscValidHeaderSpecific(sp,PETSCSPACE_CLASSID,1);
90   ierr = PetscTryMethod(sp,"PetscSpaceSumSetConcatenate_C",(PetscSpace,PetscBool),(sp,concatenate));CHKERRQ(ierr);
91   PetscFunctionReturn(0);
92 }
93 
94 /*@
95   PetscSpaceSumGetSubspace - Get a space in the sum
96 
97   Input Parameters:
98   + sp - the function space object
99   - s  - The space number
100 
101   Output Parameter:
102   . subsp - the PetscSpace
103 
104 Level: intermediate
105 
106 .seealso: PetscSpaceSumSetSubspace(), PetscSpaceSetDegree(), PetscSpaceSetNumVariables()
107 @*/
108 PetscErrorCode PetscSpaceSumGetSubspace(PetscSpace sp,PetscInt s,PetscSpace *subsp)
109 {
110   PetscErrorCode ierr;
111 
112   PetscFunctionBegin;
113   PetscValidHeaderSpecific(sp,PETSCSPACE_CLASSID,1);
114   PetscValidPointer(subsp,3);
115   ierr = PetscTryMethod(sp,"PetscSpaceSumGetSubspace_C",(PetscSpace,PetscInt,PetscSpace*),(sp,s,subsp));CHKERRQ(ierr);
116   PetscFunctionReturn(0);
117 }
118 
119 /*@
120   PetscSpaceSumSetSubspace - Set a space in the sum
121 
122   Input Parameters:
123   + sp    - the function space object
124   . s     - The space number
125   - subsp - the number of spaces
126 
127 Level: intermediate
128 
129 .seealso: PetscSpaceSumGetSubspace(), PetscSpaceSetDegree(), PetscSpaceSetNumVariables()
130 @*/
131 PetscErrorCode PetscSpaceSumSetSubspace(PetscSpace sp,PetscInt s,PetscSpace subsp)
132 {
133   PetscErrorCode ierr;
134 
135   PetscFunctionBegin;
136   PetscValidHeaderSpecific(sp,PETSCSPACE_CLASSID,1);
137   if (subsp) PetscValidHeaderSpecific(subsp,PETSCSPACE_CLASSID,3);
138   ierr = PetscTryMethod(sp,"PetscSpaceSumSetSubspace_C",(PetscSpace,PetscInt,PetscSpace),(sp,s,subsp));CHKERRQ(ierr);
139   PetscFunctionReturn(0);
140 }
141 
142 static PetscErrorCode PetscSpaceSumGetNumSubspaces_Sum(PetscSpace space,PetscInt *numSumSpaces)
143 {
144   PetscSpace_Sum *sum = (PetscSpace_Sum*)space->data;
145 
146   PetscFunctionBegin;
147   *numSumSpaces = sum->numSumSpaces;
148   PetscFunctionReturn(0);
149 }
150 
151 static PetscErrorCode PetscSpaceSumSetNumSubspaces_Sum(PetscSpace space,PetscInt numSumSpaces)
152 {
153   PetscSpace_Sum *sum = (PetscSpace_Sum*)space->data;
154   PetscInt       Ns   = sum->numSumSpaces;
155   PetscErrorCode ierr;
156 
157   PetscFunctionBegin;
158   if (sum->setupCalled) SETERRQ(PetscObjectComm((PetscObject)space),PETSC_ERR_ARG_WRONGSTATE,"Cannot change number of subspaces after setup called\n");
159   if (numSumSpaces == Ns) PetscFunctionReturn(0);
160   if (Ns >= 0) {
161     PetscInt s;
162     for (s=0; s<Ns; ++s) {
163       ierr = PetscSpaceDestroy(&sum->sumspaces[s]);CHKERRQ(ierr);
164     }
165     ierr = PetscFree(sum->sumspaces);CHKERRQ(ierr);
166   }
167 
168   Ns   = sum->numSumSpaces = numSumSpaces;
169   ierr = PetscCalloc1(Ns,&sum->sumspaces);CHKERRQ(ierr);
170   PetscFunctionReturn(0);
171 }
172 
173 static PetscErrorCode PetscSpaceSumGetConcatenate_Sum(PetscSpace sp,PetscBool *concatenate)
174 {
175   PetscSpace_Sum *sum = (PetscSpace_Sum*)sp->data;
176 
177   PetscFunctionBegin;
178   *concatenate = sum->concatenate;
179   PetscFunctionReturn(0);
180 }
181 
182 static PetscErrorCode PetscSpaceSumSetConcatenate_Sum(PetscSpace sp,PetscBool concatenate)
183 {
184   PetscSpace_Sum *sum = (PetscSpace_Sum*)sp->data;
185 
186   PetscFunctionBegin;
187   if (sum->setupCalled) SETERRQ(PetscObjectComm((PetscObject)sp),PETSC_ERR_ARG_WRONGSTATE,"Cannot change space concatenation after setup called.\n");
188 
189   sum->concatenate = concatenate;
190   PetscFunctionReturn(0);
191 }
192 
193 static PetscErrorCode PetscSpaceSumGetSubspace_Sum(PetscSpace space,PetscInt s,PetscSpace *subspace)
194 {
195   PetscSpace_Sum *sum = (PetscSpace_Sum*)space->data;
196   PetscInt       Ns   = sum->numSumSpaces;
197 
198   PetscFunctionBegin;
199   if (Ns < 0) SETERRQ(PetscObjectComm((PetscObject)space),PETSC_ERR_ARG_WRONGSTATE,"Must call PetscSpaceSumSetNumSubspaces() first\n");
200   if (s<0 || s>=Ns) SETERRQ1 (PetscObjectComm((PetscObject)space),PETSC_ERR_ARG_OUTOFRANGE,"Invalid subspace number %D\n",subspace);
201 
202   *subspace = sum->sumspaces[s];
203   PetscFunctionReturn(0);
204 }
205 
206 static PetscErrorCode PetscSpaceSumSetSubspace_Sum(PetscSpace space,PetscInt s,PetscSpace subspace)
207 {
208   PetscSpace_Sum *sum = (PetscSpace_Sum*)space->data;
209   PetscInt       Ns   = sum->numSumSpaces;
210   PetscErrorCode ierr;
211 
212   PetscFunctionBegin;
213   if (sum->setupCalled) SETERRQ(PetscObjectComm((PetscObject)space),PETSC_ERR_ARG_WRONGSTATE,"Cannot change subspace after setup called\n");
214   if (Ns < 0) SETERRQ(PetscObjectComm((PetscObject)space),PETSC_ERR_ARG_WRONGSTATE,"Must call PetscSpaceSumSetNumSubspaces() first\n");
215   if (s < 0 || s >= Ns) SETERRQ1(PetscObjectComm((PetscObject)space),PETSC_ERR_ARG_OUTOFRANGE,"Invalid subspace number %D\n",subspace);
216 
217   ierr              = PetscObjectReference((PetscObject)subspace);CHKERRQ(ierr);
218   ierr              = PetscSpaceDestroy(&sum->sumspaces[s]);CHKERRQ(ierr);
219   sum->sumspaces[s] = subspace;
220   PetscFunctionReturn(0);
221 }
222 
223 static PetscErrorCode PetscSpaceSetFromOptions_Sum(PetscOptionItems *PetscOptionsObject,PetscSpace sp)
224 {
225   PetscSpace_Sum *sum = (PetscSpace_Sum*)sp->data;
226   PetscInt       Ns,Nc,Nv,deg,i;
227   PetscBool      concatenate = PETSC_TRUE;
228   const char     *prefix;
229   PetscErrorCode ierr;
230 
231   PetscFunctionBegin;
232   ierr = PetscSpaceGetNumVariables(sp,&Nv);CHKERRQ(ierr);
233   if (!Nv) PetscFunctionReturn(0);
234   ierr = PetscSpaceGetNumComponents(sp,&Nc);CHKERRQ(ierr);
235   ierr = PetscSpaceSumGetNumSubspaces(sp,&Ns);CHKERRQ(ierr);
236   ierr = PetscSpaceGetDegree(sp,&deg,NULL);CHKERRQ(ierr);
237   Ns   = (Ns == PETSC_DEFAULT) ? 1 : Ns;
238 
239   ierr = PetscOptionsHead(PetscOptionsObject,"PetscSpace sum options");CHKERRQ(ierr);
240   ierr = PetscOptionsBoundedInt("-petscspace_sum_spaces","The number of subspaces","PetscSpaceSumSetNumSubspaces",Ns,&Ns,NULL,0);CHKERRQ(ierr);
241   ierr = PetscOptionsBool("-petscspace_sum_concatenate","Subspaces are concatenated components of the final space","PetscSpaceSumSetFromOptions",
242                           concatenate,&concatenate,NULL);CHKERRQ(ierr);
243   ierr = PetscOptionsTail();CHKERRQ(ierr);
244 
245   if (Ns < 0 || (Nv > 0 && Ns == 0)) SETERRQ1(PetscObjectComm((PetscObject)sp),PETSC_ERR_ARG_OUTOFRANGE,"Cannot have a sum space of %D spaces\n",Ns);
246   if (Ns != sum->numSumSpaces) {
247     ierr = PetscSpaceSumSetNumSubspaces(sp,Ns);CHKERRQ(ierr);
248   }
249   ierr = PetscObjectGetOptionsPrefix((PetscObject)sp,&prefix);CHKERRQ(ierr);
250   for (i=0; i<Ns; ++i) {
251     PetscInt   sNv;
252     PetscSpace subspace;
253 
254     ierr = PetscSpaceSumGetSubspace(sp,i,&subspace);CHKERRQ(ierr);
255     if (!subspace) {
256       char subspacePrefix[256];
257 
258       ierr = PetscSpaceCreate(PetscObjectComm((PetscObject)sp),&subspace);CHKERRQ(ierr);
259       ierr = PetscObjectSetOptionsPrefix((PetscObject)subspace,prefix);CHKERRQ(ierr);
260       ierr = PetscSNPrintf(subspacePrefix,256,"sumcomp_%D_",i);CHKERRQ(ierr);
261       ierr = PetscObjectAppendOptionsPrefix((PetscObject)subspace,subspacePrefix);CHKERRQ(ierr);
262     } else {
263       ierr = PetscObjectReference((PetscObject)subspace);CHKERRQ(ierr);
264     }
265     ierr = PetscSpaceSetFromOptions(subspace);CHKERRQ(ierr);
266     ierr = PetscSpaceGetNumVariables(subspace,&sNv);CHKERRQ(ierr);
267     if (!sNv) SETERRQ1(PetscObjectComm((PetscObject)sp),PETSC_ERR_ARG_WRONGSTATE,"Subspace %D has not been set properly, number of variables is 0.\n",i);
268     ierr = PetscSpaceSumSetSubspace(sp,i,subspace);CHKERRQ(ierr);
269     ierr = PetscSpaceDestroy(&subspace);CHKERRQ(ierr);
270   }
271   PetscFunctionReturn(0);
272 }
273 
274 static PetscErrorCode PetscSpaceSetUp_Sum(PetscSpace sp)
275 {
276   PetscSpace_Sum *sum = (PetscSpace_Sum*)sp->data;
277   PetscBool      concatenate = PETSC_TRUE;
278   PetscBool      uniform;
279   PetscInt       Nv,Ns,Nc,i,sum_Nc = 0,deg = PETSC_MAX_INT,maxDeg = PETSC_MIN_INT;
280   PetscInt       minNc,maxNc;
281   PetscErrorCode ierr;
282 
283   PetscFunctionBegin;
284   if (sum->setupCalled) PetscFunctionReturn(0);
285 
286   ierr = PetscSpaceGetNumVariables(sp,&Nv);CHKERRQ(ierr);
287   ierr = PetscSpaceGetNumComponents(sp,&Nc);CHKERRQ(ierr);
288   ierr = PetscSpaceSumGetNumSubspaces(sp,&Ns);CHKERRQ(ierr);
289   if (Ns == PETSC_DEFAULT) {
290     Ns   = 1;
291     ierr = PetscSpaceSumSetNumSubspaces(sp,Ns);CHKERRQ(ierr);
292   }
293   if (Ns < 0) SETERRQ1(PetscObjectComm((PetscObject)sp),PETSC_ERR_ARG_OUTOFRANGE,"Cannot have %D subspaces\n", Ns);
294   uniform = PETSC_TRUE;
295   if (Ns) {
296     PetscSpace s0;
297 
298     ierr = PetscSpaceSumGetSubspace(sp,0,&s0);CHKERRQ(ierr);
299     for (PetscInt i = 1; i < Ns; i++) {
300       PetscSpace si;
301 
302       ierr = PetscSpaceSumGetSubspace(sp,i,&si);CHKERRQ(ierr);
303       if (si != s0) {
304         uniform = PETSC_FALSE;
305         break;
306       }
307     }
308   }
309 
310   minNc = Nc;
311   maxNc = Nc;
312   for (i=0; i<Ns; ++i) {
313     PetscInt   sNv,sNc,iDeg,iMaxDeg;
314     PetscSpace si;
315 
316     ierr = PetscSpaceSumGetSubspace(sp,i,&si);CHKERRQ(ierr);
317     ierr = PetscSpaceSetUp(si);CHKERRQ(ierr);
318     ierr = PetscSpaceGetNumVariables(si,&sNv);CHKERRQ(ierr);
319     if (sNv != Nv) SETERRQ3(PetscObjectComm((PetscObject)sp),PETSC_ERR_ARG_WRONGSTATE,"Subspace %D has %D variables, space has %D.\n",i,sNv,Nv);
320     ierr = PetscSpaceGetNumComponents(si,&sNc);CHKERRQ(ierr);
321     if (i == 0 && sNc == Nc) concatenate = PETSC_FALSE;
322     minNc = PetscMin(minNc, sNc);
323     maxNc = PetscMax(maxNc, sNc);
324     sum_Nc += sNc;
325     ierr    = PetscSpaceSumGetSubspace(sp,i,&si);CHKERRQ(ierr);
326     ierr    = PetscSpaceGetDegree(si,&iDeg,&iMaxDeg);CHKERRQ(ierr);
327     deg     = PetscMin(deg,iDeg);
328     maxDeg  = PetscMax(maxDeg,iMaxDeg);
329   }
330 
331   if (concatenate) {
332     if (sum_Nc != Nc) {
333       SETERRQ2(PetscObjectComm((PetscObject)sp),PETSC_ERR_ARG_OUTOFRANGE,"Total number of subspace components (%D) does not match number of target space components (%D).",sum_Nc,Nc);
334     }
335   } else {
336     if (minNc != Nc || maxNc != Nc) SETERRQ(PetscObjectComm((PetscObject)sp),PETSC_ERR_ARG_OUTOFRANGE,"Subspaces must have same number of components as the target space.");
337   }
338 
339   sp->degree       = deg;
340   sp->maxDegree    = maxDeg;
341   sum->concatenate = concatenate;
342   sum->uniform     = uniform;
343   sum->setupCalled = PETSC_TRUE;
344   PetscFunctionReturn(0);
345 }
346 
347 static PetscErrorCode PetscSpaceSumView_Ascii(PetscSpace sp,PetscViewer v)
348 {
349   PetscSpace_Sum *sum = (PetscSpace_Sum*)sp->data;
350   PetscBool      concatenate = sum->concatenate;
351   PetscInt       i,Ns         = sum->numSumSpaces;
352   PetscErrorCode ierr;
353 
354   PetscFunctionBegin;
355   if (concatenate) {
356     ierr = PetscViewerASCIIPrintf(v,"Sum space of %D concatenated subspaces%s\n",Ns, sum->uniform ? " (all identical)": "");CHKERRQ(ierr);
357   } else {
358     ierr = PetscViewerASCIIPrintf(v,"Sum space of %D subspaces%s\n",Ns, sum->uniform ? " (all identical)" : "");CHKERRQ(ierr);
359   }
360   for (i=0; i < (sum->uniform ? (Ns > 0 ? 1 : 0) : Ns); ++i) {
361     ierr = PetscViewerASCIIPushTab(v);CHKERRQ(ierr);
362     ierr = PetscSpaceView(sum->sumspaces[i],v);CHKERRQ(ierr);
363     ierr = PetscViewerASCIIPopTab(v);CHKERRQ(ierr);
364   }
365   PetscFunctionReturn(0);
366 }
367 
368 static PetscErrorCode PetscSpaceView_Sum(PetscSpace sp,PetscViewer viewer)
369 {
370   PetscBool      iascii;
371   PetscErrorCode ierr;
372 
373   PetscFunctionBegin;
374   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
375   if (iascii) {
376     ierr = PetscSpaceSumView_Ascii(sp,viewer);CHKERRQ(ierr);
377   }
378   PetscFunctionReturn(0);
379 }
380 
381 static PetscErrorCode PetscSpaceDestroy_Sum(PetscSpace sp)
382 {
383   PetscSpace_Sum *sum = (PetscSpace_Sum*)sp->data;
384   PetscInt       i,Ns   = sum->numSumSpaces;
385   PetscErrorCode ierr;
386 
387   PetscFunctionBegin;
388   for (i=0; i<Ns; ++i) {
389     ierr = PetscSpaceDestroy(&sum->sumspaces[i]);CHKERRQ(ierr);
390   }
391   ierr = PetscFree(sum->sumspaces);CHKERRQ(ierr);
392   if (sum->heightsubspaces) {
393     PetscInt d;
394 
395     /* sp->Nv is the spatial dimension, so it is equal to the number
396      * of subspaces on higher co-dimension points */
397     for (d = 0; d < sp->Nv; ++d) {
398       ierr = PetscSpaceDestroy(&sum->heightsubspaces[d]);CHKERRQ(ierr);
399     }
400   }
401   ierr = PetscFree(sum->heightsubspaces);CHKERRQ(ierr);
402   ierr = PetscObjectComposeFunction((PetscObject)sp,"PetscSpaceSumSetSubspace_C",NULL);CHKERRQ(ierr);
403   ierr = PetscObjectComposeFunction((PetscObject)sp,"PetscSpaceSumGetSubspace_C",NULL);CHKERRQ(ierr);
404   ierr = PetscObjectComposeFunction((PetscObject)sp,"PetscSpaceSumSetNumSubspaces_C",NULL);CHKERRQ(ierr);
405   ierr = PetscObjectComposeFunction((PetscObject)sp,"PetscSpaceSumGetNumSubspaces_C",NULL);CHKERRQ(ierr);
406   ierr = PetscFree(sum);CHKERRQ(ierr);
407   PetscFunctionReturn(0);
408 }
409 
410 static PetscErrorCode PetscSpaceGetDimension_Sum(PetscSpace sp,PetscInt *dim)
411 {
412   PetscSpace_Sum *sum = (PetscSpace_Sum*)sp->data;
413   PetscInt       i,d = 0,Ns = sum->numSumSpaces;
414   PetscErrorCode ierr;
415 
416   PetscFunctionBegin;
417   if (!sum->setupCalled) {
418     ierr = PetscSpaceSetUp(sp);CHKERRQ(ierr);
419     ierr = PetscSpaceGetDimension(sp, dim);CHKERRQ(ierr);
420     PetscFunctionReturn(0);
421   }
422 
423   for (i=0; i<Ns; ++i) {
424     PetscInt id;
425 
426     ierr = PetscSpaceGetDimension(sum->sumspaces[i],&id);CHKERRQ(ierr);
427     d   += id;
428   }
429 
430   *dim = d;
431   PetscFunctionReturn(0);
432 }
433 
434 static PetscErrorCode PetscSpaceEvaluate_Sum(PetscSpace sp,PetscInt npoints,const PetscReal points[],PetscReal B[],PetscReal D[],PetscReal H[])
435 {
436   PetscSpace_Sum *sum = (PetscSpace_Sum*)sp->data;
437   PetscBool      concatenate = sum->concatenate;
438   DM             dm = sp->dm;
439   PetscInt       Nc = sp->Nc,Nv = sp->Nv,Ns = sum->numSumSpaces;
440   PetscInt       i,s,offset,ncoffset,pdimfull,numelB,numelD,numelH;
441   PetscReal      *sB = NULL,*sD = NULL,*sH = NULL;
442   PetscErrorCode ierr;
443 
444   PetscFunctionBegin;
445   if (!sum->setupCalled) {
446     ierr = PetscSpaceSetUp(sp);CHKERRQ(ierr);
447     ierr = PetscSpaceEvaluate(sp, npoints, points, B, D, H);CHKERRQ(ierr);
448     PetscFunctionReturn(0);
449   }
450   ierr   = PetscSpaceGetDimension(sp,&pdimfull);CHKERRQ(ierr);
451   numelB = npoints*pdimfull*Nc;
452   numelD = numelB*Nv;
453   numelH = numelD*Nv;
454   if (B || D || H) {
455     ierr = DMGetWorkArray(dm,numelB,MPIU_REAL,&sB);CHKERRQ(ierr);
456   }
457   if (D || H) {
458     ierr = DMGetWorkArray(dm,numelD,MPIU_REAL,&sD);CHKERRQ(ierr);
459   }
460   if (H) {
461     ierr = DMGetWorkArray(dm,numelH,MPIU_REAL,&sH);CHKERRQ(ierr);
462   }
463   if (B)
464     for (i=0; i<numelB; ++i) B[i] = 0.;
465   if (D)
466     for (i=0; i<numelD; ++i) D[i] = 0.;
467   if (H)
468     for (i=0; i<numelH; ++i) H[i] = 0.;
469 
470   for (s=0,offset=0,ncoffset=0; s<Ns; ++s) {
471     PetscInt sNv,spdim,sNc,p;
472 
473     ierr = PetscSpaceGetNumVariables(sum->sumspaces[s],&sNv);CHKERRQ(ierr);
474     ierr = PetscSpaceGetNumComponents(sum->sumspaces[s],&sNc);CHKERRQ(ierr);
475     ierr = PetscSpaceGetDimension(sum->sumspaces[s],&spdim);CHKERRQ(ierr);
476     if (offset + spdim > pdimfull) SETERRQ(PetscObjectComm((PetscObject)sp),PETSC_ERR_ARG_OUTOFRANGE,"Subspace dimensions exceed target space dimension.\n");
477     if (s == 0 || !sum->uniform) {
478       ierr = PetscSpaceEvaluate(sum->sumspaces[s],npoints,points,sB,sD,sH);CHKERRQ(ierr);
479     }
480     if (B || D || H) {
481       for (p=0; p<npoints; ++p) {
482         PetscInt j;
483 
484         for (j=0; j<spdim; ++j) {
485           PetscInt c;
486 
487           for (c=0; c<sNc; ++c) {
488             PetscInt compoffset,BInd,sBInd;
489 
490             compoffset = concatenate ? c+ncoffset : c;
491             BInd       = (p*pdimfull + j + offset)*Nc + compoffset;
492             sBInd      = (p*spdim + j)*sNc + c;
493             if (B) B[BInd] = sB[sBInd];
494             if (D || H) {
495               PetscInt v;
496 
497               for (v=0; v<Nv; ++v) {
498                 PetscInt DInd,sDInd;
499 
500                 DInd  = BInd*Nv + v;
501                 sDInd = sBInd*Nv + v;
502                 if (D) D[DInd] = sD[sDInd];
503                 if (H) {
504                   PetscInt v2;
505 
506                   for (v2=0; v2<Nv; ++v2) {
507                     PetscInt HInd,sHInd;
508 
509                     HInd    = DInd*Nv + v2;
510                     sHInd   = sDInd*Nv + v2;
511                     H[HInd] = sH[sHInd];
512                   }
513                 }
514               }
515             }
516           }
517         }
518       }
519     }
520     offset   += spdim;
521     ncoffset += sNc;
522   }
523 
524   if (H) {
525     ierr = DMRestoreWorkArray(dm,numelH,MPIU_REAL,&sH);CHKERRQ(ierr);
526   }
527   if (D || H) {
528     ierr = DMRestoreWorkArray(dm,numelD,MPIU_REAL,&sD);CHKERRQ(ierr);
529   }
530   if (B || D || H) {
531     ierr = DMRestoreWorkArray(dm,numelB,MPIU_REAL,&sB);CHKERRQ(ierr);
532   }
533   PetscFunctionReturn(0);
534 }
535 
536 static PetscErrorCode PetscSpaceGetHeightSubspace_Sum(PetscSpace sp, PetscInt height, PetscSpace *subsp)
537 {
538   PetscSpace_Sum  *sum = (PetscSpace_Sum *) sp->data;
539   PetscInt         Nc, dim, order;
540   PetscBool        tensor;
541   PetscErrorCode   ierr;
542 
543   PetscFunctionBegin;
544   ierr = PetscSpaceGetNumComponents(sp, &Nc);CHKERRQ(ierr);
545   ierr = PetscSpaceGetNumVariables(sp, &dim);CHKERRQ(ierr);
546   ierr = PetscSpaceGetDegree(sp, &order, NULL);CHKERRQ(ierr);
547   ierr = PetscSpacePolynomialGetTensor(sp, &tensor);CHKERRQ(ierr);
548   if (height > dim || height < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Asked for space at height %D for dimension %D space", height, dim);
549   if (!sum->heightsubspaces) {ierr = PetscCalloc1(dim, &sum->heightsubspaces);CHKERRQ(ierr);}
550   if (height <= dim) {
551     if (!sum->heightsubspaces[height-1]) {
552       PetscSpace  sub;
553       const char *name;
554 
555       ierr = PetscSpaceCreate(PetscObjectComm((PetscObject) sp), &sub);CHKERRQ(ierr);
556       ierr = PetscObjectGetName((PetscObject) sp,  &name);CHKERRQ(ierr);
557       ierr = PetscObjectSetName((PetscObject) sub,  name);CHKERRQ(ierr);
558       ierr = PetscSpaceSetType(sub, PETSCSPACESUM);CHKERRQ(ierr);
559       ierr = PetscSpaceSumSetNumSubspaces(sub, sum->numSumSpaces);CHKERRQ(ierr);
560       ierr = PetscSpaceSumSetConcatenate(sub, sum->concatenate);CHKERRQ(ierr);
561       ierr = PetscSpaceSetNumComponents(sub, Nc);CHKERRQ(ierr);
562       ierr = PetscSpaceSetNumVariables(sub, dim-height);CHKERRQ(ierr);
563       for (PetscInt i = 0; i < sum->numSumSpaces; i++) {
564         PetscSpace subh;
565 
566         ierr = PetscSpaceGetHeightSubspace(sum->sumspaces[i], height, &subh);CHKERRQ(ierr);
567         ierr = PetscSpaceSumSetSubspace(sub, i, subh);CHKERRQ(ierr);
568       }
569       ierr = PetscSpaceSetUp(sub);CHKERRQ(ierr);
570       sum->heightsubspaces[height-1] = sub;
571     }
572     *subsp = sum->heightsubspaces[height-1];
573   } else {
574     *subsp = NULL;
575   }
576   PetscFunctionReturn(0);
577 }
578 
579 static PetscErrorCode PetscSpaceInitialize_Sum(PetscSpace sp)
580 {
581   PetscErrorCode ierr;
582 
583   PetscFunctionBegin;
584   sp->ops->setfromoptions    = PetscSpaceSetFromOptions_Sum;
585   sp->ops->setup             = PetscSpaceSetUp_Sum;
586   sp->ops->view              = PetscSpaceView_Sum;
587   sp->ops->destroy           = PetscSpaceDestroy_Sum;
588   sp->ops->getdimension      = PetscSpaceGetDimension_Sum;
589   sp->ops->evaluate          = PetscSpaceEvaluate_Sum;
590   sp->ops->getheightsubspace = PetscSpaceGetHeightSubspace_Sum;
591 
592   ierr = PetscObjectComposeFunction((PetscObject)sp,"PetscSpaceSumGetNumSubspaces_C",PetscSpaceSumGetNumSubspaces_Sum);CHKERRQ(ierr);
593   ierr = PetscObjectComposeFunction((PetscObject)sp,"PetscSpaceSumSetNumSubspaces_C",PetscSpaceSumSetNumSubspaces_Sum);CHKERRQ(ierr);
594   ierr = PetscObjectComposeFunction((PetscObject)sp,"PetscSpaceSumGetSubspace_C",PetscSpaceSumGetSubspace_Sum);CHKERRQ(ierr);
595   ierr = PetscObjectComposeFunction((PetscObject)sp,"PetscSpaceSumSetSubspace_C",PetscSpaceSumSetSubspace_Sum);CHKERRQ(ierr);
596   ierr = PetscObjectComposeFunction((PetscObject)sp,"PetscSpaceSumGetConcatenate_C",PetscSpaceSumGetConcatenate_Sum);CHKERRQ(ierr);
597   ierr = PetscObjectComposeFunction((PetscObject)sp,"PetscSpaceSumSetConcatenate_C",PetscSpaceSumSetConcatenate_Sum);CHKERRQ(ierr);
598   PetscFunctionReturn(0);
599 }
600 
601 /*MC
602   PETSCSPACESUM = "sum" - A PetscSpace object that encapsulates a sum of subspaces.
603   That sum can either be direct or concatenate a concatenation.For example if A and B are spaces each with 2 components,
604   the direct sum of A and B will also have 2 components while the concatenated sum will have 4 components.In both cases A and B must be defined over the
605   same number of variables.
606 
607 Level: intermediate
608 
609 .seealso: PetscSpaceType, PetscSpaceCreate(), PetscSpaceSetType()
610 M*/
611 PETSC_EXTERN PetscErrorCode PetscSpaceCreate_Sum(PetscSpace sp)
612 {
613   PetscSpace_Sum *sum;
614   PetscErrorCode ierr;
615 
616   PetscFunctionBegin;
617   PetscValidHeaderSpecific(sp,PETSCSPACE_CLASSID,1);
618   ierr     = PetscNewLog(sp,&sum);CHKERRQ(ierr);
619   sum->numSumSpaces = PETSC_DEFAULT;
620   sp->data = sum;
621   ierr     = PetscSpaceInitialize_Sum(sp);CHKERRQ(ierr);
622   PetscFunctionReturn(0);
623 }
624 
625 PETSC_EXTERN PetscErrorCode PetscSpaceCreateSum(PetscInt numSubspaces,const PetscSpace subspaces[],PetscBool concatenate,PetscSpace *sumSpace)
626 {
627   PetscInt       i,Nv,Nc = 0;
628   PetscErrorCode ierr;
629 
630   PetscFunctionBegin;
631   if (sumSpace) {
632     ierr = PetscSpaceDestroy(sumSpace);CHKERRQ(ierr);
633   }
634   ierr = PetscSpaceCreate(PetscObjectComm((PetscObject)subspaces[0]),sumSpace);CHKERRQ(ierr);
635   ierr = PetscSpaceSetType(*sumSpace,PETSCSPACESUM);CHKERRQ(ierr);
636   ierr = PetscSpaceSumSetNumSubspaces(*sumSpace,numSubspaces);CHKERRQ(ierr);
637   ierr = PetscSpaceSumSetConcatenate(*sumSpace,concatenate);CHKERRQ(ierr);
638   for (i=0; i<numSubspaces; ++i) {
639     PetscInt sNc;
640 
641     ierr = PetscSpaceSumSetSubspace(*sumSpace,i,subspaces[i]);CHKERRQ(ierr);
642     ierr = PetscSpaceGetNumComponents(subspaces[i],&sNc);CHKERRQ(ierr);
643     if (concatenate) Nc += sNc;
644     else Nc = sNc;
645   }
646   ierr = PetscSpaceGetNumVariables(subspaces[0],&Nv);CHKERRQ(ierr);
647   ierr = PetscSpaceSetNumComponents(*sumSpace,Nc);CHKERRQ(ierr);
648   ierr = PetscSpaceSetNumVariables(*sumSpace,Nv);CHKERRQ(ierr);
649   ierr = PetscSpaceSetUp(*sumSpace);CHKERRQ(ierr);
650 
651   PetscFunctionReturn(0);
652 }
653