xref: /petsc/src/dm/impls/plex/plexexodusii.c (revision 3e1910f1ab6113d8365e15c6b8c907ccce7ce4ea)
1 #define PETSCDM_DLL
2 #include <petsc-private/dmpleximpl.h>    /*I   "petscdmplex.h"   I*/
3 
4 #if defined(PETSC_HAVE_EXODUSII)
5 #include <netcdf.h>
6 #include <exodusII.h>
7 #endif
8 
9 #undef __FUNCT__
10 #define __FUNCT__ "DMPlexCreateExodus"
11 /*@
12   DMPlexCreateExodus - Create a DMPlex mesh from an ExodusII file.
13 
14   Collective on comm
15 
16   Input Parameters:
17 + comm  - The MPI communicator
18 . exoid - The ExodusII id associated with a exodus file and obtained using ex_open
19 - interpolate - Create faces and edges in the mesh
20 
21   Output Parameter:
22 . dm  - The DM object representing the mesh
23 
24   Level: beginner
25 
26 .keywords: mesh,ExodusII
27 .seealso: MeshCreate(), MeshCreateExodus()
28 @*/
29 PetscErrorCode DMPlexCreateExodus(MPI_Comm comm, PetscInt exoid, PetscBool interpolate, DM *dm)
30 {
31 #if defined(PETSC_HAVE_EXODUSII)
32   PetscMPIInt    num_proc, rank;
33   PetscSection   coordSection;
34   Vec            coordinates;
35   PetscScalar    *coords;
36   PetscInt       coordSize, v;
37   PetscErrorCode ierr;
38   /* Read from ex_get_init() */
39   char title[PETSC_MAX_PATH_LEN+1];
40   int  dim    = 0, numVertices = 0, numCells = 0;
41   int  num_cs = 0, num_vs = 0, num_fs = 0;
42 #endif
43 
44   PetscFunctionBegin;
45 #if defined(PETSC_HAVE_EXODUSII)
46   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
47   ierr = MPI_Comm_size(comm, &num_proc);CHKERRQ(ierr);
48   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
49   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
50   /* Open EXODUS II file and read basic informations on rank 0, then broadcast to all processors */
51   if (!rank) {
52     ierr = ex_get_init(exoid, title, &dim, &numVertices, &numCells, &num_cs, &num_vs, &num_fs);
53     if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"ExodusII ex_get_init() failed with error code %D\n",ierr);
54     if (!num_cs) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Exodus file does not contain any cell set\n");
55   }
56   ierr = MPI_Bcast(title, PETSC_MAX_PATH_LEN+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
57   ierr = MPI_Bcast(&dim, 1, MPI_INT, 0, comm);CHKERRQ(ierr);
58   ierr = PetscObjectSetName((PetscObject) *dm, title);CHKERRQ(ierr);
59   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
60   ierr = DMPlexSetChart(*dm, 0, numCells+numVertices);CHKERRQ(ierr);
61 
62   /* Read cell sets information */
63   if (!rank) {
64     PetscInt *cone;
65     int      c, cs, c_loc, v, v_loc;
66     /* Read from ex_get_elem_blk_ids() */
67     int *cs_id;
68     /* Read from ex_get_elem_block() */
69     char buffer[PETSC_MAX_PATH_LEN+1];
70     int  num_cell_in_set, num_vertex_per_cell, num_attr;
71     /* Read from ex_get_elem_conn() */
72     int *cs_connect;
73 
74     /* Get cell sets IDs */
75     ierr = PetscMalloc(num_cs * sizeof(int), &cs_id);CHKERRQ(ierr);
76     ierr = ex_get_elem_blk_ids(exoid, cs_id);CHKERRQ(ierr);
77     /* Read the cell set connectivity table and build mesh topology
78        EXO standard requires that cells in cell sets be numbered sequentially and be pairwise disjoint. */
79     /* First set sizes */
80     for (cs = 0, c = 0; cs < num_cs; cs++) {
81       ierr = ex_get_elem_block(exoid, cs_id[cs], buffer, &num_cell_in_set, &num_vertex_per_cell, &num_attr);CHKERRQ(ierr);
82       for (c_loc = 0; c_loc < num_cell_in_set; ++c_loc, ++c) {
83         ierr = DMPlexSetConeSize(*dm, c, num_vertex_per_cell);CHKERRQ(ierr);
84       }
85     }
86     ierr = DMSetUp(*dm);CHKERRQ(ierr);
87     for (cs = 0, c = 0; cs < num_cs; cs++) {
88       ierr = ex_get_elem_block(exoid, cs_id[cs], buffer, &num_cell_in_set, &num_vertex_per_cell, &num_attr);CHKERRQ(ierr);
89       ierr = PetscMalloc2(num_vertex_per_cell*num_cell_in_set,int,&cs_connect,num_vertex_per_cell,PetscInt,&cone);CHKERRQ(ierr);
90       ierr = ex_get_elem_conn(exoid, cs_id[cs], cs_connect);CHKERRQ(ierr);
91       /* EXO uses Fortran-based indexing, sieve uses C-style and numbers cell first then vertices. */
92       for (c_loc = 0, v = 0; c_loc < num_cell_in_set; ++c_loc, ++c) {
93         for (v_loc = 0; v_loc < num_vertex_per_cell; ++v_loc, ++v) {
94           cone[v_loc] = cs_connect[v]+numCells-1;
95         }
96         ierr = DMPlexSetCone(*dm, c, cone);CHKERRQ(ierr);
97         ierr = DMPlexSetLabelValue(*dm, "Cell Sets", c, cs_id[cs]);CHKERRQ(ierr);
98       }
99       ierr = PetscFree2(cs_connect,cone);CHKERRQ(ierr);
100     }
101     ierr = PetscFree(cs_id);CHKERRQ(ierr);
102   }
103   ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
104   ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
105   if (interpolate) {
106     DM idm;
107 
108     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
109     /* Maintain Cell Sets label */
110     {
111       DMLabel label;
112 
113       ierr = DMPlexRemoveLabel(*dm, "Cell Sets", &label);CHKERRQ(ierr);
114       if (label) {ierr = DMPlexAddLabel(idm, label);CHKERRQ(ierr);}
115     }
116     ierr = DMDestroy(dm);CHKERRQ(ierr);
117     *dm  = idm;
118   }
119 
120   /* Create vertex set label */
121   if (!rank && (num_vs > 0)) {
122     int vs, v;
123     /* Read from ex_get_node_set_ids() */
124     int *vs_id;
125     /* Read from ex_get_node_set_param() */
126     int num_vertex_in_set, num_attr;
127     /* Read from ex_get_node_set() */
128     int *vs_vertex_list;
129 
130     /* Get vertex set ids */
131     ierr = PetscMalloc(num_vs * sizeof(int), &vs_id);CHKERRQ(ierr);
132     ierr = ex_get_node_set_ids(exoid, vs_id);CHKERRQ(ierr);
133     for (vs = 0; vs < num_vs; ++vs) {
134       ierr = ex_get_node_set_param(exoid, vs_id[vs], &num_vertex_in_set, &num_attr);CHKERRQ(ierr);
135       ierr = PetscMalloc(num_vertex_in_set * sizeof(int), &vs_vertex_list);CHKERRQ(ierr);
136       ierr = ex_get_node_set(exoid, vs_id[vs], vs_vertex_list);CHKERRQ(ierr);
137       for (v = 0; v < num_vertex_in_set; ++v) {
138         ierr = DMPlexSetLabelValue(*dm, "Vertex Sets", vs_vertex_list[v]+numCells-1, vs_id[vs]);CHKERRQ(ierr);
139       }
140       ierr = PetscFree(vs_vertex_list);CHKERRQ(ierr);
141     }
142     ierr = PetscFree(vs_id);CHKERRQ(ierr);
143   }
144   /* Read coordinates */
145   ierr = DMPlexGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
146   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
147   ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr);
148   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
149   for (v = numCells; v < numCells+numVertices; ++v) {
150     ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
151     ierr = PetscSectionSetFieldDof(coordSection, v, 0, dim);CHKERRQ(ierr);
152   }
153   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
154   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
155   ierr = VecCreate(comm, &coordinates);CHKERRQ(ierr);
156   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
157   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
158   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
159   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
160   if (!rank) {
161     float *x, *y, *z;
162 
163     ierr = PetscMalloc3(numVertices,float,&x,numVertices,float,&y,numVertices,float,&z);CHKERRQ(ierr);
164     ierr = ex_get_coord(exoid, x, y, z);CHKERRQ(ierr);
165     if (dim > 0) {
166       for (v = 0; v < numVertices; ++v) coords[v*dim+0] = x[v];
167     }
168     if (dim > 1) {
169       for (v = 0; v < numVertices; ++v) coords[v*dim+1] = y[v];
170     }
171     if (dim > 2) {
172       for (v = 0; v < numVertices; ++v) coords[v*dim+2] = z[v];
173     }
174     ierr = PetscFree3(x,y,z);CHKERRQ(ierr);
175   }
176   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
177   ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
178   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
179 
180   /* Create side set label */
181   if (!rank && interpolate && (num_fs > 0)) {
182     int fs, f, voff;
183     /* Read from ex_get_side_set_ids() */
184     int *fs_id;
185     /* Read from ex_get_side_set_param() */
186     int num_side_in_set, num_dist_fact_in_set;
187     /* Read from ex_get_side_set_node_list() */
188     int *fs_vertex_count_list, *fs_vertex_list;
189 
190     /* Get side set ids */
191     ierr = PetscMalloc(num_fs * sizeof(int), &fs_id);CHKERRQ(ierr);
192     ierr = ex_get_side_set_ids(exoid, fs_id);CHKERRQ(ierr);
193     for (fs = 0; fs < num_fs; ++fs) {
194       ierr = ex_get_side_set_param(exoid, fs_id[fs], &num_side_in_set, &num_dist_fact_in_set);CHKERRQ(ierr);
195       ierr = PetscMalloc2(num_side_in_set,int,&fs_vertex_count_list,num_side_in_set*4,int,&fs_vertex_list);CHKERRQ(ierr);
196       ierr = ex_get_side_set_node_list(exoid, fs_id[fs], fs_vertex_count_list, fs_vertex_list);CHKERRQ(ierr);
197       for (f = 0, voff = 0; f < num_side_in_set; ++f) {
198         const PetscInt *faces   = NULL;
199         PetscInt       faceSize = fs_vertex_count_list[f], numFaces;
200         PetscInt       faceVertices[4], v;
201 
202         if (faceSize > 4) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "ExodusII side cannot have %d > 4 vertices", faceSize);
203         for (v = 0; v < faceSize; ++v, ++voff) {
204           faceVertices[v] = fs_vertex_list[voff]+numCells-1;
205         }
206         ierr = DMPlexGetFullJoin(*dm, faceSize, faceVertices, &numFaces, &faces);CHKERRQ(ierr);
207         if (numFaces != 1) SETERRQ3(comm, PETSC_ERR_ARG_WRONG, "Invalid ExodusII side %d in set %d maps to %d faces", f, fs, numFaces);
208         ierr = DMPlexSetLabelValue(*dm, "Face Sets", faces[0], fs_id[fs]);CHKERRQ(ierr);
209         ierr = DMPlexRestoreJoin(*dm, faceSize, faceVertices, &numFaces, &faces);CHKERRQ(ierr);
210       }
211       ierr = PetscFree2(fs_vertex_count_list,fs_vertex_list);CHKERRQ(ierr);
212     }
213     ierr = PetscFree(fs_id);CHKERRQ(ierr);
214   }
215 #else
216   SETERRQ(comm, PETSC_ERR_SUP, "This method requires ExodusII support. Reconfigure using --download-exodusii");
217 #endif
218   PetscFunctionReturn(0);
219 }
220