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