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