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 &region, 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 &region, 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 &region, 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 &region, Ioss::Region &output_region,
35                                const Ioss::MeshCopyOptions &options, int rank);
36   void transfer_step(Ioss::Region &region, Ioss::Region &output_region, DataPool &pool, int istep,
37                      const Ioss::MeshCopyOptions &options, int rank);
38 
39   void transfer_nodeblock(Ioss::Region &region, Ioss::Region &output_region, DataPool &pool,
40                           const Ioss::MeshCopyOptions &options, int rank);
41   void transfer_structuredblocks(Ioss::Region &region, Ioss::Region &output_region,
42                                  const Ioss::MeshCopyOptions &options, int rank);
43   void transfer_elementblocks(Ioss::Region &region, Ioss::Region &output_region,
44                               const Ioss::MeshCopyOptions &options, int rank);
45   void transfer_edgeblocks(Ioss::Region &region, Ioss::Region &output_region,
46                            const Ioss::MeshCopyOptions &options, int rank);
47   void transfer_faceblocks(Ioss::Region &region, Ioss::Region &output_region,
48                            const Ioss::MeshCopyOptions &options, int rank);
49   void transfer_nodesets(Ioss::Region &region, Ioss::Region &output_region,
50                          const Ioss::MeshCopyOptions &options, int rank);
51   void transfer_edgesets(Ioss::Region &region, Ioss::Region &output_region,
52                          const Ioss::MeshCopyOptions &options, int rank);
53   void transfer_facesets(Ioss::Region &region, Ioss::Region &output_region,
54                          const Ioss::MeshCopyOptions &options, int rank);
55   void transfer_elemsets(Ioss::Region &region, Ioss::Region &output_region,
56                          const Ioss::MeshCopyOptions &options, int rank);
57   void transfer_sidesets(Ioss::Region &region, Ioss::Region &output_region,
58                          const Ioss::MeshCopyOptions &options, int rank);
59   void transfer_commsets(Ioss::Region &region, 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 &region, 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 &region, 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 &region)
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 &region, 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 &region, 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 &region, 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 &region, 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 &region, 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 &region, 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(&region, &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 &region, 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 &region, 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(&region, &output_region, Ioss::Field::REDUCTION);
646       transfer_fields(&region, &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 &region, 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(&region, &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 &region, 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 &region, 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 &region, 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 &region, 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 &region, 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 &region, 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 &region, 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 &region, 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 &region, 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 &region, 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 &region, 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 &region, 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 &region, 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