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