xref: /petsc/src/dm/dt/fe/impls/vector/fevector.c (revision 1b37a2a7cc4a4fb30c3e967db1c694c0a1013f51)
1 #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/
2 #include <petsc/private/petscimpl.h>
3 
4 typedef struct _n_PetscFE_Vec {
5   PetscFE   scalar_fe;
6   PetscInt  num_copies;
7   PetscBool interleave_basis;
8   PetscBool interleave_components;
9 } PetscFE_Vec;
10 
11 static PetscErrorCode PetscFEDestroy_Vector(PetscFE fe)
12 {
13   PetscFE_Vec *v;
14 
15   PetscFunctionBegin;
16   v = (PetscFE_Vec *)fe->data;
17   PetscCall(PetscFEDestroy(&v->scalar_fe));
18   PetscCall(PetscFree(v));
19   PetscFunctionReturn(PETSC_SUCCESS);
20 }
21 
22 static PetscErrorCode PetscFEView_Vector_Ascii(PetscFE fe, PetscViewer v)
23 {
24   PetscInt          dim, Nc, scalar_Nc;
25   PetscSpace        basis = NULL;
26   PetscDualSpace    dual  = NULL;
27   PetscQuadrature   quad  = NULL;
28   PetscFE_Vec      *vec;
29   PetscViewerFormat fmt;
30 
31   PetscFunctionBegin;
32   vec = (PetscFE_Vec *)fe->data;
33   PetscCall(PetscFEGetSpatialDimension(fe, &dim));
34   PetscCall(PetscFEGetNumComponents(fe, &Nc));
35   PetscCall(PetscFEGetNumComponents(vec->scalar_fe, &scalar_Nc));
36   PetscCall(PetscFEGetBasisSpace(fe, &basis));
37   PetscCall(PetscFEGetDualSpace(fe, &dual));
38   PetscCall(PetscFEGetQuadrature(fe, &quad));
39   PetscCall(PetscViewerGetFormat(v, &fmt));
40   PetscCall(PetscViewerASCIIPushTab(v));
41   if (scalar_Nc == 1) {
42     PetscCall(PetscViewerASCIIPrintf(v, "Vector Finite Element in %" PetscInt_FMT " dimensions with %" PetscInt_FMT " components\n", dim, Nc));
43   } else {
44     PetscCall(PetscViewerASCIIPrintf(v, "Vector Finite Element in %" PetscInt_FMT " dimensions with %" PetscInt_FMT " components (%" PetscInt_FMT " copies of finite element with %" PetscInt_FMT " components)\n", dim, Nc, vec->num_copies, scalar_Nc));
45   }
46   if (fmt == PETSC_VIEWER_ASCII_INFO_DETAIL) {
47     PetscCall(PetscViewerASCIIPrintf(v, "Original finite element:\n"));
48     PetscCall(PetscViewerASCIIPushTab(v));
49     PetscCall(PetscFEView(vec->scalar_fe, v));
50     PetscCall(PetscViewerASCIIPopTab(v));
51   }
52   if (basis) PetscCall(PetscSpaceView(basis, v));
53   if (dual) PetscCall(PetscDualSpaceView(dual, v));
54   if (quad) PetscCall(PetscQuadratureView(quad, v));
55   PetscCall(PetscViewerASCIIPopTab(v));
56   PetscFunctionReturn(PETSC_SUCCESS);
57 }
58 
59 static PetscErrorCode PetscFEView_Vector(PetscFE fe, PetscViewer v)
60 {
61   PetscBool iascii;
62 
63   PetscFunctionBegin;
64   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii));
65   if (iascii) PetscCall(PetscFEView_Vector_Ascii(fe, v));
66   PetscFunctionReturn(PETSC_SUCCESS);
67 }
68 
69 static PetscErrorCode PetscFESetUp_Vector(PetscFE fe)
70 {
71   PetscFE_Vec        *v = (PetscFE_Vec *)fe->data;
72   PetscDualSpace      dsp;
73   PetscInt            n, Ncopies = v->num_copies;
74   PetscInt            scalar_n;
75   PetscInt           *d, *d_mapped;
76   PetscDualSpace_Sum *sum;
77   PetscBool           is_sum;
78 
79   PetscFunctionBegin;
80   PetscCall(PetscFESetUp(v->scalar_fe));
81   PetscCall(PetscFEGetDimension(v->scalar_fe, &scalar_n));
82   PetscCall(PetscFEGetDualSpace(fe, &dsp));
83   PetscCall(PetscObjectTypeCompare((PetscObject)dsp, PETSCDUALSPACESUM, &is_sum));
84   PetscCheck(is_sum, PetscObjectComm((PetscObject)fe), PETSC_ERR_ARG_INCOMP, "Expected PETSCDUALSPACESUM dual space");
85   sum = (PetscDualSpace_Sum *)dsp->data;
86   n   = Ncopies * scalar_n;
87   PetscCall(PetscCalloc1(n * n, &fe->invV));
88   PetscCall(PetscMalloc2(scalar_n, &d, scalar_n, &d_mapped));
89   for (PetscInt i = 0; i < scalar_n; i++) d[i] = i;
90   for (PetscInt c = 0; c < Ncopies; c++) {
91     PetscCall(ISLocalToGlobalMappingApply(sum->all_rows[c], scalar_n, d, d_mapped));
92     for (PetscInt i = 0; i < scalar_n; i++) {
93       PetscInt         iw      = d_mapped[i];
94       PetscReal       *row_w   = &fe->invV[iw * n];
95       const PetscReal *row_r   = &v->scalar_fe->invV[i * scalar_n];
96       PetscInt         j0      = v->interleave_basis ? c : c * scalar_n;
97       PetscInt         jstride = v->interleave_basis ? Ncopies : 1;
98 
99       for (PetscInt j = 0; j < scalar_n; j++) row_w[j0 + j * jstride] = row_r[j];
100     }
101   }
102   PetscCall(PetscFree2(d, d_mapped));
103 
104   PetscFunctionReturn(PETSC_SUCCESS);
105 }
106 
107 static PetscErrorCode PetscFEGetDimension_Vector(PetscFE fe, PetscInt *dim)
108 {
109   PetscFE_Vec *v = (PetscFE_Vec *)fe->data;
110 
111   PetscFunctionBegin;
112   PetscCall(PetscFEGetDimension(v->scalar_fe, dim));
113   *dim *= v->num_copies;
114   PetscFunctionReturn(PETSC_SUCCESS);
115 }
116 
117 static PetscErrorCode PetscFEVectorInsertTabulation(PetscFE fe, PetscInt npoints, const PetscReal points[], PetscInt k, PetscInt scalar_Nb, PetscInt scalar_point_stride, const PetscReal scalar_Tk[], PetscReal Tk[])
118 {
119   PetscFE_Vec *v = (PetscFE_Vec *)fe->data;
120   PetscInt     scalar_Nc;
121   PetscInt     Nc;
122   PetscInt     cdim;
123   PetscInt     dblock;
124   PetscInt     block;
125   PetscInt     scalar_block;
126 
127   PetscFunctionBegin;
128   PetscCall(PetscFEGetNumComponents(v->scalar_fe, &scalar_Nc));
129   Nc = scalar_Nc * v->num_copies;
130   PetscCall(PetscFEGetSpatialDimension(v->scalar_fe, &cdim));
131   dblock       = PetscPowInt(cdim, k);
132   block        = Nc * dblock;
133   scalar_block = scalar_Nc * dblock;
134   for (PetscInt p = 0; p < npoints; p++) {
135     const PetscReal *scalar_Tp = &scalar_Tk[p * scalar_point_stride];
136     PetscReal       *Tp        = &Tk[p * scalar_point_stride * v->num_copies * v->num_copies];
137 
138     for (PetscInt j = 0; j < v->num_copies; j++) {
139       for (PetscInt scalar_i = 0; scalar_i < scalar_Nb; scalar_i++) {
140         PetscInt         i         = v->interleave_basis ? (scalar_i * v->num_copies + j) : (j * scalar_Nb + scalar_i);
141         const PetscReal *scalar_Ti = &scalar_Tp[scalar_i * scalar_block];
142         PetscReal       *Ti        = &Tp[i * block];
143 
144         for (PetscInt scalar_c = 0; scalar_c < scalar_Nc; scalar_c++) {
145           PetscInt         c         = v->interleave_components ? (scalar_c * v->num_copies + j) : (j * scalar_Nc + scalar_c);
146           const PetscReal *scalar_Tc = &scalar_Ti[scalar_c * dblock];
147           PetscReal       *Tc        = &Ti[c * dblock];
148 
149           PetscCall(PetscArraycpy(Tc, scalar_Tc, dblock));
150         }
151       }
152     }
153   }
154   PetscFunctionReturn(PETSC_SUCCESS);
155 }
156 
157 static PetscErrorCode PetscFECreateTabulation_Vector(PetscFE fe, PetscInt npoints, const PetscReal points[], PetscInt K, PetscTabulation T)
158 {
159   PetscFE_Vec    *v = (PetscFE_Vec *)fe->data;
160   PetscInt        scalar_Nc;
161   PetscInt        scalar_Nb;
162   PetscInt        cdim;
163   PetscTabulation scalar_T;
164 
165   PetscFunctionBegin;
166   PetscAssert(npoints == T->Nr * T->Np, PetscObjectComm((PetscObject)fe), PETSC_ERR_PLIB, "Expected to be able decode PetscFECreateTabulation() from PetscTabulation fields");
167   PetscCall(PetscFECreateTabulation(v->scalar_fe, T->Nr, T->Np, points, K, &scalar_T));
168   PetscCall(PetscFEGetNumComponents(v->scalar_fe, &scalar_Nc));
169   PetscCall(PetscFEGetDimension(v->scalar_fe, &scalar_Nb));
170   PetscCall(PetscFEGetSpatialDimension(v->scalar_fe, &cdim));
171   for (PetscInt k = 0; k <= T->K; k++) {
172     PetscReal       *Tk                  = T->T[k];
173     const PetscReal *scalar_Tk           = scalar_T->T[k];
174     PetscInt         dblock              = PetscPowInt(cdim, k);
175     PetscInt         scalar_block        = scalar_Nc * dblock;
176     PetscInt         scalar_point_stride = scalar_Nb * scalar_block;
177 
178     if (v->interleave_basis) {
179       PetscCall(PetscFEVectorInsertTabulation(fe, npoints, points, k, scalar_Nb, scalar_point_stride, scalar_Tk, Tk));
180     } else {
181       PetscDualSpace scalar_dsp;
182       PetscSection   ref_section;
183       PetscInt       pStart, pEnd;
184 
185       PetscCall(PetscFEGetDualSpace(v->scalar_fe, &scalar_dsp));
186       PetscCall(PetscDualSpaceGetSection(scalar_dsp, &ref_section));
187       PetscCall(PetscSectionGetChart(ref_section, &pStart, &pEnd));
188       for (PetscInt p = pStart; p < pEnd; p++) {
189         PetscInt         dof, off;
190         PetscReal       *Tp;
191         const PetscReal *scalar_Tp;
192 
193         PetscCall(PetscSectionGetDof(ref_section, p, &dof));
194         PetscCall(PetscSectionGetOffset(ref_section, p, &off));
195         scalar_Tp = &scalar_Tk[off * scalar_block];
196         Tp        = &Tk[off * scalar_block * v->num_copies * v->num_copies];
197         PetscCall(PetscFEVectorInsertTabulation(fe, npoints, points, k, dof, scalar_point_stride, scalar_Tp, Tp));
198       }
199     }
200   }
201   PetscCall(PetscTabulationDestroy(&scalar_T));
202   PetscFunctionReturn(PETSC_SUCCESS);
203 }
204 
205 static PetscErrorCode PetscFECreatePointTrace_Vector(PetscFE fe, PetscInt refPoint, PetscFE *trFE)
206 {
207   PetscFE_Vec *v = (PetscFE_Vec *)fe->data;
208   PetscFE      scalar_trFE;
209   const char  *name;
210 
211   PetscFunctionBegin;
212   PetscCall(PetscFECreatePointTrace(v->scalar_fe, refPoint, &scalar_trFE));
213   PetscCall(PetscFECreateVector(scalar_trFE, v->num_copies, v->interleave_basis, v->interleave_components, trFE));
214   PetscCall(PetscFEDestroy(&scalar_trFE));
215   PetscCall(PetscObjectGetName((PetscObject)fe, &name));
216   if (name) PetscCall(PetscFESetName(*trFE, name));
217   PetscFunctionReturn(PETSC_SUCCESS);
218 }
219 
220 PETSC_INTERN PetscErrorCode PetscFEIntegrate_Basic(PetscDS, PetscInt, PetscInt, PetscFEGeom *, const PetscScalar[], PetscDS, const PetscScalar[], PetscScalar[]);
221 PETSC_INTERN PetscErrorCode PetscFEIntegrateBd_Basic(PetscDS, PetscInt, PetscBdPointFunc, PetscInt, PetscFEGeom *, const PetscScalar[], PetscDS, const PetscScalar[], PetscScalar[]);
222 PETSC_INTERN PetscErrorCode PetscFEIntegrateHybridResidual_Basic(PetscDS, PetscDS, PetscFormKey, PetscInt, PetscInt, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscScalar[]);
223 PETSC_INTERN PetscErrorCode PetscFEIntegrateBdJacobian_Basic(PetscDS, PetscWeakForm, PetscFEJacobianType, PetscFormKey, PetscInt, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscReal, PetscScalar[]);
224 PETSC_INTERN PetscErrorCode PetscFEIntegrateHybridJacobian_Basic(PetscDS, PetscDS, PetscFEJacobianType, PetscFormKey, PetscInt, PetscInt, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscReal, PetscScalar[]);
225 
226 static PetscErrorCode PetscFEInitialize_Vector(PetscFE fe)
227 {
228   PetscFunctionBegin;
229   fe->ops->setfromoptions          = NULL;
230   fe->ops->setup                   = PetscFESetUp_Vector;
231   fe->ops->view                    = PetscFEView_Vector;
232   fe->ops->destroy                 = PetscFEDestroy_Vector;
233   fe->ops->getdimension            = PetscFEGetDimension_Vector;
234   fe->ops->createpointtrace        = PetscFECreatePointTrace_Vector;
235   fe->ops->createtabulation        = PetscFECreateTabulation_Vector;
236   fe->ops->integrate               = PetscFEIntegrate_Basic;
237   fe->ops->integratebd             = PetscFEIntegrateBd_Basic;
238   fe->ops->integrateresidual       = PetscFEIntegrateResidual_Basic;
239   fe->ops->integratebdresidual     = PetscFEIntegrateBdResidual_Basic;
240   fe->ops->integratehybridresidual = PetscFEIntegrateHybridResidual_Basic;
241   fe->ops->integratejacobianaction = NULL;
242   fe->ops->integratejacobian       = PetscFEIntegrateJacobian_Basic;
243   fe->ops->integratebdjacobian     = PetscFEIntegrateBdJacobian_Basic;
244   fe->ops->integratehybridjacobian = PetscFEIntegrateHybridJacobian_Basic;
245   PetscFunctionReturn(PETSC_SUCCESS);
246 }
247 
248 /*MC
249   PETSCFEVECTOR = "vector" - A vector-valued `PetscFE` object that is repeated copies
250   of the same underlying finite element.
251 
252   Level: intermediate
253 
254 .seealso: `PetscFE`, `PetscFEType`, `PetscFECreate()`, `PetscFESetType()`, `PETSCFEBASIC`, `PetscFECreateVector()`
255 M*/
256 PETSC_EXTERN PetscErrorCode PetscFECreate_Vector(PetscFE fe)
257 {
258   PetscFE_Vec *v;
259 
260   PetscFunctionBegin;
261   PetscValidHeaderSpecific(fe, PETSCFE_CLASSID, 1);
262   PetscCall(PetscNew(&v));
263   fe->data = v;
264 
265   PetscCall(PetscFEInitialize_Vector(fe));
266   PetscFunctionReturn(PETSC_SUCCESS);
267 }
268 
269 /*@
270   PetscFECreateVector - Create a vector-valued `PetscFE` from multiple copies of an underlying
271   `PetscFE`.
272 
273   Collective
274 
275   Input Parameters:
276 + scalar_fe             - a `PetscFE` finite element
277 . num_copies            - a positive integer
278 . interleave_basis      - if `PETSC_TRUE`, the first `num_copies` basis vectors
279                           of the output finite element will be copies of the
280                           first basis vector of `scalar_fe`, and so on for the
281                           other basis vectors; otherwise all of the first-copy
282                           basis vectors will come first, followed by all of the
283                           second-copy, and so on.
284 - interleave_components - if `PETSC_TRUE`, the first `num_copies` components
285                           of the output finite element will be copies of the
286                           first component of `scalar_fe`, and so on for the
287                           other components; otherwise all of the first-copy
288                           components will come first, followed by all of the
289                           second-copy, and so on.
290 
291   Output Parameter:
292 . vector_fe - a `PetscFE` of type `PETSCFEVECTOR` that represent a discretization space with `num_copies` copies of `scalar_fe`
293 
294   Level: intermediate
295 
296 .seealso: `PetscFE`, `PetscFEType`, `PetscFECreate()`, `PetscFESetType()`, `PETSCFEBASIC`, `PETSCFEVECTOR`
297 @*/
298 PetscErrorCode PetscFECreateVector(PetscFE scalar_fe, PetscInt num_copies, PetscBool interleave_basis, PetscBool interleave_components, PetscFE *vector_fe)
299 {
300   MPI_Comm        comm;
301   PetscFE         fe_vec;
302   PetscFE_Vec    *v;
303   PetscInt        scalar_Nc;
304   PetscQuadrature quad;
305 
306   PetscFunctionBegin;
307   PetscValidHeaderSpecific(scalar_fe, PETSCFE_CLASSID, 1);
308   PetscCall(PetscObjectGetComm((PetscObject)scalar_fe, &comm));
309   PetscCheck(num_copies >= 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "Expected positive number of copies, got %" PetscInt_FMT, num_copies);
310   PetscCall(PetscFECreate(comm, vector_fe));
311   fe_vec = *vector_fe;
312   PetscCall(PetscFESetType(fe_vec, PETSCFEVECTOR));
313   v = (PetscFE_Vec *)fe_vec->data;
314   PetscCall(PetscObjectReference((PetscObject)scalar_fe));
315   v->scalar_fe             = scalar_fe;
316   v->num_copies            = num_copies;
317   v->interleave_basis      = interleave_basis;
318   v->interleave_components = interleave_components;
319   PetscCall(PetscFEGetNumComponents(scalar_fe, &scalar_Nc));
320   PetscCall(PetscFESetNumComponents(fe_vec, scalar_Nc * num_copies));
321   PetscCall(PetscFEGetQuadrature(scalar_fe, &quad));
322   PetscCall(PetscFESetQuadrature(fe_vec, quad));
323   PetscCall(PetscFEGetFaceQuadrature(scalar_fe, &quad));
324   PetscCall(PetscFESetFaceQuadrature(fe_vec, quad));
325   {
326     PetscSpace  scalar_sp;
327     PetscSpace *copies;
328     PetscSpace  sp;
329 
330     PetscCall(PetscFEGetBasisSpace(scalar_fe, &scalar_sp));
331     PetscCall(PetscMalloc1(num_copies, &copies));
332     for (PetscInt i = 0; i < num_copies; i++) {
333       PetscCall(PetscObjectReference((PetscObject)scalar_sp));
334       copies[i] = scalar_sp;
335     }
336     PetscCall(PetscSpaceCreateSum(num_copies, copies, PETSC_TRUE, &sp));
337     PetscCall(PetscSpaceSumSetInterleave(sp, interleave_basis, interleave_components));
338     PetscCall(PetscSpaceSetUp(sp));
339     PetscCall(PetscFESetBasisSpace(fe_vec, sp));
340     PetscCall(PetscSpaceDestroy(&sp));
341     for (PetscInt i = 0; i < num_copies; i++) PetscCall(PetscSpaceDestroy(&copies[i]));
342     PetscCall(PetscFree(copies));
343   }
344   {
345     PetscDualSpace  scalar_sp;
346     PetscDualSpace *copies;
347     PetscDualSpace  sp;
348 
349     PetscCall(PetscFEGetDualSpace(scalar_fe, &scalar_sp));
350     PetscCall(PetscMalloc1(num_copies, &copies));
351     for (PetscInt i = 0; i < num_copies; i++) {
352       PetscCall(PetscObjectReference((PetscObject)scalar_sp));
353       copies[i] = scalar_sp;
354     }
355     PetscCall(PetscDualSpaceCreateSum(num_copies, copies, PETSC_TRUE, &sp));
356     PetscCall(PetscDualSpaceSumSetInterleave(sp, interleave_basis, interleave_components));
357     PetscCall(PetscDualSpaceSetUp(sp));
358     PetscCall(PetscFESetDualSpace(fe_vec, sp));
359     PetscCall(PetscDualSpaceDestroy(&sp));
360     for (PetscInt i = 0; i < num_copies; i++) PetscCall(PetscDualSpaceDestroy(&copies[i]));
361     PetscCall(PetscFree(copies));
362   }
363   PetscFunctionReturn(PETSC_SUCCESS);
364 }
365