xref: /petsc/src/dm/impls/plex/tutorials/ex18.c (revision 5552b385b77b214b234683fbe1b434751e6350f0)
1*5552b385SBrandon #include "petscsys.h"
2*5552b385SBrandon static const char help[] = "Test of PETSC/CAD Shape Modification Technology";
3*5552b385SBrandon 
4*5552b385SBrandon #include <petscdmplexegads.h>
5*5552b385SBrandon #include <petsc/private/hashmapi.h>
6*5552b385SBrandon 
7*5552b385SBrandon static PetscErrorCode surfArea(DM dm)
8*5552b385SBrandon {
9*5552b385SBrandon   DMLabel     bodyLabel, faceLabel;
10*5552b385SBrandon   double      surfaceArea = 0., volume = 0.;
11*5552b385SBrandon   PetscReal   vol, centroid[3], normal[3];
12*5552b385SBrandon   PetscInt    dim, cStart, cEnd, fStart, fEnd;
13*5552b385SBrandon   PetscInt    bodyID, faceID;
14*5552b385SBrandon   MPI_Comm    comm;
15*5552b385SBrandon   const char *name;
16*5552b385SBrandon 
17*5552b385SBrandon   PetscFunctionBeginUser;
18*5552b385SBrandon   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
19*5552b385SBrandon   PetscCall(PetscObjectGetName((PetscObject)dm, &name));
20*5552b385SBrandon   PetscCall(DMGetDimension(dm, &dim));
21*5552b385SBrandon   PetscCall(PetscPrintf(comm, "    dim = %" PetscInt_FMT "\n", dim));
22*5552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Body ID", &bodyLabel));
23*5552b385SBrandon   PetscCall(DMGetLabel(dm, "EGADS Face ID", &faceLabel));
24*5552b385SBrandon   PetscCall(DMGetCoordinatesLocalSetUp(dm));
25*5552b385SBrandon 
26*5552b385SBrandon   if (dim == 2) {
27*5552b385SBrandon     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
28*5552b385SBrandon     for (PetscInt ii = cStart; ii < cEnd; ++ii) {
29*5552b385SBrandon       PetscCall(DMLabelGetValue(faceLabel, ii, &faceID));
30*5552b385SBrandon       if (faceID >= 0) {
31*5552b385SBrandon         PetscCall(DMPlexComputeCellGeometryFVM(dm, ii, &vol, centroid, normal));
32*5552b385SBrandon         surfaceArea += vol;
33*5552b385SBrandon       }
34*5552b385SBrandon     }
35*5552b385SBrandon   }
36*5552b385SBrandon 
37*5552b385SBrandon   if (dim == 3) {
38*5552b385SBrandon     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
39*5552b385SBrandon     for (PetscInt ii = fStart; ii < fEnd; ++ii) {
40*5552b385SBrandon       PetscCall(DMLabelGetValue(faceLabel, ii, &faceID));
41*5552b385SBrandon       if (faceID >= 0) {
42*5552b385SBrandon         PetscCall(DMPlexComputeCellGeometryFVM(dm, ii, &vol, centroid, normal));
43*5552b385SBrandon         surfaceArea += vol;
44*5552b385SBrandon       }
45*5552b385SBrandon     }
46*5552b385SBrandon 
47*5552b385SBrandon     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
48*5552b385SBrandon     for (PetscInt ii = cStart; ii < cEnd; ++ii) {
49*5552b385SBrandon       PetscCall(DMLabelGetValue(bodyLabel, ii, &bodyID));
50*5552b385SBrandon       if (bodyID >= 0) {
51*5552b385SBrandon         PetscCall(DMPlexComputeCellGeometryFVM(dm, ii, &vol, centroid, normal));
52*5552b385SBrandon         volume += vol;
53*5552b385SBrandon       }
54*5552b385SBrandon     }
55*5552b385SBrandon   }
56*5552b385SBrandon 
57*5552b385SBrandon   if (dim == 2) {
58*5552b385SBrandon     PetscCall(PetscPrintf(comm, "%s Surface Area = %.6e \n\n", name, (double)surfaceArea));
59*5552b385SBrandon   } else if (dim == 3) {
60*5552b385SBrandon     PetscCall(PetscPrintf(comm, "%s Volume = %.6e \n", name, (double)volume));
61*5552b385SBrandon     PetscCall(PetscPrintf(comm, "%s Surface Area = %.6e \n\n", name, (double)surfaceArea));
62*5552b385SBrandon   }
63*5552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
64*5552b385SBrandon }
65*5552b385SBrandon 
66*5552b385SBrandon int main(int argc, char *argv[])
67*5552b385SBrandon {
68*5552b385SBrandon   /* EGADSlite variables */
69*5552b385SBrandon   PetscGeom model, *bodies, *fobjs;
70*5552b385SBrandon   int       Nb, Nf, id;
71*5552b385SBrandon   /* PETSc variables */
72*5552b385SBrandon   DM             dm;
73*5552b385SBrandon   MPI_Comm       comm;
74*5552b385SBrandon   PetscContainer modelObj, cpHashTableObj, wHashTableObj, cpCoordDataLengthObj, wDataLengthObj;
75*5552b385SBrandon   Vec            cntrlPtCoordsVec, cntrlPtWeightsVec;
76*5552b385SBrandon   PetscScalar   *cpCoordData, *wData;
77*5552b385SBrandon   PetscInt       cpCoordDataLength, wDataLength;
78*5552b385SBrandon   PetscInt      *cpCoordDataLengthPtr, *wDataLengthPtr;
79*5552b385SBrandon   PetscHMapI     cpHashTable, wHashTable;
80*5552b385SBrandon   PetscInt       Nr = 2;
81*5552b385SBrandon 
82*5552b385SBrandon   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
83*5552b385SBrandon   comm = PETSC_COMM_WORLD;
84*5552b385SBrandon   PetscCall(DMCreate(PETSC_COMM_WORLD, &dm));
85*5552b385SBrandon   PetscCall(DMSetType(dm, DMPLEX));
86*5552b385SBrandon   PetscCall(DMPlexDistributeSetDefault(dm, PETSC_FALSE));
87*5552b385SBrandon   PetscCall(DMSetFromOptions(dm));
88*5552b385SBrandon 
89*5552b385SBrandon   PetscCall(PetscObjectSetName((PetscObject)dm, "Original Surface"));
90*5552b385SBrandon   PetscCall(DMViewFromOptions(dm, NULL, "-dm_view"));
91*5552b385SBrandon   PetscCall(surfArea(dm));
92*5552b385SBrandon 
93*5552b385SBrandon   // Expose Geometry Definition Data and Calculate Surface Gradients
94*5552b385SBrandon   PetscCall(DMPlexGeomDataAndGrads(dm, PETSC_FALSE));
95*5552b385SBrandon 
96*5552b385SBrandon   // Get Attached EGADS model
97*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", (PetscObject *)&modelObj));
98*5552b385SBrandon   if (!modelObj) PetscCall(PetscObjectQuery((PetscObject)dm, "EGADSlite Model", (PetscObject *)&modelObj));
99*5552b385SBrandon 
100*5552b385SBrandon   // Get attached EGADS model (pointer)
101*5552b385SBrandon   PetscCall(PetscContainerGetPointer(modelObj, (void **)&model));
102*5552b385SBrandon 
103*5552b385SBrandon   // Look to see if DM has Container for Geometry Control Point Data
104*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Hash Table", (PetscObject *)&cpHashTableObj));
105*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinates", (PetscObject *)&cntrlPtCoordsVec));
106*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Coordinate Data Length", (PetscObject *)&cpCoordDataLengthObj));
107*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weights Hash Table", (PetscObject *)&wHashTableObj));
108*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data", (PetscObject *)&cntrlPtWeightsVec));
109*5552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "Control Point Weight Data Length", (PetscObject *)&wDataLengthObj));
110*5552b385SBrandon 
111*5552b385SBrandon   // Get attached EGADS model Control Point and Weights Hash Tables and Data Arrays (pointer)
112*5552b385SBrandon   PetscCall(PetscContainerGetPointer(cpHashTableObj, (void **)&cpHashTable));
113*5552b385SBrandon   PetscCall(VecGetArrayWrite(cntrlPtCoordsVec, &cpCoordData));
114*5552b385SBrandon   PetscCall(PetscContainerGetPointer(cpCoordDataLengthObj, (void **)&cpCoordDataLengthPtr));
115*5552b385SBrandon   PetscCall(PetscContainerGetPointer(wHashTableObj, (void **)&wHashTable));
116*5552b385SBrandon   PetscCall(VecGetArrayWrite(cntrlPtWeightsVec, &wData));
117*5552b385SBrandon   PetscCall(PetscContainerGetPointer(wDataLengthObj, (void **)&wDataLengthPtr));
118*5552b385SBrandon 
119*5552b385SBrandon   cpCoordDataLength = *cpCoordDataLengthPtr;
120*5552b385SBrandon   wDataLength       = *wDataLengthPtr;
121*5552b385SBrandon   PetscCheck(cpCoordDataLength && wDataLength, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Data sizes must be positive");
122*5552b385SBrandon 
123*5552b385SBrandon   // Get the number of bodies and body objects in the model
124*5552b385SBrandon   PetscCall(DMPlexGetGeomModelBodies(dm, &bodies, &Nb));
125*5552b385SBrandon 
126*5552b385SBrandon   // Get all FACES of the Body
127*5552b385SBrandon   PetscGeom body = bodies[0];
128*5552b385SBrandon   PetscCall(DMPlexGetGeomModelBodyFaces(dm, body, &fobjs, &Nf));
129*5552b385SBrandon 
130*5552b385SBrandon   // Update Control Point and Weight definitions for each surface
131*5552b385SBrandon   for (PetscInt jj = 0; jj < Nf; ++jj) {
132*5552b385SBrandon     PetscGeom face         = fobjs[jj];
133*5552b385SBrandon     PetscInt  numCntrlPnts = 0;
134*5552b385SBrandon 
135*5552b385SBrandon     PetscCall(DMPlexGetGeomID(dm, body, face, &id));
136*5552b385SBrandon     PetscCall(DMPlexGetGeomFaceNumOfControlPoints(dm, face, &numCntrlPnts));
137*5552b385SBrandon 
138*5552b385SBrandon     // Update Control Points
139*5552b385SBrandon     PetscHashIter CPiter, Witer;
140*5552b385SBrandon     PetscBool     CPfound, Wfound;
141*5552b385SBrandon     PetscInt      faceCPStartRow, faceWStartRow;
142*5552b385SBrandon 
143*5552b385SBrandon     PetscCall(PetscHMapIFind(cpHashTable, id, &CPiter, &CPfound));
144*5552b385SBrandon     PetscCheck(CPfound, comm, PETSC_ERR_SUP, "FACE ID not found in Control Point Hash Table");
145*5552b385SBrandon     PetscCall(PetscHMapIGet(cpHashTable, id, &faceCPStartRow));
146*5552b385SBrandon 
147*5552b385SBrandon     PetscCall(PetscHMapIFind(wHashTable, id, &Witer, &Wfound));
148*5552b385SBrandon     PetscCheck(Wfound, comm, PETSC_ERR_SUP, "FACE ID not found in Control Point Weights Hash Table");
149*5552b385SBrandon     PetscCall(PetscHMapIGet(wHashTable, id, &faceWStartRow));
150*5552b385SBrandon 
151*5552b385SBrandon     for (PetscInt ii = 0; ii < numCntrlPnts; ++ii) {
152*5552b385SBrandon       if (ii == 4) {
153*5552b385SBrandon         // Update Control Points - Change the location of the center control point of the faces
154*5552b385SBrandon         // Note :: Modification geometry requires knowledge of how the geometry is defined.
155*5552b385SBrandon         cpCoordData[faceCPStartRow + (3 * ii) + 0] = 2.0 * cpCoordData[faceCPStartRow + (3 * ii) + 0];
156*5552b385SBrandon         cpCoordData[faceCPStartRow + (3 * ii) + 1] = 2.0 * cpCoordData[faceCPStartRow + (3 * ii) + 1];
157*5552b385SBrandon         cpCoordData[faceCPStartRow + (3 * ii) + 2] = 2.0 * cpCoordData[faceCPStartRow + (3 * ii) + 2];
158*5552b385SBrandon       } else {
159*5552b385SBrandon         // Do Nothing
160*5552b385SBrandon         // Note: Could use section the change location of other face control points.
161*5552b385SBrandon       }
162*5552b385SBrandon     }
163*5552b385SBrandon   }
164*5552b385SBrandon   PetscCall(DMPlexFreeGeomObject(dm, fobjs));
165*5552b385SBrandon 
166*5552b385SBrandon   // Modify Control Points of Geometry
167*5552b385SBrandon   PetscCall(PetscObjectSetName((PetscObject)dm, "Modified Surface"));
168*5552b385SBrandon   // TODO Wrap EG_saveModel() in a Plex viewer to manage file access
169*5552b385SBrandon   PetscCall(DMPlexModifyGeomModel(dm, comm, cpCoordData, wData, PETSC_FALSE, PETSC_TRUE, "newModel.stp"));
170*5552b385SBrandon   PetscCall(VecRestoreArrayWrite(cntrlPtCoordsVec, &cpCoordData));
171*5552b385SBrandon   PetscCall(VecRestoreArrayWrite(cntrlPtWeightsVec, &wData));
172*5552b385SBrandon 
173*5552b385SBrandon   // Inflate Mesh to Geometry
174*5552b385SBrandon   PetscCall(DMPlexInflateToGeomModel(dm, PETSC_FALSE));
175*5552b385SBrandon   PetscCall(surfArea(dm));
176*5552b385SBrandon 
177*5552b385SBrandon   // Output .hdf5 file
178*5552b385SBrandon   PetscCall(DMViewFromOptions(dm, NULL, "-dm_view"));
179*5552b385SBrandon 
180*5552b385SBrandon   for (PetscInt r = 0; r < Nr; ++r) {
181*5552b385SBrandon     char name[PETSC_MAX_PATH_LEN];
182*5552b385SBrandon 
183*5552b385SBrandon     // Perform refinement on the Mesh attached to the new geometry
184*5552b385SBrandon     PetscCall(DMSetFromOptions(dm));
185*5552b385SBrandon     PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN, "Modified Surface refinement %" PetscInt_FMT, r));
186*5552b385SBrandon     PetscCall(PetscObjectSetName((PetscObject)dm, name));
187*5552b385SBrandon     PetscCall(DMViewFromOptions(dm, NULL, "-dm_view"));
188*5552b385SBrandon     PetscCall(surfArea(dm));
189*5552b385SBrandon   }
190*5552b385SBrandon 
191*5552b385SBrandon   PetscCall(DMDestroy(&dm));
192*5552b385SBrandon   PetscCall(PetscFinalize());
193*5552b385SBrandon   return 0;
194*5552b385SBrandon }
195*5552b385SBrandon 
196*5552b385SBrandon /*TEST
197*5552b385SBrandon   build:
198*5552b385SBrandon     requires: egads
199*5552b385SBrandon 
200*5552b385SBrandon   # Use -dm_view hdf5:mesh_shapeMod_sphere.h5 to view the mesh
201*5552b385SBrandon   test:
202*5552b385SBrandon     suffix: sphere_shapeMod
203*5552b385SBrandon     requires: datafilespath
204*5552b385SBrandon     temporaries: newModel.stp
205*5552b385SBrandon     args: -dm_plex_filename ${DATAFILESPATH}/meshes/cad/sphere_example.stp \
206*5552b385SBrandon           -dm_refine -dm_plex_geom_print_model 1 -dm_plex_geom_shape_opt 1
207*5552b385SBrandon 
208*5552b385SBrandon TEST*/
209