Chi-Tech
chi_meshcontinuum_exportexodus.cc
Go to the documentation of this file.
1#include "chi_meshcontinuum.h"
2
6
7#include <vtkUnstructuredGrid.h>
8#include <vtkMultiBlockDataSet.h>
9
10#include <vtkInformation.h>
11#include <vtkModelMetadata.h>
12
13#include <vtkExodusIIWriter.h>
14
15#include <vtkPointData.h>
16#include <vtkCellData.h>
17
18#include "chi_runtime.h"
19#include "chi_log.h"
20
21#define scvtkid static_cast<vtkIdType>
22
23//###################################################################
24/**Exports just the portion of the mesh to ExodusII format.*/
26 ExportCellsToExodus(const std::string& file_base_name,
27 bool suppress_node_sets/*= false*/,
28 bool suppress_side_sets/*= false*/) const
29{
30 const std::string fname = "chi_mesh::MeshContinuum::ExportCellsToExodus";
31 Chi::log.Log() << "Exporting mesh to Exodus file with base " << file_base_name;
32
33 if (Chi::mpi.process_count != 1)
34 throw std::logic_error(fname + ": Currently this routine is only allowed "
35 "in serial.");
36
37 const auto& grid = *this;
38
39 //============================================= Check block consistency
40 std::map<int, chi_mesh::CellType> block_id_map;
41 for (const auto& cell : local_cells)
42 {
43 const int mat_id = cell.material_id_;
44 if (block_id_map.count(mat_id) == 0)
45 block_id_map[mat_id] = cell.SubType();
46 else
47 {
48 if (cell.SubType() != block_id_map.at(mat_id))
49 throw std::logic_error(fname + ": Material id " +
50 std::to_string(mat_id) + " appearing for more "
51 "than one cell type.");
52 }
53 }
54
55 //============================================= Create unstructured meshes
56 // for each material-type pair
58 int max_dimension = 0;
59 {
61 vtkNew<vtkPoints> points;
62
63 points->SetDataType(VTK_DOUBLE);
64
65 vtkNew<vtkIdTypeArray> global_node_id_list;
66 global_node_id_list->SetName("GlobalNodeId");
67
68 vtkNew<vtkIdTypeArray> global_elem_id_list;
69 global_elem_id_list->SetName("GlobalElementId");
70
71 vtkNew<vtkIntArray> block_id_list;
72 block_id_list->SetName("BlockID");
73
74 //============================ Load vertices
75 std::vector<uint64_t> vertex_map(grid.GetGlobalVertexCount(), 0);
76 const size_t num_verts = grid.GetGlobalVertexCount();
77 for (size_t v=0; v<num_verts; ++v)
78 {
79 vertex_map[v] = v;
80 const auto& vertex = grid.vertices[v];
81 points->InsertNextPoint(vertex.x,vertex.y,vertex.z);
82
83 //Exodus node- and cell indices are 1-based
84 //therefore we add a 1 here.
85 global_node_id_list->InsertNextValue(scvtkid(v+1));
86 }
87
88 //============================ Load cells
89 for (const auto& cell : grid.local_cells)
90 {
91 if (cell.SubType() == CellType::POLYGON or
92 cell.SubType() == CellType::POLYHEDRON)
93 throw std::logic_error(fname + ": Cell-subtype \"" +
94 chi_mesh::CellTypeName(cell.SubType()) + "\" encountered that is not"
95 "supported by exodus.");
96 chi_mesh::UploadCellGeometryContinuous(cell, vertex_map, ugrid);
97 block_id_list->InsertNextValue(cell.material_id_);
98 max_dimension =
99 std::max(max_dimension,MeshContinuum::GetCellDimension(cell));
100
101 //Exodus node- and cell indices are 1-based
102 //therefore we add a 1 here.
103 global_elem_id_list->InsertNextValue(scvtkid(cell.global_id_+1));
104 }//for local cells
105
106 //============================ Set arrays
107 ugrid->SetPoints(points);
108 ugrid->GetPointData()->AddArray(global_node_id_list);
109 ugrid->GetCellData()->AddArray(global_elem_id_list);
110 ugrid->GetCellData()->AddArray(block_id_list);
111
112 ugrid->GetPointData()->SetActiveGlobalIds("GlobalNodeId");
113 ugrid->GetCellData()->SetActiveGlobalIds("GlobalElementId");
114
115 //============================ Set block
116 grid_blocks->SetBlock(0, ugrid);
117
118 Chi::log.Log()
119 << "Writing grid block "
120 << " Number of cells: " << ugrid->GetNumberOfCells()
121 << " Number of points: " << ugrid->GetNumberOfPoints();
122 }//end of grid_blocks assignment
123
124 //============================================= Separate faces by boundary
125 // id
126 struct FaceInfo
127 {
128 chi_mesh::CellFace const* face_ptr;
129 uint64_t source_cell_id;
130 int source_face_id;
131 };
132 typedef std::vector<FaceInfo> ListOfFaces;
133 std::map<uint64_t, ListOfFaces> boundary_id_faces_map;
134 for (const auto& cell : grid.local_cells)
135 {
136 //Here we build a face mapping because ChiTech's face orientation
137 //for prisms (wedges) and hexahedrons differ from that of VTK.
138 //ChiTech's orientation for prisms and hexes actually matches that
139 //of Exodus but VTK assumes the incoming mesh to be conformant to
140 //VTK and therefore, internally performs a mapping. Fortunately,
141 //the only relevant cell-types, for which a special mapping is
142 //required, are the prisms and hexes.
143 const size_t num_faces = cell.faces_.size();
144 std::vector<int> face_mapping(num_faces, 0);
145 if (cell.SubType() == CellType::WEDGE)
146 face_mapping = { 2, 3, 4, 0, 1 };
147 else if (cell.SubType() == CellType::HEXAHEDRON)
148 face_mapping = { 2, 1, 3, 0, 4, 5 };
149 else
150 {
151 for (size_t f=0; f<cell.faces_.size(); ++f)
152 face_mapping[f] = static_cast<int>(f);
153 }
154
155 //Here we store face information as a triplet, i.e., a face pointer,
156 //the id of the cell owning it, and the local face index (relative to
157 //the cell) of the face.
158 int f=0;
159 for (const auto& face : cell.faces_)
160 {
161 if (not face.has_neighbor_)
162 boundary_id_faces_map[face.neighbor_id_].push_back(
163 {&face,cell.global_id_,face_mapping[f]});
164 ++f;
165 }
166 }
167
168 //============================================= Make NodeSets and/or SideSets
169 vtkNew<vtkMultiBlockDataSet> nodesets_blocks;
170 vtkNew<vtkMultiBlockDataSet> sidesets_blocks;
171 for (const auto& [bndry_id, face_list] : boundary_id_faces_map)
172 {
173 const std::string block_name = grid.GetBoundaryIDMap().at(bndry_id);
174 Chi::log.Log0Verbose1() << "bid: " + std::to_string(bndry_id) +
175 " name=\"" + block_name + "\"";
176
177 //====================================== NodeSet
178 {
180 vtkNew<vtkPoints> points;
181
182 points->SetDataType(VTK_DOUBLE);
183
184 vtkNew<vtkIdTypeArray> node_global_ids;
185 node_global_ids->SetName("GlobalNodeId");
186
187 //========================== Build vertex set
188 std::set<uint64_t> vid_set;
189 for (const auto& face_info : face_list)
190 for (uint64_t vid : face_info.face_ptr->vertex_ids_)
191 vid_set.insert(vid);
192
193 //========================== Build vertex map
194 std::vector<uint64_t> vertex_map(grid.GetGlobalVertexCount(), 0);
195 {
196 uint64_t mapped_id = 0;
197 for (uint64_t vid : vid_set)
198 vertex_map[vid] = mapped_id++;
199 }
200
201 //========================== Load vertices
202 for (uint64_t vid : vid_set)
203 {
204 const auto& vertex = grid.vertices[vid];
205 points->InsertNextPoint(vertex.x,vertex.y,vertex.z);
206
207 //Exodus node- and cell indices are 1-based
208 //therefore we add a 1 here.
209 node_global_ids->InsertNextValue(scvtkid(vid+1));
210 }
211
212 //========================== Load cells
213 for (uint64_t vid : vid_set)
214 {
215 std::vector<vtkIdType> cell_vids = {scvtkid(vertex_map[vid])};
216 ugrid->InsertNextCell(VTK_VERTEX,
217 scvtkid(1),
218 cell_vids.data());
219 }
220
221 ugrid->SetPoints(points);
222 ugrid->GetPointData()->AddArray(node_global_ids);
223
224 ugrid->GetPointData()->SetActiveGlobalIds("GlobalNodeId");
225
226 nodesets_blocks->SetBlock(bndry_id, ugrid);
227 nodesets_blocks->GetMetaData(bndry_id)->
228 Set(vtkCompositeDataSet::NAME(), block_name);
229
230 Chi::log.Log()
231 << "Writing nodeset block " << block_name
232 << " Number of cells: " << ugrid->GetNumberOfCells()
233 << " Number of points: " << ugrid->GetNumberOfPoints();
234 }
235
236 //====================================== SideSet
237 {
239 vtkNew<vtkPoints> points;
240
241 points->SetDataType(VTK_DOUBLE);
242
243 vtkNew<vtkIdTypeArray> src_cell_global_ids;
244 vtkNew<vtkIntArray> src_cell_face_id;
245 src_cell_global_ids->SetName("SourceElementId");
246 src_cell_face_id->SetName("SourceElementSide");
247
248 //========================== Build vertex set
249 std::set<uint64_t> vid_set;
250 for (const auto& face_info : face_list)
251 for (uint64_t vid : face_info.face_ptr->vertex_ids_)
252 vid_set.insert(vid);
253
254 //========================== Build vertex map
255 std::vector<uint64_t> vertex_map(grid.GetGlobalVertexCount(), 0);
256 {
257 uint64_t mapped_id = 0;
258 for (uint64_t vid : vid_set)
259 vertex_map[vid] = mapped_id++;
260 }
261
262 //========================== Load vertices
263 for (uint64_t vid : vid_set)
264 {
265 const auto& vertex = grid.vertices[vid];
266 points->InsertNextPoint(vertex.x,vertex.y,vertex.z);
267 }
268
269 //========================== Load faces
270 for (const auto& face_info : face_list)
271 {
272 UploadFaceGeometry(*face_info.face_ptr, vertex_map, ugrid);
273 src_cell_global_ids->InsertNextValue(scvtkid(face_info.source_cell_id));
274 src_cell_face_id->InsertNextValue(face_info.source_face_id);
275 }
276
277 ugrid->SetPoints(points);
278 ugrid->GetCellData()->AddArray(src_cell_global_ids);
279 ugrid->GetCellData()->AddArray(src_cell_face_id);
280
281 sidesets_blocks->SetBlock(bndry_id, ugrid);
282 sidesets_blocks->GetMetaData(bndry_id)->
283 Set(vtkCompositeDataSet::NAME(), block_name);
284
285 Chi::log.Log()
286 << "Writing sideset block " << block_name
287 << " Number of cells: " << ugrid->GetNumberOfCells()
288 << " Number of points: " << ugrid->GetNumberOfPoints();
289 }//End of side-set
290 }
291
292 //============================================= Write the file
293 unsigned int next_block = 0;
295 main_block->SetBlock(next_block++, grid_blocks);
296 if (not suppress_node_sets)
297 {
298 Chi::log.Log0Verbose1() << "Exporting nodeset";
299 main_block->SetBlock(next_block, nodesets_blocks);
300 main_block->GetMetaData(next_block++)->Set(vtkCompositeDataSet::NAME(), "Node Sets");
301 }
302 if (not suppress_side_sets)
303 {
304 Chi::log.Log0Verbose1() << "Exporting sideset";
305 main_block->SetBlock(next_block, sidesets_blocks);
306 main_block->GetMetaData(next_block++)->Set(vtkCompositeDataSet::NAME(), "Side Sets");
307 }
308
310 writer->SetBlockIdArrayName("BlockID");
311
312 writer->SetFileName((file_base_name + ".e").c_str());
313 writer->SetStoreDoubles(1);
314
315 writer->SetInputData(main_block);
316
317 writer->WriteOutGlobalNodeIdArrayOff();
318 writer->WriteOutGlobalElementIdArrayOff();
319 writer->WriteOutBlockIdArrayOff();
320
321// The code below requires a VTK patch
322//
323// {
324// auto em_in = vtkModelMetadata::New();
325//
326// char **dimNames = new char *[3];
327// dimNames[0] = new char[]{"X"};
328// dimNames[1] = new char[]{"Y"};
329// dimNames[2] = new char[]{"Z"};
330//
331// max_dimension = std::min(max_dimension, 3);
332// chi::log.Log() << "Max dimension set to " << max_dimension;
333//
334// em_in->SetCoordinateNames(max_dimension, dimNames);
335//
336// writer->SetModelMetadata(em_in);
337// }
338
339 writer->Write();
340
341 auto em = writer->GetModelMetadata();
342
343 Chi::log.Log() << "Num Blocks : " << em->GetNumberOfBlocks();
344 Chi::log.Log() << "Num Node Sets: " << em->GetNumberOfNodeSets();
345 Chi::log.Log() << "Num Side Sets: " << em->GetNumberOfSideSets();
346 Chi::log.Log() << "Dimension : " << em->GetDimension();
347
348 //writer->PrintSelf(std::cout, vtkIndent());
349
350 Chi::log.Log() << "Done exporting mesh to exodus.";
352}
static chi::ChiLog & log
Definition: chi_runtime.h:81
static chi::MPI_Info & mpi
Definition: chi_runtime.h:78
LogStream Log(LOG_LVL level=LOG_0)
Definition: chi_log.cc:35
LogStream Log0Verbose1()
Definition: chi_log.h:234
void Barrier() const
Definition: mpi_info.cc:38
void ExportCellsToExodus(const std::string &file_base_name, bool suppress_node_sets=false, bool suppress_side_sets=false) const
LocalCellHandler local_cells
static int GetCellDimension(const chi_mesh::Cell &cell)
void Set(VecDbl &x, const double &val)
void UploadFaceGeometry(const chi_mesh::CellFace &cell_face, const std::vector< uint64_t > &vertex_map, vtkNew< vtkUnstructuredGrid > &ugrid)
void UploadCellGeometryContinuous(const chi_mesh::Cell &cell, const std::vector< uint64_t > &vertex_map, vtkNew< vtkUnstructuredGrid > &ugrid)
std::string CellTypeName(CellType type)
Definition: cell.cc:12