17#define scint static_cast<int>
30 "Generates the mesh only on location 0, thereafter partitions the mesh"
31 " but instead of broadcasting the mesh to other locations it creates binary"
32 " mesh files for each location.");
38 "The number of partitions to generate. If zero will "
39 "default to the number of MPI processes. Is "
40 "ignored if the number of MPI processes > 1.");
43 "split_mesh_dir_path",
45 "Path of the directory to be created for containing the split meshes.");
49 "Prefix to use for all split mesh files");
54 "Controls whether the split mesh is recreated or just read.");
59 "Verbosity level. 1 will report each 10% complete. 2 will print each part "
60 "and the number of local cells it wrote.");
69 num_parts_(params.GetParamValue<int>(
"num_partitions")),
71 params.GetParamValue<std::string>(
"split_mesh_dir_path")),
72 split_file_prefix_(params.GetParamValue<std::string>(
"split_file_prefix")),
73 read_only_(params.GetParamValue<bool>(
"read_only")),
74 verbosity_level_(params.GetParamValue<int>(
"verbosity_level"))
82 const int num_parts = num_mpi == 1 ?
num_parts_ : num_mpi;
88 std::unique_ptr<UnpartitionedMesh> current_umesh =
nullptr;
89 for (
auto mesh_generator_ptr :
inputs_)
92 mesh_generator_ptr->GenerateUnpartitionedMesh(std::move(current_umesh));
93 current_umesh = std::move(new_umesh);
99 Chi::log.
Log() <<
"Writing split-mesh with " << num_parts <<
" parts";
100 const auto cell_pids =
PartitionMesh(*current_umesh, num_parts);
103 <<
" parts successfully created";
109 if (
Chi::mpi.process_count == num_parts)
118 new_mesher->SetContinuum(grid_ptr);
123 cur_hndlr.SetVolumeMesher(new_mesher);
129 <<
"After creating a split-mesh with mpi-processes < "
130 "num_parts the program will now auto terminate. This is not an error "
131 "and is the default behavior for the SplitFileMeshGenerator.\n"
141 const std::vector<int64_t>& cell_pids,
145 const std::filesystem::path dir_path =
148 const auto parent_path = dir_path.parent_path();
150 "Parent path " + parent_path.string() +
153 bool root_dir_created =
true;
154 if (not std::filesystem::exists(dir_path))
155 root_dir_created = std::filesystem::create_directories(dir_path);
158 "Failed to create directory " + dir_path.string());
167 "Sorting data",
"FileMeshGenerator::WriteSplitMesh");
169 "WriteCells",
"FileMeshGenerator::WriteSplitMesh");
171 "WriteVerts",
"FileMeshGenerator::WriteSplitMesh");
174 uint64_t aux_counter = 0;
175 for (
int pid = 0; pid < num_parts; ++pid)
178 const std::filesystem::path file_path = dir_path.string() +
"/" +
180 std::to_string(pid) +
".cmesh";
182 std::ofstream ofile(file_path.string(),
183 std::ios_base::binary | std::ios_base::out);
186 "Failed to open " + file_path.string());
189 t_sorting.TimeSectionBegin();
191 std::vector<uint64_t> local_cells_needed;
192 std::set<uint64_t> cells_needed;
193 std::set<uint64_t> vertices_needed;
195 local_cells_needed.reserve(raw_cells.size() / num_parts);
197 uint64_t cell_global_id = 0;
198 for (
auto cell_pid : cell_pids)
200 if (cell_pid == pid) local_cells_needed.push_back(cell_global_id);
205 for (uint64_t cell_global_id : local_cells_needed)
207 cells_needed.insert(cell_global_id);
209 const auto& raw_cell = *raw_cells[cell_global_id];
211 for (uint64_t vid : raw_cell.vertex_ids)
213 vertices_needed.insert(vid);
214 for (uint64_t ghost_gid : vertex_subs[vid])
216 if (ghost_gid == cell_global_id)
continue;
217 cells_needed.insert(ghost_gid);
219 const auto& ghost_raw_cell = *raw_cells[ghost_gid];
220 for (uint64_t gvid : ghost_raw_cell.vertex_ids)
221 vertices_needed.insert(gvid);
226 t_sorting.TimeSectionEnd();
230 <<
" num_local_cells=" << local_cells_needed.size();
246 const auto& bndry_map = mesh_options.boundary_id_map;
248 for (
const auto& [bid, bname] : bndry_map)
251 const size_t num_chars = bname.size();
253 ofile.write(bname.data(),
scint(num_chars));
262 const size_t BUFFER_SIZE = 4096 * 2;
264 serial_data.
Data().reserve(BUFFER_SIZE * 2);
265 for (
const auto& cell_global_id : cells_needed)
267 t_cells.TimeSectionBegin();
268 t_serialize.TimeSectionBegin();
269 const auto& cell = *raw_cells[cell_global_id];
270 serial_data.
Write(
static_cast<int>(cell_pids[cell_global_id]));
271 serial_data.
Write(cell_global_id);
273 t_serialize.TimeSectionEnd();
274 if (serial_data.
Size() > BUFFER_SIZE)
276 ofile.write((
char*)serial_data.
Data().data(),
278 const size_t cap = serial_data.
Data().capacity();
280 serial_data.
Data().reserve(cap);
282 t_cells.TimeSectionEnd();
284 if (serial_data.
Size() > 0)
286 ofile.write((
char*)serial_data.
Data().data(),
scint(serial_data.
Size()));
291 t_verts.TimeSectionBegin();
292 for (
const uint64_t vid : vertices_needed)
294 serial_data.
Write(vid);
295 serial_data.
Write(raw_vertices[vid]);
296 if (serial_data.
Size() > BUFFER_SIZE)
298 ofile.write((
char*)serial_data.
Data().data(),
303 if (serial_data.
Size() > 0)
305 ofile.write((
char*)serial_data.
Data().data(),
scint(serial_data.
Size()));
308 t_verts.TimeSectionEnd();
311 t_write.TimeSectionEnd();
313 const double fraction_complete =
314 static_cast<double>(pid) /
static_cast<double>(num_parts);
315 if (fraction_complete >=
static_cast<double>(aux_counter + 1) * 0.1)
319 <<
" Surpassing part " << pid <<
" of " << num_parts
320 <<
" (" << (aux_counter + 1) * 10 <<
"%)";
337 serial_buffer.
Write(vid);
339 for (
const auto& face : cell.
faces)
341 serial_buffer.
Write(face.vertex_ids.size());
342 for (uint64_t vid : face.vertex_ids)
343 serial_buffer.
Write(vid);
344 serial_buffer.
Write(face.has_neighbor);
345 serial_buffer.
Write(face.neighbor);
352 const std::filesystem::path dir_path =
354 const std::filesystem::path file_path = dir_path.string() +
"/" +
356 std::to_string(pid) +
".cmesh";
359 auto& cells = info_block.
cells_;
361 std::ifstream ifile(file_path, std::ios_base::binary | std::ios_base::in);
364 "Failed to open " + file_path.string());
368 const size_t file_num_parts = chi::ReadBinaryValue<int>(ifile);
372 "\" has been created with " +
373 std::to_string(file_num_parts) +
374 " parts but is now being read with " +
375 std::to_string(
Chi::mpi.process_count) +
" processes.");
378 info_block.
ortho_Nx_ = chi::ReadBinaryValue<size_t>(ifile);
379 info_block.
ortho_Ny_ = chi::ReadBinaryValue<size_t>(ifile);
380 info_block.
ortho_Nz_ = chi::ReadBinaryValue<size_t>(ifile);
385 const size_t num_bndries = chi::ReadBinaryValue<size_t>(ifile);
386 for (
size_t b = 0; b < num_bndries; ++b)
388 const uint64_t bid = chi::ReadBinaryValue<uint64_t>(ifile);
389 const size_t num_chars = chi::ReadBinaryValue<size_t>(ifile);
390 std::string bname(num_chars,
' ');
391 ifile.read(bname.data(),
static_cast<int>(num_chars));
398 const size_t num_cells = chi::ReadBinaryValue<size_t>(ifile);
399 const size_t num_vertices = chi::ReadBinaryValue<size_t>(ifile);
402 for (
size_t c = 0; c < num_cells; ++c)
404 const int cell_pid = chi::ReadBinaryValue<int>(ifile);
405 const uint64_t cell_gid = chi::ReadBinaryValue<uint64_t>(ifile);
406 const CellType cell_type = chi::ReadBinaryValue<CellType>(ifile);
407 const CellType cell_sub_type = chi::ReadBinaryValue<CellType>(ifile);
411 new_cell.
centroid = chi::ReadBinaryValue<chi_mesh::Vector3>(ifile);
412 new_cell.
material_id = chi::ReadBinaryValue<int>(ifile);
414 const size_t num_vids = chi::ReadBinaryValue<size_t>(ifile);
415 for (
size_t v = 0; v < num_vids; ++v)
416 new_cell.
vertex_ids.push_back(chi::ReadBinaryValue<uint64_t>(ifile));
418 const size_t num_faces = chi::ReadBinaryValue<size_t>(ifile);
419 for (
size_t f = 0; f < num_faces; ++f)
422 const size_t num_face_vids = chi::ReadBinaryValue<size_t>(ifile);
423 for (
size_t v = 0; v < num_face_vids; ++v)
424 new_face.
vertex_ids.push_back(chi::ReadBinaryValue<uint64_t>(ifile));
426 new_face.
has_neighbor = chi::ReadBinaryValue<bool>(ifile);
427 new_face.
neighbor = chi::ReadBinaryValue<uint64_t>(ifile);
429 new_cell.
faces.push_back(std::move(new_face));
433 std::make_pair(
CellPIDGID(cell_pid, cell_gid), std::move(new_cell)));
437 for (
size_t v = 0; v < num_vertices; ++v)
439 const uint64_t vid = chi::ReadBinaryValue<uint64_t>(ifile);
441 chi::ReadBinaryValue<chi_mesh::Vector3>(ifile);
442 vertices.insert(std::make_pair(vid, vertex));
450std::shared_ptr<MeshContinuum>
457 auto& cells = mesh_info.
cells_;
460 for (
const auto& [vid, vertex] : vertices)
461 grid_ptr->vertices.Insert(vid, vertex);
463 for (
const auto& [pidgid, raw_cell] : cells)
465 const auto& [cell_pid, cell_global_id] = pidgid;
469 grid_ptr->cells.push_back(std::move(cell));
475 {mesh_info.ortho_Nx_, mesh_info.ortho_Ny_, mesh_info.ortho_Nz_});
#define ChiLogicalErrorIf(condition, message)
#define ChiInvalidArgumentIf(condition, message)
static chi::Timer program_timer
static void Exit(int error_code)
static int current_mesh_handler
static chi::MPI_Info & mpi
LogStream Log(LOG_LVL level=LOG_0)
const int & process_count
Total number of processes.
const int & location_id
Current process rank.
std::string GetTimeString() const
std::string MakeGraphString()
TimingBlock & CreateOrGetTimingBlock(const std::string &name, const std::string &parent_name="")
TimingBlock & GetTimingBlock(const std::string &name)
std::vector< std::byte > & Data()
void Write(const T &value)
static std::shared_ptr< MeshContinuum > New()
static void ComputeAndPrintStats(const chi_mesh::MeshContinuum &grid)
static void SetGridAttributes(chi_mesh::MeshContinuum &grid, MeshAttributes new_attribs, std::array< size_t, 3 > ortho_cells_per_dimension)
std::vector< MeshGenerator * > inputs_
static std::unique_ptr< chi_mesh::Cell > SetupCell(const UnpartitionedMesh::LightWeightCell &raw_cell, uint64_t global_id, uint64_t partition_id, const VertexListHelper &vertices)
std::vector< int64_t > PartitionMesh(const UnpartitionedMesh &input_umesh, int num_partitions)
virtual std::unique_ptr< UnpartitionedMesh > GenerateUnpartitionedMesh(std::unique_ptr< UnpartitionedMesh > input_umesh)
static chi::InputParameters GetInputParameters()
static std::shared_ptr< MeshContinuum > SetupLocalMesh(SplitMeshInfo &mesh_info)
static void SerializeCell(const UnpartitionedMesh::LightWeightCell &cell, chi_data_types::ByteArray &serial_buffer)
SplitFileMeshGenerator(const chi::InputParameters ¶ms)
const std::string split_file_prefix_
std::pair< int, uint64_t > CellPIDGID
SplitMeshInfo ReadSplitMesh()
const std::string split_mesh_dir_path_
static chi::InputParameters GetInputParameters()
void WriteSplitMesh(const std::vector< int64_t > &cell_pids, const UnpartitionedMesh &umesh, int num_parts)
const int verbosity_level_
MeshAttributes & GetMeshAttributes()
const std::vector< chi_mesh::Vertex > & GetVertices() const
std::vector< LightWeightCell * > & GetRawCells()
Options & GetMeshOptions()
const std::vector< std::set< uint64_t > > & GetVertextCellSubscriptions() const
size_t PushNewHandlerAndGetIndex()
RegisterChiObject(chi_mesh, BooleanLogicalVolume)
MeshHandler & GetCurrentHandler()
void WriteBinaryValue(std::ofstream &output_file, T value)
std::map< CellPIDGID, UnpartitionedMesh::LightWeightCell > cells_
std::map< uint64_t, std::string > boundary_id_map_
size_t num_global_vertices_
std::map< uint64_t, chi_mesh::Vector3 > vertices_
std::vector< uint64_t > vertex_ids
const chi_mesh::CellType sub_type
chi_mesh::Vertex centroid
const chi_mesh::CellType type
std::vector< LightWeightFace > faces
std::vector< uint64_t > vertex_ids