1 // Copyright(C) 2021 National Technology & Engineering Solutions
2 // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with
3 // NTESS, the U.S. Government retains certain rights in this software.
4 //
5 // See packages/seacas/LICENSE for details
6
7 #include <Ioss_CodeTypes.h>
8 #include <Ioss_CopyDatabase.h>
9 #include <Ioss_DataPool.h>
10 #include <Ioss_FaceGenerator.h>
11 #include <Ioss_MeshCopyOptions.h>
12 #include <Ioss_SubSystem.h>
13
14 #include <fmt/ostream.h>
15
16 // For Sleep...
17 #include <chrono>
18 #include <thread>
19
20 // For copy_database...
21 namespace {
22 auto initial_time = std::chrono::steady_clock::now();
23
24 std::vector<int> get_selected_steps(Ioss::Region ®ion, const Ioss::MeshCopyOptions &options);
25 void show_step(int istep, double time, const Ioss::MeshCopyOptions &options, int rank);
26 std::vector<Ioss::Face> generate_boundary_faces(Ioss::Region & region,
27 const Ioss::MeshCopyOptions &options);
28 void define_model(Ioss::Region ®ion, Ioss::Region &output_region, DataPool &data_pool,
29 const std::vector<Ioss::Face> &boundary, const Ioss::MeshCopyOptions &options,
30 int rank);
31 void transfer_model(Ioss::Region ®ion, Ioss::Region &output_region, DataPool &pool,
32 const std::vector<Ioss::Face> &boundary, const Ioss::MeshCopyOptions &options,
33 int rank);
34 void define_transient_fields(Ioss::Region ®ion, Ioss::Region &output_region,
35 const Ioss::MeshCopyOptions &options, int rank);
36 void transfer_step(Ioss::Region ®ion, Ioss::Region &output_region, DataPool &pool, int istep,
37 const Ioss::MeshCopyOptions &options, int rank);
38
39 void transfer_nodeblock(Ioss::Region ®ion, Ioss::Region &output_region, DataPool &pool,
40 const Ioss::MeshCopyOptions &options, int rank);
41 void transfer_structuredblocks(Ioss::Region ®ion, Ioss::Region &output_region,
42 const Ioss::MeshCopyOptions &options, int rank);
43 void transfer_elementblocks(Ioss::Region ®ion, Ioss::Region &output_region,
44 const Ioss::MeshCopyOptions &options, int rank);
45 void transfer_edgeblocks(Ioss::Region ®ion, Ioss::Region &output_region,
46 const Ioss::MeshCopyOptions &options, int rank);
47 void transfer_faceblocks(Ioss::Region ®ion, Ioss::Region &output_region,
48 const Ioss::MeshCopyOptions &options, int rank);
49 void transfer_nodesets(Ioss::Region ®ion, Ioss::Region &output_region,
50 const Ioss::MeshCopyOptions &options, int rank);
51 void transfer_edgesets(Ioss::Region ®ion, Ioss::Region &output_region,
52 const Ioss::MeshCopyOptions &options, int rank);
53 void transfer_facesets(Ioss::Region ®ion, Ioss::Region &output_region,
54 const Ioss::MeshCopyOptions &options, int rank);
55 void transfer_elemsets(Ioss::Region ®ion, Ioss::Region &output_region,
56 const Ioss::MeshCopyOptions &options, int rank);
57 void transfer_sidesets(Ioss::Region ®ion, Ioss::Region &output_region,
58 const Ioss::MeshCopyOptions &options, int rank);
59 void transfer_commsets(Ioss::Region ®ion, Ioss::Region &output_region,
60 const Ioss::MeshCopyOptions &options, int rank);
61
62 template <typename T>
63 void transfer_fields(const std::vector<T *> &entities, Ioss::Region &output_region,
64 Ioss::Field::RoleType role, const Ioss::MeshCopyOptions &options, int rank);
65
66 void transfer_fields(const Ioss::GroupingEntity *ige, Ioss::GroupingEntity *oge,
67 Ioss::Field::RoleType role, const std::string &prefix = "");
68
69 void add_proc_id(Ioss::Region ®ion, int rank);
70
71 template <typename T>
72 void transfer_field_data(const std::vector<T *> &entities, Ioss::Region &output_region,
73 DataPool &pool, Ioss::Field::RoleType role,
74 const Ioss::MeshCopyOptions &options);
75
76 void transfer_field_data(Ioss::GroupingEntity *ige, Ioss::GroupingEntity *oge, DataPool &pool,
77 Ioss::Field::RoleType role, const Ioss::MeshCopyOptions &options,
78 const std::string &prefix = "");
79
80 void transfer_properties(const Ioss::GroupingEntity *ige, Ioss::GroupingEntity *oge);
81
82 void transfer_qa_info(Ioss::Region &in, Ioss::Region &out);
83
84 void transfer_field_data_internal(Ioss::GroupingEntity *ige, Ioss::GroupingEntity *oge,
85 DataPool &pool, const std::string &field_name,
86 const Ioss::MeshCopyOptions &options);
87
88 template <typename INT>
89 void set_owned_node_count(Ioss::Region ®ion, int my_processor, INT dummy);
90
91 template <typename T>
calculate_maximum_field_size(const std::vector<T> & entities,size_t max_field_size)92 size_t calculate_maximum_field_size(const std::vector<T> &entities, size_t max_field_size)
93 {
94 size_t max_size = max_field_size;
95 for (const auto &entity : entities) {
96 Ioss::NameList fields;
97 entity->field_describe(&fields);
98 for (const auto &field_name : fields) {
99 Ioss::Field field = entity->get_field(field_name);
100 max_size = std::max(field.get_size(), max_size);
101 }
102 }
103 return max_size;
104 }
105
calculate_maximum_field_size(const Ioss::Region & region)106 size_t calculate_maximum_field_size(const Ioss::Region ®ion)
107 {
108 size_t max_field_size = 0;
109 max_field_size = calculate_maximum_field_size(region.get_node_blocks(), max_field_size);
110 max_field_size = calculate_maximum_field_size(region.get_edge_blocks(), max_field_size);
111 max_field_size = calculate_maximum_field_size(region.get_face_blocks(), max_field_size);
112 max_field_size = calculate_maximum_field_size(region.get_element_blocks(), max_field_size);
113 max_field_size = calculate_maximum_field_size(region.get_sidesets(), max_field_size);
114 max_field_size = calculate_maximum_field_size(region.get_nodesets(), max_field_size);
115 max_field_size = calculate_maximum_field_size(region.get_edgesets(), max_field_size);
116 max_field_size = calculate_maximum_field_size(region.get_facesets(), max_field_size);
117 max_field_size = calculate_maximum_field_size(region.get_elementsets(), max_field_size);
118 max_field_size = calculate_maximum_field_size(region.get_commsets(), max_field_size);
119 max_field_size = calculate_maximum_field_size(region.get_structured_blocks(), max_field_size);
120 max_field_size = calculate_maximum_field_size(region.get_assemblies(), max_field_size);
121 max_field_size = calculate_maximum_field_size(region.get_blobs(), max_field_size);
122 return max_field_size;
123 }
124
125 template <typename INT>
output_boundary_sideset(Ioss::SideBlock * sb,const std::vector<Ioss::Face> & boundary,INT)126 void output_boundary_sideset(Ioss::SideBlock *sb, const std::vector<Ioss::Face> &boundary,
127 INT /* dummy */)
128 {
129 std::vector<INT> el_side;
130 el_side.reserve(boundary.size() * 2);
131 for (const auto &face : boundary) {
132 el_side.push_back(face.element[0] / 10);
133 el_side.push_back(face.element[0] % 10 + 1);
134 }
135 sb->put_field_data("element_side", el_side);
136 }
137 } // namespace
138
transfer_coordinate_frames(Ioss::Region & region,Ioss::Region & output_region)139 void Ioss::transfer_coordinate_frames(Ioss::Region ®ion, Ioss::Region &output_region)
140 {
141 const Ioss::CoordinateFrameContainer &cf = region.get_coordinate_frames();
142 for (const auto &frame : cf) {
143 output_region.add(frame);
144 }
145 }
146
transfer_assemblies(Ioss::Region & region,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)147 void Ioss::transfer_assemblies(Ioss::Region ®ion, Ioss::Region &output_region,
148 const Ioss::MeshCopyOptions &options, int rank)
149 {
150 const auto &assem = region.get_assemblies();
151 if (!assem.empty()) {
152 for (const auto &assm : assem) {
153 const std::string &name = assm->name();
154 if (options.debug && rank == 0) {
155 fmt::print(Ioss::DEBUG(), "{}, ", name);
156 }
157
158 // NOTE: Can't totally use the copy constructor as it will
159 // create a members list containing entities from input
160 // database. We need corresponding entities from output
161 // database...
162 auto o_assem = new Ioss::Assembly(*assm);
163 o_assem->remove_members();
164
165 // Now, repopulate member list with corresponding entities from output database...
166 const auto &members = assm->get_members();
167 for (const auto &member : members) {
168 const auto *entity = output_region.get_entity(member->name(), member->type());
169 if (entity != nullptr) {
170 o_assem->add(entity);
171 }
172 }
173 output_region.add(o_assem);
174 }
175
176 if (options.verbose && rank == 0) {
177 fmt::print(Ioss::DEBUG(), " Number of {:20s} = {:14L}\n", "Assemblies", assem.size());
178 }
179 if (options.debug && rank == 0) {
180 fmt::print(Ioss::DEBUG(), "\n");
181 }
182 }
183 }
184
transfer_blobs(Ioss::Region & region,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)185 void Ioss::transfer_blobs(Ioss::Region ®ion, Ioss::Region &output_region,
186 const Ioss::MeshCopyOptions &options, int rank)
187 {
188 const auto &blobs = region.get_blobs();
189 if (!blobs.empty()) {
190 size_t total_entities = 0;
191 for (const auto &blob : blobs) {
192 const std::string &name = blob->name();
193 if (options.debug && rank == 0) {
194 fmt::print(Ioss::DEBUG(), "{}, ", name);
195 }
196 size_t count = blob->entity_count();
197 total_entities += count;
198 auto o_blob = new Ioss::Blob(*blob);
199 output_region.add(o_blob);
200 }
201
202 if (options.verbose && rank == 0) {
203 fmt::print(Ioss::DEBUG(), " Number of {:20s} = {:14L}", (*blobs.begin())->type_string() + "s",
204 blobs.size());
205 fmt::print(Ioss::DEBUG(), "\tLength of entity list = {:14L}\n", total_entities);
206 }
207 if (options.debug && rank == 0) {
208 fmt::print(Ioss::DEBUG(), "\n");
209 }
210 }
211 }
212
copy_database(Ioss::Region & region,Ioss::Region & output_region,Ioss::MeshCopyOptions & options)213 void Ioss::copy_database(Ioss::Region ®ion, Ioss::Region &output_region,
214 Ioss::MeshCopyOptions &options)
215 {
216
217 Ioss::DatabaseIO *dbi = region.get_database();
218 int rank = dbi->util().parallel_rank();
219
220 // Minimize number of times that we grow the memory buffer used for transferring field data.
221 size_t max_field_size = calculate_maximum_field_size(region);
222 if (options.verbose && rank == 0) {
223 fmt::print(Ioss::DEBUG(), "\n Maximum Field size = {:L} bytes.\n", max_field_size);
224 }
225
226 DataPool data_pool;
227 data_pool.data.resize(max_field_size);
228 if (options.verbose && rank == 0) {
229 fmt::print(Ioss::DEBUG(), " Resize finished...\n");
230 }
231
232 std::vector<Ioss::Face> boundary = generate_boundary_faces(region, options);
233 if (options.define_geometry) {
234 define_model(region, output_region, data_pool, boundary, options, rank);
235 }
236 bool appending = output_region.get_database()->open_create_behavior() == Ioss::DB_APPEND;
237 if (!appending) {
238 transfer_model(region, output_region, data_pool, boundary, options, rank);
239
240 if (options.add_proc_id) {
241 Ioss::Utils::clear(data_pool.data);
242 add_proc_id(output_region, rank);
243 return;
244 }
245
246 if (options.delete_timesteps) {
247 Ioss::Utils::clear(data_pool.data);
248 return;
249 }
250 } // !appending
251
252 if (options.define_geometry) {
253 define_transient_fields(region, output_region, options, rank);
254 }
255
256 output_region.begin_mode(Ioss::STATE_TRANSIENT);
257 if (options.debug && rank == 0) {
258 fmt::print(Ioss::DEBUG(), "TRANSFERRING TRANSIENT FIELDS ... \n");
259 }
260 dbi->progress("TRANSFERRING TRANSIENT FIELDS... ");
261
262 // Get the timesteps from the input database. Step through them
263 // and transfer fields to output database...
264 // `selected_steps` specifies whether an input step should be transferred
265 // to the output region based on values in `options`
266 std::vector<int> selected_steps = get_selected_steps(region, options);
267
268 int step_count = region.get_property("state_count").get_int();
269 for (int istep = 1; istep <= step_count; istep++) {
270 if (selected_steps[istep] == 1) {
271 transfer_step(region, output_region, data_pool, istep, options, rank);
272 }
273 }
274
275 if (options.debug && rank == 0) {
276 fmt::print(Ioss::DEBUG(), "END STATE_TRANSIENT... \n");
277 }
278 dbi->progress("END STATE_TRANSIENT (begin) ... ");
279
280 output_region.end_mode(Ioss::STATE_TRANSIENT);
281 dbi->progress("END STATE_TRANSIENT (end) ... ");
282 Ioss::Utils::clear(data_pool.data);
283
284 if (rank == 0) {
285 fmt::print(std::cout, "\n\n Output Region summary for rank 0:");
286 output_region.output_summary(std::cout);
287 }
288 }
289
290 namespace {
get_selected_steps(Ioss::Region & region,const Ioss::MeshCopyOptions & options)291 std::vector<int> get_selected_steps(Ioss::Region ®ion, const Ioss::MeshCopyOptions &options)
292 {
293 // This routine checks all steps of the input database and selects those which
294 // meet the requirements specified in `options`. The returned (1-based) vector will have a
295 // value of `1` if the step is to be output and `0` if skipped.
296 int step_count = region.get_property("state_count").get_int();
297 std::vector<int> selected_steps(step_count + 1);
298
299 // If user specified a list of times to transfer to output database,
300 // process the list and find the times on the input database that are
301 // closest to the times in the list.
302 if (!options.selected_times.empty()) {
303 int selected_step = 0;
304 for (auto time : options.selected_times) {
305 double diff = std::numeric_limits<double>::max();
306 for (int step = 1; step <= step_count; step++) {
307 double db_time = region.get_state_time(step);
308 double cur_diff = std::abs(db_time - time);
309 if (cur_diff < diff) {
310 diff = std::abs(db_time - time);
311 selected_step = step;
312 }
313 }
314 if (selected_step > 0) {
315 selected_steps[selected_step] = 1;
316 }
317 }
318 }
319 else {
320 // User did not select specific times to be output...
321 // Just select them all
322 for (int i = 1; i <= step_count; i++) {
323 selected_steps[i] = 1;
324 }
325 }
326
327 // Now, filter by min and max time...
328 for (int istep = 1; istep <= step_count; istep++) {
329 double time = region.get_state_time(istep);
330 if (time < options.minimum_time) {
331 selected_steps[istep] = 0;
332 }
333 if (time > options.maximum_time) {
334 selected_steps[istep] = 0;
335 }
336 }
337 return selected_steps;
338 }
339
transfer_mesh_info(const T * input,T * output)340 template <typename T> void transfer_mesh_info(const T *input, T *output)
341 {
342 transfer_properties(input, output);
343 transfer_fields(input, output, Ioss::Field::MESH);
344 transfer_fields(input, output, Ioss::Field::ATTRIBUTE);
345 transfer_fields(input, output, Ioss::Field::MESH_REDUCTION);
346 }
347
generate_boundary_faces(Ioss::Region & region,const Ioss::MeshCopyOptions & options)348 std::vector<Ioss::Face> generate_boundary_faces(Ioss::Region & region,
349 const Ioss::MeshCopyOptions &options)
350 {
351 std::vector<Ioss::Face> boundary;
352 if (options.define_geometry && options.boundary_sideset) {
353 Ioss::FaceGenerator face_generator(region);
354 if (region.get_database()->int_byte_size_api() == 4) {
355 face_generator.generate_faces((int)0, false);
356 }
357 else {
358 face_generator.generate_faces((int64_t)0, false);
359 }
360
361 // Get vector of all boundary faces which will be output as the skin...
362 auto &faces = face_generator.faces("ALL");
363 for (auto &face : faces) {
364 if (face.elementCount_ == 1) {
365 boundary.push_back(face);
366 }
367 }
368 }
369 return boundary;
370 }
371
define_model(Ioss::Region & region,Ioss::Region & output_region,DataPool & data_pool,const std::vector<Ioss::Face> & boundary,const Ioss::MeshCopyOptions & options,int rank)372 void define_model(Ioss::Region ®ion, Ioss::Region &output_region, DataPool &data_pool,
373 const std::vector<Ioss::Face> &boundary, const Ioss::MeshCopyOptions &options,
374 int rank)
375 {
376 if (options.debug && rank == 0) {
377 fmt::print(Ioss::DEBUG(), "DEFINING MODEL ... \n");
378 }
379 Ioss::DatabaseIO *dbi = region.get_database();
380 dbi->progress("DEFINING MODEL");
381 if (!output_region.begin_mode(Ioss::STATE_DEFINE_MODEL)) {
382 if (options.verbose) {
383 std::ostringstream errmsg;
384 fmt::print(errmsg, "ERROR: Could not put output region into define model state\n");
385 IOSS_ERROR(errmsg);
386 }
387 else {
388 std::exit(EXIT_FAILURE);
389 }
390 }
391
392 if (rank == 0) {
393 fmt::print(std::cout, "\n\n Input Region summary for rank 0:\n");
394 }
395
396 // Get all properties of input database...
397 transfer_properties(®ion, &output_region);
398 transfer_qa_info(region, output_region);
399
400 if (rank == 0) {
401 fmt::print(std::cout, "\n\n Input Region summary for rank 0:\n");
402 }
403 transfer_nodeblock(region, output_region, data_pool, options, rank);
404
405 #ifdef SEACAS_HAVE_MPI
406 // This also assumes that the node order and count is the same for input
407 // and output regions... (This is checked during nodeset output)
408 if (output_region.get_database()->needs_shared_node_information()) {
409 if (options.ints_64_bit)
410 set_owned_node_count(region, rank, (int64_t)0);
411 else
412 set_owned_node_count(region, rank, (int)0);
413 }
414 #endif
415
416 transfer_edgeblocks(region, output_region, options, rank);
417 transfer_faceblocks(region, output_region, options, rank);
418 transfer_elementblocks(region, output_region, options, rank);
419 transfer_structuredblocks(region, output_region, options, rank);
420
421 transfer_nodesets(region, output_region, options, rank);
422 transfer_edgesets(region, output_region, options, rank);
423 transfer_facesets(region, output_region, options, rank);
424 transfer_elemsets(region, output_region, options, rank);
425
426 transfer_sidesets(region, output_region, options, rank);
427
428 if (options.define_geometry && options.boundary_sideset) {
429 // Get topology of the sideset faces. Using just block[0] since for what we are doing, doesn't
430 // really matter.
431 const auto &blocks = region.get_element_blocks();
432 auto topo = blocks[0]->topology();
433 auto elem_topo = topo->name();
434 auto face_topo = topo->boundary_type(0)->name();
435
436 auto ss = new Ioss::SideSet(output_region.get_database(), "boundary");
437 output_region.add(ss);
438 auto sb = new Ioss::SideBlock(output_region.get_database(), "boundary", face_topo, elem_topo,
439 boundary.size());
440 ss->add(sb);
441 }
442
443 transfer_commsets(region, output_region, options, rank);
444
445 transfer_coordinate_frames(region, output_region);
446 transfer_blobs(region, output_region, options, rank);
447
448 // This must be last...
449 transfer_assemblies(region, output_region, options, rank);
450
451 if (options.debug && rank == 0) {
452 fmt::print(Ioss::DEBUG(), "END STATE_DEFINE_MODEL...\n");
453 }
454 dbi->progress("END STATE_DEFINE_MODEL");
455
456 output_region.end_mode(Ioss::STATE_DEFINE_MODEL);
457 dbi->progress("output_region.end_mode(Ioss::STATE_DEFINE_MODEL) finished");
458 }
459
transfer_model(Ioss::Region & region,Ioss::Region & output_region,DataPool & data_pool,const std::vector<Ioss::Face> & boundary,const Ioss::MeshCopyOptions & options,int rank)460 void transfer_model(Ioss::Region ®ion, Ioss::Region &output_region, DataPool &data_pool,
461 const std::vector<Ioss::Face> &boundary, const Ioss::MeshCopyOptions &options,
462 int rank)
463 {
464 if (options.debug && rank == 0) {
465 fmt::print(Ioss::DEBUG(), "TRANSFERRING MESH FIELD DATA ...\n");
466 }
467 Ioss::DatabaseIO *dbi = region.get_database();
468 dbi->progress("TRANSFERRING MESH FIELD DATA ... ");
469
470 // Model defined, now fill in the model data...
471 output_region.begin_mode(Ioss::STATE_MODEL);
472
473 // Transfer MESH field_data from input to output...
474 // Transfer MESH field_data from input to output...
475 bool node_major = output_region.node_major();
476
477 if (!node_major) {
478 transfer_field_data(region.get_element_blocks(), output_region, data_pool, Ioss::Field::MESH,
479 options);
480 transfer_field_data(region.get_element_blocks(), output_region, data_pool,
481 Ioss::Field::ATTRIBUTE, options);
482 }
483
484 if (region.mesh_type() != Ioss::MeshType::STRUCTURED) {
485 transfer_field_data(region.get_node_blocks(), output_region, data_pool, Ioss::Field::MESH,
486 options);
487 transfer_field_data(region.get_node_blocks(), output_region, data_pool,
488 Ioss::Field::ATTRIBUTE, options);
489 }
490
491 if (node_major) {
492 transfer_field_data(region.get_element_blocks(), output_region, data_pool, Ioss::Field::MESH,
493 options);
494 transfer_field_data(region.get_element_blocks(), output_region, data_pool,
495 Ioss::Field::ATTRIBUTE, options);
496 }
497
498 // Structured Blocks -- Contain a NodeBlock that also needs its field data transferred...
499 const auto &sbs = region.get_structured_blocks();
500 for (const auto &isb : sbs) {
501 const std::string &name = isb->name();
502 if (options.debug && rank == 0) {
503 fmt::print(Ioss::DEBUG(), "{}, ", name);
504 }
505 // Find matching output structured block
506 Ioss::StructuredBlock *osb = output_region.get_structured_block(name);
507 if (osb != nullptr) {
508 transfer_field_data(isb, osb, data_pool, Ioss::Field::MESH, options);
509 transfer_field_data(isb, osb, data_pool, Ioss::Field::ATTRIBUTE, options);
510
511 auto &inb = isb->get_node_block();
512 auto &onb = osb->get_node_block();
513 if (options.debug && rank == 0) {
514 fmt::print(Ioss::DEBUG(), "NB: {}, ", inb.name());
515 }
516
517 transfer_field_data(&inb, &onb, data_pool, Ioss::Field::MESH, options);
518 transfer_field_data(&inb, &onb, data_pool, Ioss::Field::ATTRIBUTE, options);
519 }
520 }
521
522 transfer_field_data(region.get_assemblies(), output_region, data_pool, Ioss::Field::MESH,
523 options);
524 transfer_field_data(region.get_assemblies(), output_region, data_pool, Ioss::Field::ATTRIBUTE,
525 options);
526
527 transfer_field_data(region.get_blobs(), output_region, data_pool, Ioss::Field::MESH, options);
528 transfer_field_data(region.get_blobs(), output_region, data_pool, Ioss::Field::ATTRIBUTE,
529 options);
530
531 transfer_field_data(region.get_edge_blocks(), output_region, data_pool, Ioss::Field::MESH,
532 options);
533 transfer_field_data(region.get_edge_blocks(), output_region, data_pool, Ioss::Field::ATTRIBUTE,
534 options);
535
536 transfer_field_data(region.get_face_blocks(), output_region, data_pool, Ioss::Field::MESH,
537 options);
538 transfer_field_data(region.get_face_blocks(), output_region, data_pool, Ioss::Field::ATTRIBUTE,
539 options);
540
541 transfer_field_data(region.get_nodesets(), output_region, data_pool, Ioss::Field::MESH,
542 options);
543 transfer_field_data(region.get_nodesets(), output_region, data_pool, Ioss::Field::ATTRIBUTE,
544 options);
545
546 transfer_field_data(region.get_edgesets(), output_region, data_pool, Ioss::Field::MESH,
547 options);
548 transfer_field_data(region.get_edgesets(), output_region, data_pool, Ioss::Field::ATTRIBUTE,
549 options);
550
551 transfer_field_data(region.get_facesets(), output_region, data_pool, Ioss::Field::MESH,
552 options);
553 transfer_field_data(region.get_facesets(), output_region, data_pool, Ioss::Field::ATTRIBUTE,
554 options);
555
556 transfer_field_data(region.get_elementsets(), output_region, data_pool, Ioss::Field::MESH,
557 options);
558 transfer_field_data(region.get_elementsets(), output_region, data_pool, Ioss::Field::ATTRIBUTE,
559 options);
560
561 transfer_field_data(region.get_commsets(), output_region, data_pool, Ioss::Field::MESH,
562 options);
563 transfer_field_data(region.get_commsets(), output_region, data_pool, Ioss::Field::ATTRIBUTE,
564 options);
565 transfer_field_data(region.get_commsets(), output_region, data_pool, Ioss::Field::COMMUNICATION,
566 options);
567
568 // Side Sets
569 if (region.mesh_type() == Ioss::MeshType::UNSTRUCTURED) {
570 const auto &fss = region.get_sidesets();
571 for (const auto &ifs : fss) {
572 const std::string &name = ifs->name();
573 if (options.debug && rank == 0) {
574 fmt::print(Ioss::DEBUG(), "{}, ", name);
575 }
576 // Find matching output sideset
577 Ioss::SideSet *ofs = output_region.get_sideset(name);
578
579 if (ofs != nullptr) {
580 transfer_field_data(ifs, ofs, data_pool, Ioss::Field::MESH, options);
581 transfer_field_data(ifs, ofs, data_pool, Ioss::Field::ATTRIBUTE, options);
582
583 const auto &fbs = ifs->get_side_blocks();
584 for (const auto &ifb : fbs) {
585
586 // Find matching output sideblock
587 const std::string &fbname = ifb->name();
588 if (options.debug && rank == 0) {
589 fmt::print(Ioss::DEBUG(), "{}, ", fbname);
590 }
591 Ioss::SideBlock *ofb = ofs->get_side_block(fbname);
592
593 if (ofb != nullptr) {
594 transfer_field_data(ifb, ofb, data_pool, Ioss::Field::MESH, options);
595 transfer_field_data(ifb, ofb, data_pool, Ioss::Field::ATTRIBUTE, options);
596 }
597 }
598 }
599 }
600 if (options.debug && rank == 0) {
601 fmt::print(Ioss::DEBUG(), "\n");
602 }
603
604 if (options.define_geometry && options.boundary_sideset) {
605 auto *ss = output_region.get_sideset("boundary");
606 if (ss != nullptr) {
607 auto sb = ss->get_side_block("boundary");
608 if (output_region.get_database()->int_byte_size_api() == 4) {
609 output_boundary_sideset(sb, boundary, (int)0);
610 }
611 else {
612 output_boundary_sideset(sb, boundary, (int64_t)0);
613 }
614 }
615 }
616 }
617 if (options.debug && rank == 0) {
618 fmt::print(Ioss::DEBUG(), "END STATE_MODEL... \n");
619 }
620 dbi->progress("END STATE_MODEL... ");
621 output_region.end_mode(Ioss::STATE_MODEL);
622 }
623
define_transient_fields(Ioss::Region & region,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)624 void define_transient_fields(Ioss::Region ®ion, Ioss::Region &output_region,
625 const Ioss::MeshCopyOptions &options, int rank)
626 {
627 if (options.debug && rank == 0) {
628 fmt::print(Ioss::DEBUG(), "DEFINING TRANSIENT FIELDS ... \n");
629 }
630
631 Ioss::DatabaseIO *dbi = region.get_database();
632 dbi->progress("DEFINING TRANSIENT FIELDS ... ");
633
634 if (region.property_exists("state_count") && region.get_property("state_count").get_int() > 0) {
635 if (options.verbose && rank == 0) {
636 fmt::print(Ioss::DEBUG(), "\n Number of time steps on database = {}\n",
637 region.get_property("state_count").get_int());
638 }
639
640 output_region.begin_mode(Ioss::STATE_DEFINE_TRANSIENT);
641
642 // NOTE: For most types, the fields are transferred from input to output
643 // via the copy constructor. The "special" ones are handled here.
644 // The below lines handle both methods of handling global variables...
645 transfer_fields(®ion, &output_region, Ioss::Field::REDUCTION);
646 transfer_fields(®ion, &output_region, Ioss::Field::TRANSIENT);
647
648 // Structured Blocks -- Contain a NodeBlock that also needs its fields transferred...
649 const auto &sbs = region.get_structured_blocks();
650 for (const auto &isb : sbs) {
651
652 // Find matching output structured block
653 const std::string & name = isb->name();
654 Ioss::StructuredBlock *osb = output_region.get_structured_block(name);
655 if (osb != nullptr) {
656 transfer_fields(isb, osb, Ioss::Field::TRANSIENT);
657 transfer_fields(isb, osb, Ioss::Field::REDUCTION);
658
659 auto &inb = isb->get_node_block();
660 auto &onb = osb->get_node_block();
661 transfer_fields(&inb, &onb, Ioss::Field::TRANSIENT);
662 transfer_fields(&inb, &onb, Ioss::Field::REDUCTION);
663 }
664 }
665
666 if (options.debug && rank == 0) {
667 fmt::print(Ioss::DEBUG(), "END STATE_DEFINE_TRANSIENT... \n");
668 }
669 dbi->progress("END STATE_DEFINE_TRANSIENT... ");
670 output_region.end_mode(Ioss::STATE_DEFINE_TRANSIENT);
671 }
672 }
transfer_step(Ioss::Region & region,Ioss::Region & output_region,DataPool & data_pool,int istep,const Ioss::MeshCopyOptions & options,int rank)673 void transfer_step(Ioss::Region ®ion, Ioss::Region &output_region, DataPool &data_pool,
674 int istep, const Ioss::MeshCopyOptions &options, int rank)
675 {
676 double time = region.get_state_time(istep);
677 int ostep = output_region.add_state(time);
678 show_step(istep, time, options, rank);
679
680 output_region.begin_state(ostep);
681 region.begin_state(istep);
682
683 for (int i = 0; i < 2; i++) {
684 auto field_type = Ioss::Field::TRANSIENT;
685 if (i > 0) {
686 field_type = Ioss::Field::REDUCTION;
687 }
688
689 transfer_field_data(®ion, &output_region, data_pool, field_type, options);
690
691 transfer_field_data(region.get_assemblies(), output_region, data_pool, field_type, options);
692 transfer_field_data(region.get_blobs(), output_region, data_pool, field_type, options);
693
694 if (region.mesh_type() != Ioss::MeshType::STRUCTURED) {
695 transfer_field_data(region.get_node_blocks(), output_region, data_pool, field_type,
696 options);
697 }
698 transfer_field_data(region.get_edge_blocks(), output_region, data_pool, field_type, options);
699 transfer_field_data(region.get_face_blocks(), output_region, data_pool, field_type, options);
700 transfer_field_data(region.get_element_blocks(), output_region, data_pool, field_type,
701 options);
702
703 {
704 // Structured Blocks -- handle embedded NodeBlock also.
705 const auto &sbs = region.get_structured_blocks();
706 for (const auto &isb : sbs) {
707 const std::string &name = isb->name();
708 if (options.debug && rank == 0) {
709 fmt::print(Ioss::DEBUG(), "{}, ", name);
710 }
711 // Find matching output structured block
712 Ioss::StructuredBlock *osb = output_region.get_structured_block(name);
713 if (osb != nullptr) {
714 transfer_field_data(isb, osb, data_pool, field_type, options);
715
716 auto &inb = isb->get_node_block();
717 auto &onb = osb->get_node_block();
718 transfer_field_data(&inb, &onb, data_pool, field_type, options);
719 }
720 }
721 }
722
723 transfer_field_data(region.get_nodesets(), output_region, data_pool, field_type, options);
724 transfer_field_data(region.get_edgesets(), output_region, data_pool, field_type, options);
725 transfer_field_data(region.get_facesets(), output_region, data_pool, field_type, options);
726 transfer_field_data(region.get_elementsets(), output_region, data_pool, field_type, options);
727
728 // Side Sets
729 {
730 const auto &fss = region.get_sidesets();
731 for (const auto &ifs : fss) {
732 const std::string &name = ifs->name();
733 if (options.debug && rank == 0) {
734 fmt::print(Ioss::DEBUG(), "{}, ", name);
735 }
736
737 // Find matching output sideset
738 Ioss::SideSet *ofs = output_region.get_sideset(name);
739 if (ofs != nullptr) {
740 transfer_field_data(ifs, ofs, data_pool, field_type, options);
741
742 const auto &fbs = ifs->get_side_blocks();
743 for (const auto &ifb : fbs) {
744
745 // Find matching output sideblock
746 const std::string &fbname = ifb->name();
747 if (options.debug && rank == 0) {
748 fmt::print(Ioss::DEBUG(), "{}, ", fbname);
749 }
750
751 Ioss::SideBlock *ofb = ofs->get_side_block(fbname);
752 if (ofb != nullptr) {
753 transfer_field_data(ifb, ofb, data_pool, field_type, options);
754 }
755 }
756 }
757 }
758 }
759 }
760 region.end_state(istep);
761 output_region.end_state(ostep);
762
763 if (options.delay > 0.0) {
764 std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(options.delay * 1000)));
765 }
766 }
767
transfer_nodeblock(Ioss::Region & region,Ioss::Region & output_region,DataPool & pool,const Ioss::MeshCopyOptions & options,int rank)768 void transfer_nodeblock(Ioss::Region ®ion, Ioss::Region &output_region, DataPool &pool,
769 const Ioss::MeshCopyOptions &options, int rank)
770 {
771 const auto &nbs = region.get_node_blocks();
772 for (const auto &inb : nbs) {
773 const std::string &name = inb->name();
774 if (options.debug && rank == 0) {
775 fmt::print(Ioss::DEBUG(), "{}, ", name);
776 }
777 size_t num_nodes = inb->entity_count();
778 size_t degree = inb->get_property("component_degree").get_int();
779 if (options.verbose && rank == 0) {
780 fmt::print(Ioss::DEBUG(), " Number of Coordinates per Node = {:14L}\n", degree);
781 fmt::print(Ioss::DEBUG(), " Number of Nodes = {:14L}\n", num_nodes);
782 }
783 auto *nb = new Ioss::NodeBlock(*inb);
784 output_region.add(nb);
785
786 if (output_region.get_database()->needs_shared_node_information()) {
787 // If the "owning_processor" field exists on the input
788 // nodeblock, transfer it and the "ids" field to the output
789 // nodeblock at this time since it is used to determine
790 // per-processor sizes of nodeblocks and nodesets.
791 if (inb->field_exists("owning_processor")) {
792 size_t isize = inb->get_field("ids").get_size();
793 pool.data.resize(isize);
794 inb->get_field_data("ids", pool.data.data(), isize);
795 nb->put_field_data("ids", pool.data.data(), isize);
796
797 isize = inb->get_field("owning_processor").get_size();
798 pool.data.resize(isize);
799 inb->get_field_data("owning_processor", pool.data.data(), isize);
800 nb->put_field_data("owning_processor", pool.data.data(), isize);
801 }
802 }
803 }
804 if (options.debug && rank == 0) {
805 fmt::print(Ioss::DEBUG(), "\n");
806 }
807 }
808
809 template <typename T>
transfer_fields(const std::vector<T * > & entities,Ioss::Region & output_region,Ioss::Field::RoleType role,const Ioss::MeshCopyOptions & options,int rank)810 void transfer_fields(const std::vector<T *> &entities, Ioss::Region &output_region,
811 Ioss::Field::RoleType role, const Ioss::MeshCopyOptions &options, int rank)
812 {
813 for (const auto &entity : entities) {
814 const std::string &name = entity->name();
815 if (options.debug && rank == 0) {
816 fmt::print(Ioss::DEBUG(), "{}, ", name);
817 }
818
819 // Find the corresponding output node_block...
820 Ioss::GroupingEntity *oeb = output_region.get_entity(name, entity->type());
821 if (oeb != nullptr) {
822 transfer_fields(entity, oeb, role);
823 }
824 }
825 if (options.debug && rank == 0) {
826 fmt::print(Ioss::DEBUG(), "\n");
827 }
828 }
829
830 template <typename T>
transfer_field_data(const std::vector<T * > & entities,Ioss::Region & output_region,DataPool & pool,Ioss::Field::RoleType role,const Ioss::MeshCopyOptions & options)831 void transfer_field_data(const std::vector<T *> &entities, Ioss::Region &output_region,
832 DataPool &pool, Ioss::Field::RoleType role,
833 const Ioss::MeshCopyOptions &options)
834 {
835 for (const auto &entity : entities) {
836 const std::string &name = entity->name();
837
838 // Find the corresponding output block...
839 Ioss::GroupingEntity *output = output_region.get_entity(name, entity->type());
840 if (output != nullptr) {
841 transfer_field_data(entity, output, pool, role, options);
842 }
843 }
844 }
845
846 template <typename T>
transfer_blocks(const std::vector<T * > & blocks,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)847 void transfer_blocks(const std::vector<T *> &blocks, Ioss::Region &output_region,
848 const Ioss::MeshCopyOptions &options, int rank)
849 {
850 if (!blocks.empty()) {
851 size_t total_entities = 0;
852 for (const auto &iblock : blocks) {
853 const std::string &name = iblock->name();
854 if (options.debug && rank == 0) {
855 fmt::print(Ioss::DEBUG(), "{}, ", name);
856 }
857 size_t count = iblock->entity_count();
858 total_entities += count;
859
860 auto block = new T(*iblock);
861 output_region.add(block);
862 }
863 if (options.verbose && rank == 0) {
864 fmt::print(Ioss::DEBUG(), " Number of {:20s} = {:14L}\n",
865 (*blocks.begin())->type_string() + "s", blocks.size());
866 fmt::print(Ioss::DEBUG(), " Number of {:20s} = {:14L}\n",
867 (*blocks.begin())->contains_string() + "s", total_entities);
868 }
869 if (options.debug && rank == 0) {
870 fmt::print(Ioss::DEBUG(), "\n");
871 }
872 }
873 }
874
transfer_structuredblocks(Ioss::Region & region,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)875 void transfer_structuredblocks(Ioss::Region ®ion, Ioss::Region &output_region,
876 const Ioss::MeshCopyOptions &options, int rank)
877 {
878 auto blocks = region.get_structured_blocks();
879 if (!blocks.empty()) {
880 size_t total_entities = 0;
881 if (options.reverse) {
882 // Defines the CGNS zones in the reverse order they
883 // were read from the input mesh. This is used in
884 // testing to verify that we handle zone reordering
885 // correctly.
886 for (int i = blocks.size() - 1; i >= 0; i--) {
887 const auto & iblock = blocks[i];
888 const std::string &name = iblock->name();
889 if (options.debug && rank == 0) {
890 fmt::print(Ioss::DEBUG(), "{}, ", name);
891 }
892 size_t count = iblock->entity_count();
893 total_entities += count;
894
895 auto block = iblock->clone(output_region.get_database());
896 output_region.add(block);
897 transfer_mesh_info(iblock, block);
898
899 // Now do the transfer on the NodeBlock contained in the StructuredBlock
900 auto &inb = iblock->get_node_block();
901 auto &onb = block->get_node_block();
902 if (options.debug && rank == 0) {
903 fmt::print(Ioss::DEBUG(), "(NB: {}), ", inb.name());
904 }
905 transfer_mesh_info(&inb, &onb);
906 }
907 }
908 else {
909 for (const auto &iblock : blocks) {
910 const std::string &name = iblock->name();
911 if (options.debug && rank == 0) {
912 fmt::print(Ioss::DEBUG(), "{}, ", name);
913 }
914 size_t count = iblock->entity_count();
915 total_entities += count;
916
917 auto block = iblock->clone(output_region.get_database());
918 output_region.add(block);
919 transfer_mesh_info(iblock, block);
920
921 // Now do the transfer on the NodeBlock contained in the StructuredBlock
922 auto &inb = iblock->get_node_block();
923 auto &onb = block->get_node_block();
924 if (options.debug && rank == 0) {
925 fmt::print(Ioss::DEBUG(), "(NB: {}), ", inb.name());
926 }
927 transfer_mesh_info(&inb, &onb);
928 }
929 }
930
931 if (options.verbose && rank == 0) {
932 fmt::print(Ioss::DEBUG(), " Number of {:20s} = {:14L}\n",
933 (*blocks.begin())->type_string() + "s", blocks.size());
934 fmt::print(Ioss::DEBUG(), " Number of {:20s} = {:14L}\n",
935 (*blocks.begin())->contains_string() + "s", total_entities);
936 }
937 if (options.debug && rank == 0) {
938 fmt::print(Ioss::DEBUG(), "\n");
939 }
940 }
941 }
942
transfer_elementblocks(Ioss::Region & region,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)943 void transfer_elementblocks(Ioss::Region ®ion, Ioss::Region &output_region,
944 const Ioss::MeshCopyOptions &options, int rank)
945 {
946 const auto &ebs = region.get_element_blocks();
947 transfer_blocks(ebs, output_region, options, rank);
948 }
949
transfer_edgeblocks(Ioss::Region & region,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)950 void transfer_edgeblocks(Ioss::Region ®ion, Ioss::Region &output_region,
951 const Ioss::MeshCopyOptions &options, int rank)
952 {
953 const auto &ebs = region.get_edge_blocks();
954 transfer_blocks(ebs, output_region, options, rank);
955 }
956
transfer_faceblocks(Ioss::Region & region,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)957 void transfer_faceblocks(Ioss::Region ®ion, Ioss::Region &output_region,
958 const Ioss::MeshCopyOptions &options, int rank)
959 {
960 const auto &ebs = region.get_face_blocks();
961 transfer_blocks(ebs, output_region, options, rank);
962 }
963
transfer_sidesets(Ioss::Region & region,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)964 void transfer_sidesets(Ioss::Region ®ion, Ioss::Region &output_region,
965 const Ioss::MeshCopyOptions &options, int rank)
966 {
967 const auto &fss = region.get_sidesets();
968 size_t total_sides = 0;
969 for (const auto &ss : fss) {
970 const std::string &name = ss->name();
971 if (options.debug && rank == 0) {
972 fmt::print(Ioss::DEBUG(), "{}, ", name);
973 }
974 auto surf = new Ioss::SideSet(*ss);
975 output_region.add(surf);
976
977 // Fix up the optional 'owner_block' in copied SideBlocks...
978 const auto &fbs = ss->get_side_blocks();
979 for (const auto &ifb : fbs) {
980 if (ifb->parent_block() != nullptr) {
981 auto fb_name = ifb->parent_block()->name();
982 auto *parent = dynamic_cast<Ioss::EntityBlock *>(output_region.get_entity(fb_name));
983
984 auto *ofb = surf->get_side_block(ifb->name());
985 ofb->set_parent_block(parent);
986 }
987 }
988 }
989
990 if (options.verbose && rank == 0 && !fss.empty()) {
991 fmt::print(Ioss::DEBUG(), " Number of {:20s} = {:14L}\n", (*fss.begin())->type_string() + "s",
992 fss.size());
993 fmt::print(Ioss::DEBUG(), " Number of {:20s} = {:14L}\n",
994 (*fss.begin())->contains_string() + "s", total_sides);
995 }
996 if (options.debug && rank == 0) {
997 fmt::print(Ioss::DEBUG(), "\n");
998 }
999 }
1000
1001 template <typename T>
transfer_sets(const std::vector<T * > & sets,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)1002 void transfer_sets(const std::vector<T *> &sets, Ioss::Region &output_region,
1003 const Ioss::MeshCopyOptions &options, int rank)
1004 {
1005 if (!sets.empty()) {
1006 size_t total_entities = 0;
1007 for (const auto &set : sets) {
1008 const std::string &name = set->name();
1009 if (options.debug && rank == 0) {
1010 fmt::print(Ioss::DEBUG(), "{}, ", name);
1011 }
1012 size_t count = set->entity_count();
1013 total_entities += count;
1014 auto o_set = new T(*set);
1015 output_region.add(o_set);
1016 }
1017
1018 if (options.verbose && rank == 0) {
1019 fmt::print(Ioss::DEBUG(), " Number of {:20s} = {:14L}",
1020 (*sets.begin())->type_string() + "s", sets.size());
1021 fmt::print(Ioss::DEBUG(), "\tLength of entity list = {:14L}\n", total_entities);
1022 }
1023 if (options.debug && rank == 0) {
1024 fmt::print(Ioss::DEBUG(), "\n");
1025 }
1026 }
1027 }
1028
transfer_nodesets(Ioss::Region & region,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)1029 void transfer_nodesets(Ioss::Region ®ion, Ioss::Region &output_region,
1030 const Ioss::MeshCopyOptions &options, int rank)
1031 {
1032 const auto &nss = region.get_nodesets();
1033 transfer_sets(nss, output_region, options, rank);
1034 }
1035
transfer_edgesets(Ioss::Region & region,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)1036 void transfer_edgesets(Ioss::Region ®ion, Ioss::Region &output_region,
1037 const Ioss::MeshCopyOptions &options, int rank)
1038 {
1039 const auto &nss = region.get_edgesets();
1040 transfer_sets(nss, output_region, options, rank);
1041 }
1042
transfer_facesets(Ioss::Region & region,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)1043 void transfer_facesets(Ioss::Region ®ion, Ioss::Region &output_region,
1044 const Ioss::MeshCopyOptions &options, int rank)
1045 {
1046 const auto &nss = region.get_facesets();
1047 transfer_sets(nss, output_region, options, rank);
1048 }
1049
transfer_elemsets(Ioss::Region & region,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)1050 void transfer_elemsets(Ioss::Region ®ion, Ioss::Region &output_region,
1051 const Ioss::MeshCopyOptions &options, int rank)
1052 {
1053 const auto &nss = region.get_elementsets();
1054 transfer_sets(nss, output_region, options, rank);
1055 }
1056
transfer_commsets(Ioss::Region & region,Ioss::Region & output_region,const Ioss::MeshCopyOptions & options,int rank)1057 void transfer_commsets(Ioss::Region ®ion, Ioss::Region &output_region,
1058 const Ioss::MeshCopyOptions &options, int rank)
1059 {
1060 const auto &css = region.get_commsets();
1061 for (const auto &ics : css) {
1062 if (options.debug && rank == 0) {
1063 const std::string &name = ics->name();
1064 fmt::print(Ioss::DEBUG(), "{}, ", name);
1065 }
1066 auto cs = new Ioss::CommSet(*ics);
1067 output_region.add(cs);
1068 }
1069 if (options.debug && rank == 0) {
1070 fmt::print(Ioss::DEBUG(), "\n");
1071 }
1072 }
1073
transfer_fields(const Ioss::GroupingEntity * ige,Ioss::GroupingEntity * oge,Ioss::Field::RoleType role,const std::string & prefix)1074 void transfer_fields(const Ioss::GroupingEntity *ige, Ioss::GroupingEntity *oge,
1075 Ioss::Field::RoleType role, const std::string &prefix)
1076 {
1077 // Check for transient fields...
1078 Ioss::NameList fields;
1079 ige->field_describe(role, &fields);
1080
1081 // Iterate through results fields and transfer to output
1082 // database... If a prefix is specified, only transfer fields
1083 // whose names begin with the prefix
1084 for (const auto &field_name : fields) {
1085 Ioss::Field field = ige->get_field(field_name);
1086 if (field_name != "ids" && !oge->field_exists(field_name) &&
1087 Ioss::Utils::substr_equal(prefix, field_name)) {
1088 // If the field does not already exist, add it to the output node block
1089 oge->field_add(field);
1090 }
1091 }
1092 }
1093
transfer_field_data(Ioss::GroupingEntity * ige,Ioss::GroupingEntity * oge,DataPool & pool,Ioss::Field::RoleType role,const Ioss::MeshCopyOptions & options,const std::string & prefix)1094 void transfer_field_data(Ioss::GroupingEntity *ige, Ioss::GroupingEntity *oge, DataPool &pool,
1095 Ioss::Field::RoleType role, const Ioss::MeshCopyOptions &options,
1096 const std::string &prefix)
1097 {
1098 // !!!! WARNING !!!! This is a hack. It assumes that all NodeBlocks that have "_nodes" in
1099 // their name belong to a StructuredBlock (m_nodeBlock). Further, it assumes that the
1100 // NodeBlocks that belong to a StructuredBlock have no field data that needs to be transferred.
1101 // A permanent and comprehensive fix that handles this issue still needs to be developed.
1102 // --sll 21aug20
1103 if (ige->type() == Ioss::NODEBLOCK && ige->name().find("_nodes") != std::string::npos) {
1104 return;
1105 }
1106
1107 // Iterate through the TRANSIENT-role fields of the input
1108 // database and transfer to output database.
1109 Ioss::NameList state_fields;
1110 ige->field_describe(role, &state_fields);
1111
1112 // Complication here is that if the 'role' is 'Ioss::Field::MESH',
1113 // then the 'ids' field must be transferred first...
1114 if (role == Ioss::Field::MESH && ige->field_exists("ids")) {
1115 assert(oge->field_exists("ids"));
1116 transfer_field_data_internal(ige, oge, pool, "ids", options);
1117 }
1118
1119 for (const auto &field_name : state_fields) {
1120 // All of the 'Ioss::EntityBlock' derived classes have a
1121 // 'connectivity' field, but it is only interesting on the
1122 // Ioss::ElementBlock class. On the other classes, it just
1123 // generates overhead...
1124
1125 if (field_name == "connectivity" && ige->type() != Ioss::ELEMENTBLOCK) {
1126 continue;
1127 }
1128 if (field_name == "ids") {
1129 continue;
1130 }
1131
1132 if (Ioss::Utils::substr_equal(prefix, field_name)) {
1133 assert(oge->field_exists(field_name));
1134 transfer_field_data_internal(ige, oge, pool, field_name, options);
1135 }
1136 }
1137 }
1138
transfer_field_data_internal(Ioss::GroupingEntity * ige,Ioss::GroupingEntity * oge,DataPool & pool,const std::string & field_name,const Ioss::MeshCopyOptions & options)1139 void transfer_field_data_internal(Ioss::GroupingEntity *ige, Ioss::GroupingEntity *oge,
1140 DataPool &pool, const std::string &field_name,
1141 const Ioss::MeshCopyOptions &options)
1142 {
1143
1144 size_t isize = ige->get_field(field_name).get_size();
1145 assert(isize == oge->get_field(field_name).get_size());
1146
1147 int basic_type = ige->get_field(field_name).get_type();
1148
1149 if (field_name == "mesh_model_coordinates_x") {
1150 return;
1151 }
1152 if (field_name == "mesh_model_coordinates_y") {
1153 return;
1154 }
1155 if (field_name == "mesh_model_coordinates_z") {
1156 return;
1157 }
1158 if (field_name == "connectivity_raw") {
1159 return;
1160 }
1161 if (field_name == "element_side_raw") {
1162 return;
1163 }
1164 if (field_name == "ids_raw") {
1165 return;
1166 }
1167 if (field_name == "implicit_ids") {
1168 return;
1169 }
1170 if (field_name == "node_connectivity_status") {
1171 return;
1172 }
1173 if (field_name == "owning_processor") {
1174 return;
1175 }
1176 if (field_name == "entity_processor_raw") {
1177 return;
1178 }
1179 if (field_name == "ids" && ige->type() == Ioss::SIDEBLOCK) {
1180 return;
1181 }
1182 if (field_name == "ids" && ige->type() == Ioss::STRUCTUREDBLOCK) {
1183 return;
1184 }
1185 if (field_name == "cell_ids" && ige->type() == Ioss::STRUCTUREDBLOCK) {
1186 return;
1187 }
1188 if (field_name == "cell_node_ids" && ige->type() == Ioss::STRUCTUREDBLOCK) {
1189 return;
1190 }
1191
1192 if (options.data_storage_type == 1 || options.data_storage_type == 2) {
1193 if (pool.data.size() < isize) {
1194 pool.data.resize(isize);
1195 }
1196 }
1197 else {
1198 }
1199
1200 assert(pool.data.size() >= isize);
1201
1202 switch (options.data_storage_type) {
1203 case 1: ige->get_field_data(field_name, pool.data.data(), isize); break;
1204 case 2:
1205 if ((basic_type == Ioss::Field::CHARACTER) || (basic_type == Ioss::Field::STRING)) {
1206 ige->get_field_data(field_name, pool.data);
1207 }
1208 else if (basic_type == Ioss::Field::INT32) {
1209 ige->get_field_data(field_name, pool.data_int);
1210 }
1211 else if (basic_type == Ioss::Field::INT64) {
1212 ige->get_field_data(field_name, pool.data_int64);
1213 }
1214 else if (basic_type == Ioss::Field::REAL) {
1215 ige->get_field_data(field_name, pool.data_double);
1216 }
1217 else if (basic_type == Ioss::Field::COMPLEX) {
1218 ige->get_field_data(field_name, pool.data_complex);
1219 }
1220 else {
1221 }
1222 break;
1223 #ifdef SEACAS_HAVE_KOKKOS
1224 case 3:
1225 if ((basic_type == Ioss::Field::CHARACTER) || (basic_type == Ioss::Field::STRING)) {
1226 ige->get_field_data<char>(field_name, pool.data_view_char);
1227 }
1228 else if (basic_type == Ioss::Field::INT32) {
1229 ige->get_field_data<int>(field_name, pool.data_view_int);
1230 }
1231 else if (basic_type == Ioss::Field::INT64) {
1232 ige->get_field_data<int64_t>(field_name, pool.data_view_int64);
1233 }
1234 else if (basic_type == Ioss::Field::REAL) {
1235 ige->get_field_data<double>(field_name, pool.data_view_double);
1236 }
1237 else if (basic_type == Ioss::Field::COMPLEX) {
1238 // Since data_view_complex cannot be a global variable.
1239 ige->get_field_data(field_name, pool.data.data(), isize);
1240 }
1241 else {
1242 }
1243 break;
1244 case 4:
1245 if ((basic_type == Ioss::Field::CHARACTER) || (basic_type == Ioss::Field::STRING)) {
1246 ige->get_field_data<char>(field_name, pool.data_view_2D_char);
1247 }
1248 else if (basic_type == Ioss::Field::INT32) {
1249 ige->get_field_data<int>(field_name, pool.data_view_2D_int);
1250 }
1251 else if (basic_type == Ioss::Field::INT64) {
1252 ige->get_field_data<int64_t>(field_name, pool.data_view_2D_int64);
1253 }
1254 else if (basic_type == Ioss::Field::REAL) {
1255 ige->get_field_data<double>(field_name, pool.data_view_2D_double);
1256 }
1257 else if (basic_type == Ioss::Field::COMPLEX) {
1258 // Since data_view_complex cannot be a global variable.
1259 ige->get_field_data(field_name, pool.data.data(), isize);
1260 }
1261 else {
1262 }
1263 break;
1264 case 5:
1265 if ((basic_type == Ioss::Field::CHARACTER) || (basic_type == Ioss::Field::STRING)) {
1266 ige->get_field_data<char, Kokkos::LayoutRight, Kokkos::HostSpace>(
1267 field_name, pool.data_view_2D_char_layout_space);
1268 }
1269 else if (basic_type == Ioss::Field::INT32) {
1270 ige->get_field_data<int, Kokkos::LayoutRight, Kokkos::HostSpace>(
1271 field_name, pool.data_view_2D_int_layout_space);
1272 }
1273 else if (basic_type == Ioss::Field::INT64) {
1274 ige->get_field_data<int64_t, Kokkos::LayoutRight, Kokkos::HostSpace>(
1275 field_name, pool.data_view_2D_int64_layout_space);
1276 }
1277 else if (basic_type == Ioss::Field::REAL) {
1278 ige->get_field_data<double, Kokkos::LayoutRight, Kokkos::HostSpace>(
1279 field_name, pool.data_view_2D_double_layout_space);
1280 }
1281 else if (basic_type == Ioss::Field::COMPLEX) {
1282 // Since data_view_complex cannot be a global variable.
1283 ige->get_field_data(field_name, pool.data.data(), isize);
1284 }
1285 else {
1286 }
1287 break;
1288 #endif
1289 default:
1290 if (field_name == "mesh_model_coordinates") {
1291 fmt::print(Ioss::DEBUG(), "data_storage option not recognized.");
1292 }
1293 return;
1294 }
1295
1296 switch (options.data_storage_type) {
1297 case 1: oge->put_field_data(field_name, pool.data.data(), isize); break;
1298 case 2:
1299 if ((basic_type == Ioss::Field::CHARACTER) || (basic_type == Ioss::Field::STRING)) {
1300 oge->put_field_data(field_name, pool.data);
1301 }
1302 else if (basic_type == Ioss::Field::INT32) {
1303 oge->put_field_data(field_name, pool.data_int);
1304 }
1305 else if (basic_type == Ioss::Field::INT64) {
1306 oge->put_field_data(field_name, pool.data_int64);
1307 }
1308 else if (basic_type == Ioss::Field::REAL) {
1309 oge->put_field_data(field_name, pool.data_double);
1310 }
1311 else if (basic_type == Ioss::Field::COMPLEX) {
1312 oge->put_field_data(field_name, pool.data_complex);
1313 }
1314 else {
1315 }
1316 break;
1317 #ifdef SEACAS_HAVE_KOKKOS
1318 case 3:
1319 if ((basic_type == Ioss::Field::CHARACTER) || (basic_type == Ioss::Field::STRING)) {
1320 oge->put_field_data<char>(field_name, pool.data_view_char);
1321 }
1322 else if (basic_type == Ioss::Field::INT32) {
1323 oge->put_field_data<int>(field_name, pool.data_view_int);
1324 }
1325 else if (basic_type == Ioss::Field::INT64) {
1326 oge->put_field_data<int64_t>(field_name, pool.data_view_int64);
1327 }
1328 else if (basic_type == Ioss::Field::REAL) {
1329 oge->put_field_data<double>(field_name, pool.data_view_double);
1330 }
1331 else if (basic_type == Ioss::Field::COMPLEX) {
1332 // Since data_view_complex cannot be a global variable.
1333 oge->put_field_data(field_name, pool.data.data(), isize);
1334 }
1335 else {
1336 }
1337 break;
1338 case 4:
1339 if ((basic_type == Ioss::Field::CHARACTER) || (basic_type == Ioss::Field::STRING)) {
1340 oge->put_field_data<char>(field_name, pool.data_view_2D_char);
1341 }
1342 else if (basic_type == Ioss::Field::INT32) {
1343 oge->put_field_data<int>(field_name, pool.data_view_2D_int);
1344 }
1345 else if (basic_type == Ioss::Field::INT64) {
1346 oge->put_field_data<int64_t>(field_name, pool.data_view_2D_int64);
1347 }
1348 else if (basic_type == Ioss::Field::REAL) {
1349 oge->put_field_data<double>(field_name, pool.data_view_2D_double);
1350 }
1351 else if (basic_type == Ioss::Field::COMPLEX) {
1352 // Since data_view_complex cannot be a global variable.
1353 oge->put_field_data(field_name, pool.data.data(), isize);
1354 }
1355 else {
1356 }
1357 break;
1358 case 5:
1359 if ((basic_type == Ioss::Field::CHARACTER) || (basic_type == Ioss::Field::STRING)) {
1360 oge->put_field_data<char, Kokkos::LayoutRight, Kokkos::HostSpace>(
1361 field_name, pool.data_view_2D_char_layout_space);
1362 }
1363 else if (basic_type == Ioss::Field::INT32) {
1364 oge->put_field_data<int, Kokkos::LayoutRight, Kokkos::HostSpace>(
1365 field_name, pool.data_view_2D_int_layout_space);
1366 }
1367 else if (basic_type == Ioss::Field::INT64) {
1368 oge->put_field_data<int64_t, Kokkos::LayoutRight, Kokkos::HostSpace>(
1369 field_name, pool.data_view_2D_int64_layout_space);
1370 }
1371 else if (basic_type == Ioss::Field::REAL) {
1372 oge->put_field_data<double, Kokkos::LayoutRight, Kokkos::HostSpace>(
1373 field_name, pool.data_view_2D_double_layout_space);
1374 }
1375 else if (basic_type == Ioss::Field::COMPLEX) {
1376 // Since data_view_complex cannot be a global variable.
1377 oge->put_field_data(field_name, pool.data.data(), isize);
1378 }
1379 else {
1380 }
1381 break;
1382 #endif
1383 default: return;
1384 }
1385 }
1386
transfer_qa_info(Ioss::Region & in,Ioss::Region & out)1387 void transfer_qa_info(Ioss::Region &in, Ioss::Region &out)
1388 {
1389 out.add_information_records(in.get_information_records());
1390
1391 const std::vector<std::string> &qa = in.get_qa_records();
1392 for (size_t i = 0; i < qa.size(); i += 4) {
1393 out.add_qa_record(qa[i + 0], qa[i + 1], qa[i + 2], qa[i + 3]);
1394 }
1395 }
1396
transfer_properties(const Ioss::GroupingEntity * ige,Ioss::GroupingEntity * oge)1397 void transfer_properties(const Ioss::GroupingEntity *ige, Ioss::GroupingEntity *oge)
1398 {
1399 Ioss::NameList properties;
1400 ige->property_describe(&properties);
1401
1402 // Iterate through properties and transfer to output database...
1403 for (const auto &property : properties) {
1404 if (!oge->property_exists(property)) {
1405 oge->property_add(ige->get_property(property));
1406 }
1407 }
1408 }
1409
show_step(int istep,double time,const Ioss::MeshCopyOptions & options,int rank)1410 void show_step(int istep, double time, const Ioss::MeshCopyOptions &options, int rank)
1411 {
1412 if (options.verbose && rank == 0) {
1413 fmt::print(Ioss::DEBUG(), "\r\tTime step {:5d} at time {:10.5e}", istep, time);
1414 }
1415 }
1416
1417 template <typename INT>
set_owned_node_count(Ioss::Region & region,int my_processor,INT)1418 void set_owned_node_count(Ioss::Region ®ion, int my_processor, INT /*dummy*/)
1419 {
1420 Ioss::NodeBlock *nb = region.get_node_block("nodeblock_1");
1421 if (nb->field_exists("owning_processor")) {
1422 std::vector<int> my_data;
1423 nb->get_field_data("owning_processor", my_data);
1424
1425 INT owned = std::count(my_data.begin(), my_data.end(), my_processor);
1426 nb->property_add(Ioss::Property("locally_owned_count", owned));
1427
1428 // Set locally_owned_count property on all nodesets...
1429 const Ioss::NodeSetContainer &nss = region.get_nodesets();
1430 for (auto ns : nss) {
1431
1432 std::vector<INT> ids;
1433 ns->get_field_data("ids_raw", ids);
1434 owned = 0;
1435 for (size_t n = 0; n < ids.size(); n++) {
1436 INT id = ids[n];
1437 if (my_data[id - 1] == my_processor) {
1438 ++owned;
1439 }
1440 }
1441 ns->property_add(Ioss::Property("locally_owned_count", owned));
1442 }
1443 }
1444 }
1445
add_proc_id(Ioss::Region & region,int rank)1446 void add_proc_id(Ioss::Region ®ion, int rank)
1447 {
1448 region.begin_mode(Ioss::STATE_DEFINE_TRANSIENT);
1449 auto &sblocks = region.get_structured_blocks();
1450 for (auto &sb : sblocks) {
1451 sb->field_add(
1452 Ioss::Field("processor_id", Ioss::Field::REAL, "scalar", Ioss::Field::TRANSIENT));
1453 }
1454
1455 auto &eblocks = region.get_element_blocks();
1456 for (auto &eb : eblocks) {
1457 eb->field_add(
1458 Ioss::Field("processor_id", Ioss::Field::REAL, "scalar", Ioss::Field::TRANSIENT));
1459 }
1460 region.end_mode(Ioss::STATE_DEFINE_TRANSIENT);
1461
1462 region.begin_mode(Ioss::STATE_TRANSIENT);
1463
1464 auto step = region.add_state(0.0);
1465 region.begin_state(step);
1466
1467 for (auto &sb : sblocks) {
1468 std::vector<double> proc_id(sb->entity_count(), rank);
1469 sb->put_field_data("processor_id", proc_id);
1470 }
1471
1472 for (auto &eb : eblocks) {
1473 std::vector<double> proc_id(eb->entity_count(), rank);
1474 eb->put_field_data("processor_id", proc_id);
1475 }
1476
1477 region.end_state(step);
1478 region.end_mode(Ioss::STATE_TRANSIENT);
1479 }
1480 } // namespace
1481