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