xref: /libCEED/examples/petsc/src/petscutils.c (revision cdf95791513f7c35170bef3ba2e19f272fe04533)
1 #include "../include/petscutils.h"
2 
3 // -----------------------------------------------------------------------------
4 // Convert PETSc MemType to libCEED MemType
5 // -----------------------------------------------------------------------------
6 CeedMemType MemTypeP2C(PetscMemType mem_type) {
7   return PetscMemTypeDevice(mem_type) ? CEED_MEM_DEVICE : CEED_MEM_HOST;
8 }
9 
10 // -----------------------------------------------------------------------------
11 // Utility function taken from petsc/src/dm/impls/plex/examples/tutorials/ex7.c
12 // -----------------------------------------------------------------------------
13 PetscErrorCode ProjectToUnitSphere(DM dm) {
14   Vec            coordinates;
15   PetscScalar   *coords;
16   PetscInt       Nv, v, dim, d;
17   PetscErrorCode ierr;
18 
19   PetscFunctionBeginUser;
20   ierr = DMGetCoordinatesLocal(dm, &coordinates); CHKERRQ(ierr);
21   ierr = VecGetLocalSize(coordinates, &Nv); CHKERRQ(ierr);
22   ierr = VecGetBlockSize(coordinates, &dim); CHKERRQ(ierr);
23   Nv  /= dim;
24   ierr = VecGetArray(coordinates, &coords); CHKERRQ(ierr);
25   for (v = 0; v < Nv; ++v) {
26     PetscReal r = 0.0;
27 
28     for (d = 0; d < dim; ++d) r += PetscSqr(PetscRealPart(coords[v*dim+d]));
29     r = PetscSqrtReal(r);
30     for (d = 0; d < dim; ++d) coords[v*dim+d] /= r;
31   }
32   ierr = VecRestoreArray(coordinates, &coords); CHKERRQ(ierr);
33   PetscFunctionReturn(0);
34 };
35 
36 // -----------------------------------------------------------------------------
37 // Apply 3D Kershaw mesh transformation
38 // -----------------------------------------------------------------------------
39 // Transition from a value of "a" for x=0, to a value of "b" for x=1.  Optionally
40 // smooth -- see the commented versions at the end.
41 static double step(const double a, const double b, double x) {
42   if (x <= 0) return a;
43   if (x >= 1) return b;
44   return a + (b-a) * (x);
45 }
46 
47 // 1D transformation at the right boundary
48 static double right(const double eps, const double x) {
49   return (x <= 0.5) ? (2-eps) * x : 1 + eps*(x-1);
50 }
51 
52 // 1D transformation at the left boundary
53 static double left(const double eps, const double x) {
54   return 1-right(eps,1-x);
55 }
56 
57 // Apply 3D Kershaw mesh transformation
58 // The eps parameters are in (0, 1]
59 // Uniform mesh is recovered for eps=1
60 PetscErrorCode Kershaw(DM dm_orig, PetscScalar eps) {
61   PetscErrorCode ierr;
62   Vec coord;
63   PetscInt ncoord;
64   PetscScalar *c;
65 
66   PetscFunctionBeginUser;
67   ierr = DMGetCoordinatesLocal(dm_orig, &coord); CHKERRQ(ierr);
68   ierr = VecGetLocalSize(coord, &ncoord); CHKERRQ(ierr);
69   ierr = VecGetArray(coord, &c); CHKERRQ(ierr);
70 
71   for (PetscInt i = 0; i < ncoord; i += 3) {
72     PetscScalar x = c[i], y = c[i+1], z = c[i+2];
73     PetscInt layer = x*6;
74     PetscScalar lambda = (x-layer/6.0)*6;
75     c[i] = x;
76 
77     switch (layer) {
78     case 0:
79       c[i+1] = left(eps, y);
80       c[i+2] = left(eps, z);
81       break;
82     case 1:
83     case 4:
84       c[i+1] = step(left(eps, y), right(eps, y), lambda);
85       c[i+2] = step(left(eps, z), right(eps, z), lambda);
86       break;
87     case 2:
88       c[i+1] = step(right(eps, y), left(eps, y), lambda/2);
89       c[i+2] = step(right(eps, z), left(eps, z), lambda/2);
90       break;
91     case 3:
92       c[i+1] = step(right(eps, y), left(eps, y), (1+lambda)/2);
93       c[i+2] = step(right(eps, z), left(eps, z), (1+lambda)/2);
94       break;
95     default:
96       c[i+1] = right(eps, y);
97       c[i+2] = right(eps, z);
98     }
99   }
100   ierr = VecRestoreArray(coord, &c); CHKERRQ(ierr);
101   PetscFunctionReturn(0);
102 }
103 
104 // -----------------------------------------------------------------------------
105 // Create BC label
106 // -----------------------------------------------------------------------------
107 static PetscErrorCode CreateBCLabel(DM dm, const char name[]) {
108   int ierr;
109   DMLabel label;
110 
111   PetscFunctionBeginUser;
112 
113   ierr = DMCreateLabel(dm, name); CHKERRQ(ierr);
114   ierr = DMGetLabel(dm, name, &label); CHKERRQ(ierr);
115   ierr = DMPlexMarkBoundaryFaces(dm, 1, label); CHKERRQ(ierr);
116 
117   PetscFunctionReturn(0);
118 };
119 
120 // -----------------------------------------------------------------------------
121 // This function sets up a DM for a given degree
122 // -----------------------------------------------------------------------------
123 PetscErrorCode SetupDMByDegree(DM dm, PetscInt degree, PetscInt num_comp_u,
124                                PetscInt dim, bool enforce_bc, BCFunction bc_func) {
125   PetscInt ierr, marker_ids[1] = {1};
126   PetscFE fe;
127   MPI_Comm comm;
128 
129   PetscFunctionBeginUser;
130 
131   // Setup FE
132   ierr = PetscObjectGetComm((PetscObject)dm, &comm); CHKERRQ(ierr);
133   ierr = PetscFECreateLagrange(comm, dim, num_comp_u, PETSC_FALSE, degree, degree,
134                                &fe); CHKERRQ(ierr);
135   ierr = DMSetFromOptions(dm); CHKERRQ(ierr);
136   ierr = DMAddField(dm, NULL, (PetscObject)fe); CHKERRQ(ierr);
137   {
138     /* create FE field for coordinates */
139     PetscFE fe_coords;
140     PetscInt num_comp_coord;
141     ierr = DMGetCoordinateDim(dm, &num_comp_coord); CHKERRQ(ierr);
142     ierr = PetscFECreateLagrange(comm, dim, num_comp_coord, PETSC_FALSE, 1, 1,
143                                  &fe_coords); CHKERRQ(ierr);
144     ierr = DMProjectCoordinates(dm, fe_coords); CHKERRQ(ierr);
145     ierr = PetscFEDestroy(&fe_coords); CHKERRQ(ierr);
146   }
147 
148   // Setup DM
149   ierr = DMCreateDS(dm); CHKERRQ(ierr);
150   if (enforce_bc) {
151     PetscBool has_label;
152     DMHasLabel(dm, "marker", &has_label);
153     if (!has_label) {CreateBCLabel(dm, "marker");}
154     DMLabel label;
155     ierr = DMGetLabel(dm, "marker", &label); CHKERRQ(ierr);
156     ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1,
157                          marker_ids, 0, 0, NULL, (void(*)(void))bc_func,
158                          NULL, NULL, NULL); CHKERRQ(ierr);
159   }
160   ierr = DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL);
161   CHKERRQ(ierr);
162   ierr = PetscFEDestroy(&fe); CHKERRQ(ierr);
163 
164   PetscFunctionReturn(0);
165 };
166 
167 // -----------------------------------------------------------------------------
168 // Utility function - essential BC dofs are encoded in closure indices as -(i+1)
169 // -----------------------------------------------------------------------------
170 PetscInt Involute(PetscInt i) {
171   return i >= 0 ? i : -(i + 1);
172 };
173 
174 // -----------------------------------------------------------------------------
175 // Get CEED restriction data from DMPlex
176 // -----------------------------------------------------------------------------
177 PetscErrorCode CreateRestrictionFromPlex(Ceed ceed, DM dm, CeedInt height,
178     DMLabel domain_label, CeedInt value, CeedElemRestriction *elem_restr) {
179   PetscInt num_elem, elem_size, num_dof, num_comp, *elem_restr_offsets;
180   PetscErrorCode ierr;
181 
182   PetscFunctionBeginUser;
183 
184   ierr = DMPlexGetLocalOffsets(dm, domain_label, value, height, 0, &num_elem,
185                                &elem_size, &num_comp, &num_dof, &elem_restr_offsets);
186   CHKERRQ(ierr);
187 
188   CeedElemRestrictionCreate(ceed, num_elem, elem_size, num_comp,
189                             1, num_dof, CEED_MEM_HOST, CEED_COPY_VALUES,
190                             elem_restr_offsets, elem_restr);
191   ierr = PetscFree(elem_restr_offsets); CHKERRQ(ierr);
192 
193   PetscFunctionReturn(0);
194 };
195 
196 // -----------------------------------------------------------------------------
197