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