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