Chi-Tech
chi_grid_vtk_utils_01_reading.cc
Go to the documentation of this file.
2
3#include <vtkUnstructuredGrid.h>
4#include <vtkAppendFilter.h>
5
6#include <vtkCellData.h>
7#include <vtkPointData.h>
8
9#include "chi_runtime.h"
10#include "chi_log.h"
11
12// ###################################################################
13/**Finds the highest dimension across all the grid blocks. This
14 * is useful when a vtk-read mesh contains multiple blocks. Some of which
15 * are boundary faces.*/
17 std::vector<vtkUGridPtrAndName>& ugrid_blocks)
18{
19 int max_dim = 0;
20 for (auto& ugrid : ugrid_blocks)
21 {
22 const int64_t num_cells = ugrid.first->GetNumberOfCells();
23 for (int64_t c = 0; c < num_cells; ++c)
24 {
25 auto cell = ugrid.first->GetCell(c);
26 ChiLogicalErrorIf(not cell, "Failed to obtain VTK-cell pointer");
27 max_dim = std::max(max_dim, cell->GetCellDimension());
28 }
29 }// for ugrid in block
30
31 return max_dim;
32}
33
34// ###################################################################
35/**Consolidates all blocks containing cells with the desired dimension.
36 * Thereafter it removes duplicate vertices.*/
38 std::vector<vtkUGridPtrAndName>& ugrid_blocks,
39 const std::string& block_id_array_name /*="BlockID"*/)
40{
41 const std::string fname = "chi_mesh::ConsolidateGridBlocks";
42
43 //======================================== Determine if all blocks have
44 // global-ids
45 bool has_global_ids = true;
46 for (auto& ugrid_name : ugrid_blocks)
47 {
48 auto& ugrid = ugrid_name.first;
49 const bool has_cell_gids = ugrid->GetCellData()->GetGlobalIds();
50 const bool has_pnts_gids = ugrid->GetPointData()->GetGlobalIds();
51 const bool has_block_ids =
52 ugrid->GetCellData()->GetArray(block_id_array_name.c_str());
53
54 if ((not has_cell_gids) or (not has_pnts_gids)) has_global_ids = false;
55
56 if (not has_block_ids)
57 throw std::logic_error(fname + ": Grid block " + ugrid_name.second +
58 " does not have \"" + block_id_array_name +
59 "\" array.");
60 } // for grid_name pairs
61
62 if (has_global_ids)
63 Chi::log.Log() << fname << ": blocks have global-id arrays";
64
65 //======================================== Consolidate the blocks
67 for (auto& ugrid : ugrid_blocks)
68 append->AddInputData(ugrid.first);
69
70 append->MergePointsOn();
71 append->Update();
72
73 auto consolidated_ugrid = vtkSmartPointer<vtkUnstructuredGrid>(
74 vtkUnstructuredGrid::SafeDownCast(append->GetOutput()));
75
76 Chi::log.Log0Verbose1() << "Consolidated grid num cells and points: "
77 << consolidated_ugrid->GetNumberOfCells() << " "
78 << consolidated_ugrid->GetNumberOfPoints();
79
80 if (has_global_ids)
81 {
82 const vtkIdType num_points = consolidated_ugrid->GetNumberOfPoints();
83 vtkIdType min_id = num_points;
84 vtkIdType max_id = 0;
85 for (vtkIdType p = 0; p < num_points; ++p)
86 {
87 auto point_gids = vtkIdTypeArray::SafeDownCast(
88 consolidated_ugrid->GetPointData()->GetGlobalIds());
89 auto point_gid = point_gids->GetValue(p);
90
91 min_id = std::min(min_id, point_gid);
92 max_id = std::max(max_id, point_gid);
93 }
94
95 Chi::log.Log() << "Minimum and Maximum node-ids " << min_id << " "
96 << max_id;
97 }
98
99 std::map<std::string, size_t> cell_type_count_map;
100 const int64_t num_cells = consolidated_ugrid->GetNumberOfCells();
101 for (int64_t c = 0; c < num_cells; ++c)
102 {
103 auto cell = consolidated_ugrid->GetCell(c);
104 ChiLogicalErrorIf(not cell, "Failed to obtain VTK-cell pointer");
105
106 auto cell_type_name = cell->GetClassName();
107 cell_type_count_map[cell_type_name] += 1;
108 }
109
110 if (Chi::log.GetVerbosity() >= 1)
111 {
112 std::stringstream outstr;
113 /**Lambda to right pad an entry.*/
114 auto RightPad = [](std::string& entry, size_t width)
115 {
116 const size_t pad_size = width - entry.size();
117 entry.append(std::string(pad_size, ' '));
118 };
119
120 outstr << "Block statistictics:\n";
121 for (const auto& [type_name, count] : cell_type_count_map)
122 {
123 auto temp_name = type_name;
124 RightPad(temp_name, 20);
125 outstr << " " << temp_name << " " << count << "\n";
126 }
127 Chi::log.Log0Verbose1() << outstr.str();
128 }
129
130 return consolidated_ugrid;
131}
132
133// ###################################################################
134/**Provides a map of the different grids that have the
135 * requested dimension.*/
136std::vector<chi_mesh::vtkUGridPtrAndName> chi_mesh::GetBlocksOfDesiredDimension(
137 std::vector<vtkUGridPtrAndName>& ugrid_blocks, int desired_dimension)
138{
139 std::vector<chi_mesh::vtkUGridPtrAndName> desired_blocks;
140 for (auto& ugrid : ugrid_blocks)
141 {
142 if (ugrid.first->GetNumberOfCells() == 0) continue;
143
144 std::vector<vtkUGridPtrAndName> single_grid = {ugrid};
145 int block_dimension = chi_mesh::FindHighestDimension(single_grid);
146
147 if (block_dimension == desired_dimension)
148 desired_blocks.push_back(ugrid);
149 }
150
151 return desired_blocks;
152}
153
154// ###################################################################
155/**Given several unstructured grid blocks, each denoting a material id,
156 * this function sets material ids accordingly.*/
157std::vector<uint64_t>
158chi_mesh::BuildBlockCellExtents(std::vector<vtkUGridPtrAndName>& ugrid_blocks,
159 const int desired_dimension)
160{
161 std::vector<uint64_t> block_mat_ids;
162 size_t total_cells = 0;
163
164 for (auto& ugrid : ugrid_blocks)
165 {
166 uint64_t num_cells = ugrid.first->GetNumberOfCells();
167
168 if (num_cells == 0) continue;
169
170 if (ugrid.first->GetCell(0)->GetCellDimension() == desired_dimension)
171 {
172 total_cells += num_cells;
173 block_mat_ids.push_back(total_cells);
174 }
175 }
176 return block_mat_ids;
177}
178
179// ###################################################################
180/**Given several unstructured grid blocks, each denoting a material id,
181 * this function creates a VTK cell-data array called "BlockID" that holds
182 * this information.*/
183void chi_mesh::SetBlockIDArrays(std::vector<vtkUGridPtrAndName>& ugrid_blocks)
184{
185 int block_id = 0;
186 for (auto& ugrid : ugrid_blocks)
187 {
188 const vtkIdType num_cells = ugrid.first->GetNumberOfCells();
189
190 if (num_cells == 0) continue;
191
192 vtkNew<vtkIntArray> block_id_list;
193 block_id_list->SetName("BlockID");
194
195 for (vtkIdType c = 0; c < num_cells; ++c)
196 block_id_list->InsertNextValue(block_id);
197
198 auto arr = ugrid.first->GetCellData()->GetArray("BlockID");
199 if (not arr) ugrid.first->GetCellData()->RemoveArray("BlockID");
200
201 ugrid.first->GetCellData()->AddArray(block_id_list);
202 ++block_id;
203 }
204}
205
206// ###################################################################
207/**Retrieves material-ids from a field.*/
208std::vector<int>
210 const std::string& field_name,
211 const std::string& file_name)
212{
213 const size_t total_cell_count = ugrid->GetNumberOfCells();
214 std::vector<int> material_ids(total_cell_count, -1);
215
216 //======================================== Determine if reading
217 // cell identifiers
218 vtkDataArray* cell_id_array_ptr;
219 if (field_name.empty())
220 {
222 << "A user-supplied field name from which to recover material "
223 "identifiers "
224 << "has not been found. Material-ids will be left unassigned.";
225 goto end_error_checks;
226 }
227 else
228 {
229 auto cell_data = ugrid->GetCellData();
230 const auto vtk_abstract_array_ptr =
231 cell_data->GetAbstractArray(field_name.c_str());
232
233 if (!vtk_abstract_array_ptr)
234 {
236 << "The VTU file : \"" << file_name << "\" "
237 << "does not contain a vtkCellData field of name : \"" << field_name
238 << "\". Material-ids will be left unassigned.";
239 goto end_error_checks;
240 }
241
242 cell_id_array_ptr = vtkArrayDownCast<vtkDataArray>(vtk_abstract_array_ptr);
243 if (!cell_id_array_ptr)
244 {
246 << "The VTU file : \"" << file_name << "\" "
247 << "with vtkCellData field of name : \"" << field_name << "\" "
248 << "cannot be downcast to vtkDataArray. Material-ids will be left "
249 "unassigned.";
250 goto end_error_checks;
251 }
252
253 const auto cell_id_n_tup = cell_id_array_ptr->GetNumberOfTuples();
254 if (cell_id_n_tup != total_cell_count)
255 {
257 << "The VTU file : \"" << file_name << "\" "
258 << "with vtkCellData field of name : \"" << field_name
259 << "\" has n. tuples : " << cell_id_n_tup
260 << ", but differs from the value expected : " << total_cell_count
261 << ". Material-ids will be left unassigned.";
262 goto end_error_checks;
263 }
264
265 const auto cell_id_n_val = cell_id_array_ptr->GetNumberOfValues();
266 if (cell_id_n_val != total_cell_count)
267 {
269 << "The VTU file : \"" << file_name << "\" "
270 << "with vtkCellData field of name : \"" << field_name
271 << "\" has n. values : " << cell_id_n_val
272 << ", but differs from the value expected : " << total_cell_count
273 << ". Material-ids will be left unassigned.";
274 goto end_error_checks;
275 }
276 }
277
278 // apply cell identifier
279 for (size_t c = 0; c < total_cell_count; ++c)
280 {
281 std::vector<double> cell_id_vec(1);
282 cell_id_array_ptr->GetTuple(static_cast<vtkIdType>(c), cell_id_vec.data());
283 const auto mat_id = (int)cell_id_vec.front();
284
285 material_ids[c] = mat_id;
286 }
287
288end_error_checks:
289 return material_ids;
290}
#define ChiLogicalErrorIf(condition, message)
static chi::ChiLog & log
Definition: chi_runtime.h:81
LogStream Log0Warning()
Definition: chi_log.h:231
LogStream Log(LOG_LVL level=LOG_0)
Definition: chi_log.cc:35
LogStream Log0Verbose1()
Definition: chi_log.h:234
std::vector< int > BuildCellMaterialIDsFromField(vtkUGridPtr &ugrid, const std::string &field_name, const std::string &file_name)
std::vector< uint64_t > BuildBlockCellExtents(std::vector< vtkUGridPtrAndName > &ugrid_blocks, int desired_dimension)
vtkUGridPtr ConsolidateGridBlocks(std::vector< vtkUGridPtrAndName > &ugrid_blocks, const std::string &block_id_array_name="BlockID")
void SetBlockIDArrays(std::vector< vtkUGridPtrAndName > &ugrid_blocks)
int FindHighestDimension(std::vector< vtkUGridPtrAndName > &ugrid_blocks)
std::vector< vtkUGridPtrAndName > GetBlocksOfDesiredDimension(std::vector< vtkUGridPtrAndName > &ugrid_blocks, int desired_dimension)