libMesh
dyna_io.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 // Local includes
19 #include "libmesh/libmesh_config.h"
20 #include "libmesh/libmesh_logging.h"
21 #include "libmesh/dof_map.h"
22 #include "libmesh/elem.h"
23 #include "libmesh/dyna_io.h"
24 #include "libmesh/mesh_base.h"
25 #include "libmesh/mesh_tools.h"
26 #include "libmesh/int_range.h"
27 #include "libmesh/utility.h"
28 
29 // TIMPI includes
31 
32 // gzstream for reading compressed files as a stream
33 #ifdef LIBMESH_HAVE_GZSTREAM
34 # include "gzstream.h"
35 #endif
36 
37 // C++ includes
38 #include <array>
39 #include <cstddef>
40 #include <fstream>
41 #include <iterator>
42 #include <numeric> // iota
43 
44 namespace libMesh
45 {
46 
47 // Initialize the static data member
49 
50 
51 
52 // Definition of the static function which constructs the ElementMaps object.
54 {
55  // Object to be filled up
56  ElementMaps em;
57 
58  // em.add_def(ElementDefinition(TRI3, 2, 2, 1)); // node mapping?
59  // em.add_def(ElementDefinition(TRI6, 2, 2, 2)); // node mapping?
60  // em.add_def(ElementDefinition(TET4, 2, 3, 1)); // node mapping?
61  // em.add_def(ElementDefinition(TET10, 2, 3, 2)); // node mapping?
62  // em.add_def(ElementDefinition(PRISM6, 3, 3, 1)); // node mapping?
63  // em.add_def(ElementDefinition(PRISM18, 3, 3, 2)); // node mapping?
64 
65  // Eventually we'll map both tensor-product and non-tensor-product
66  // BEXT elements to ours; for now we only support non-tensor-product
67  // Bezier elements.
68  // for (unsigned int i=0; i != 2; ++i)
69  for (unsigned int i=1; i != 2; ++i)
70  {
71  // We only have one element for whom node orders match...
72  em.add_def(ElementDefinition(EDGE2, i, 1, 1));
73 
74  em.add_def(ElementDefinition(EDGE3, i, 1, 2,
75  {0, 2, 1}));
76  em.add_def(ElementDefinition(EDGE4, i, 1, 2,
77  {0, 2, 3, 1}));
78 
79  em.add_def(ElementDefinition(QUAD4, i, 2, 1,
80  {0, 1, 3, 2}));
81  em.add_def(ElementDefinition(QUAD9, i, 2, 2,
82  {0, 4, 1, 7, 8, 5, 3, 6, 2}));
83 
84  em.add_def(ElementDefinition(HEX8, i, 3, 1,
85  {0, 1, 3, 2, 4, 5, 7, 6}));
86  em.add_def(ElementDefinition(HEX27, i, 3, 2,
87  { 0, 8, 1, 11, 20, 9, 3, 10, 2,
88  12, 21, 13, 24, 26, 22, 15, 23, 14,
89  4, 16, 5, 19, 25, 17, 7, 18, 6}));
90  }
91 
92  return em;
93 }
94 
95 
96 
98  (ElemType type_in,
99  dyna_int_type dyna_type_in,
100  dyna_int_type dim_in,
101  dyna_int_type p_in) :
102  type(type_in),
103  dyna_type(dyna_type_in),
104  dim(dim_in),
105  p(p_in)
106 {
107  const unsigned int n_nodes = Elem::type_to_n_nodes_map[type_in];
108  if (n_nodes == invalid_uint)
109  libmesh_not_implemented_msg("Support for Polygons/Polyhedra not yet implemented");
110  nodes.resize(n_nodes);
111  std::iota(nodes.begin(), nodes.end(), 0);
112 }
113 
114 
116  (ElemType type_in,
117  dyna_int_type dyna_type_in,
118  dyna_int_type dim_in,
119  dyna_int_type p_in,
120  std::vector<unsigned int> && nodes_in) :
121  type(type_in),
122  dyna_type(dyna_type_in),
123  dim(dim_in),
124  p(p_in),
125  nodes(nodes_in)
126 {}
127 
128 
129 
131  bool keep_spline_nodes) :
133  _keep_spline_nodes (keep_spline_nodes)
134 {
135 }
136 
137 
138 
139 void DynaIO::read (const std::string & name)
140 {
141  const bool gzipped_file = (name.rfind(".gz") == name.size() - 3);
142  // These will be handled in unzip_file:
143  // const bool bzipped_file = (name.size() - name.rfind(".bz2") == 4);
144  // const bool xzipped_file = (name.size() - name.rfind(".xz") == 3);
145 
146  std::unique_ptr<std::istream> in;
147 
148  if (gzipped_file)
149  {
150 #ifdef LIBMESH_HAVE_GZSTREAM
151  auto inf = std::make_unique<igzstream>();
152  libmesh_assert(inf);
153  inf->open(name.c_str(), std::ios::in);
154  in = std::move(inf);
155 #else
156  libmesh_error_msg("ERROR: need gzstream to handle .gz files!!!");
157 #endif
158  }
159  else
160  {
161  auto inf = std::make_unique<std::ifstream>();
162  libmesh_assert(inf);
163 
164  std::string new_name = Utility::unzip_file(name);
165 
166  inf->open(new_name.c_str(), std::ios::in);
167  in = std::move(inf);
168  }
169 
170  libmesh_assert(in.get());
171 
172  this->read_mesh (*in);
173 }
174 
175 
176 
177 void DynaIO::read_mesh(std::istream & in)
178 {
180 
181  // This is a serial-only process for now;
182  // the Mesh should be read on processor 0 and
183  // broadcast later
184  libmesh_assert_equal_to (mesh.processor_id(), 0);
185 
186  libmesh_error_msg_if(!in.good(), "Can't read input stream");
187 
188  // clear any data in the mesh
189  mesh.clear();
190 
191  // clear any of our own data
192  spline_node_ptrs.clear();
193  spline_nodeelem_ptrs.clear();
194 
195  // Expect different sections, in this order, perhaps with blank
196  // lines and/or comments in between:
197 
198  enum FileSection {
199  FILE_HEADER,
200  PATCH_HEADER,
201  NODE_LINES,
202  // (repeat for each node)
203  N_ELEM_SUBBLOCKS,
204  ELEM_SUBBLOCK_HEADER,
205  // (repeat for each subblock)
206  ELEM_NODES_LINES,
207  ELEM_COEF_VEC_IDS,
208  // (repeat nodes lines + coef vec ids for each elem, subblock)
209  N_COEF_BLOCKS, // number of coef vec blocks of each type
210  N_VECS_PER_BLOCK, // number of coef vecs in each dense block
211  COEF_VEC_COMPONENTS,
212  // (repeat coef vec components as necessary)
213  // (repeat coef blocks as necessary)
214  //
215  // reserved for sparse block stuff we don't support yet
216  END_OF_FILE };
217 
218  FileSection section = FILE_HEADER;
219 
220  // Values to remember from section to section
221  dyna_int_type patch_id, n_spline_nodes, n_elem, n_coef_vec, weight_control_flag;
222  dyna_int_type n_elem_blocks, n_dense_coef_vec_blocks;
223  std::vector<dyna_int_type> // indexed from 0 to n_elem_blocks
224  block_elem_type,
225  block_n_elem,
226  block_n_nodes, // Number of *spline* nodes constraining elements
227  block_n_coef_vec, // Number of coefficient vectors for each elem
228  block_p,
229  block_dim;
230  std::vector<dyna_int_type> // indexed from 0 to n_dense_coef_vec_blocks
231  n_coef_vecs_in_subblock, n_coef_comp;
232  unsigned char weight_index = 0;
233  dyna_int_type n_nodes_read = 0,
234  n_elem_blocks_read = 0,
235  n_elems_read = 0,
236  n_elem_nodes_read = 0,
237  n_elem_cvids_read = 0,
238  n_coef_headers_read = 0,
239  n_coef_blocks_read = 0,
240  n_coef_comp_read = 0,
241  n_coef_vecs_read = 0;
242 
243  // For reading the file line by line
244  std::string s;
245 
246  // For storing global (spline) weights, until we have enough data to
247  // use them for calculating local (Bezier element) nodes
248  std::vector<Real> spline_weights;
249 
250  // For storing elements' constraint equations:
251  // Global node indices (1-based in file, 0-based in memory):
252  // elem_global_nodes[block_num][elem_num][local_index] = global_index
253  std::vector<std::vector<std::vector<dof_id_type>>> elem_global_nodes;
254 
255  // Dense constraint vectors in the Dyna file
256  // When first read:
257  // dense_constraint_vecs[block_num][vec_in_block][column_num] = coef
258  // When used:
259  // dense_constraint_vecs[0][vec_num][column_num] = coef
260  std::vector<std::vector<std::vector<Real>>> dense_constraint_vecs;
261 
262  // Constraint vector indices (1-based in file, 0-based in memory):
263  // elem_constraint_rows[block_num][elem_num][row_num] = cv_index
264  std::vector<std::vector<std::vector<dof_id_type>>> elem_constraint_rows;
265 
266  while (true)
267  {
268  // Try to read something. This may set EOF!
269  std::getline(in, s);
270 
271  if (in)
272  {
273  // Process s...
274 
275  if (s.find("B E X T 2.0") == static_cast<std::string::size_type>(0))
276  {
277  libmesh_error_msg_if(section != FILE_HEADER,
278  "Found 'B E X T 2.0' outside file header?");
279 
280  section = PATCH_HEADER;
281  continue;
282  }
283 
284  // Ignore comments
285  if (s.find("$#") == static_cast<std::string::size_type>(0))
286  continue;
287 
288  // Ignore blank lines
289  if (s.find_first_not_of(" \t") == std::string::npos)
290  continue;
291 
292  // Parse each important section
293  std::stringstream stream(s);
294  switch (section) {
295  case PATCH_HEADER:
296  stream >> patch_id;
297  stream >> n_spline_nodes;
298  stream >> n_elem;
299  stream >> n_coef_vec;
300  stream >> weight_control_flag;
301  libmesh_error_msg_if(stream.fail(), "Failure to parse patch header\n");
302 
303  spline_node_ptrs.resize(n_spline_nodes);
304  spline_weights.resize(n_spline_nodes);
305 
306  // Even if we have w=1.0, we still want RATIONAL_BERNSTEIN
307  // elements!
308  // if (weight_control_flag)
309  {
310  // If we ever add more nodes that aren't in this file,
311  // merge this mesh with a non-spline mesh, etc., 1.0
312  // is a good default weight
313  const Real default_weight = 1.0;
314  weight_index = cast_int<unsigned char>
315  (mesh.add_node_datum<Real>("rational_weight", true,
316  &default_weight));
318  mesh.set_default_mapping_data(weight_index);
319  }
320 
321  section = NODE_LINES;
322  break;
323  case NODE_LINES:
324  {
325  std::array<dyna_fp_type, 4> xyzw;
326  stream >> xyzw[0];
327  stream >> xyzw[1];
328  stream >> xyzw[2];
329  stream >> xyzw[3];
330 
331  if (weight_control_flag)
332  spline_weights[n_nodes_read] = xyzw[3];
333 
334  // We'll use the spline nodes via NodeElem as the "true"
335  // degrees of freedom, to which other Elem degrees of
336  // freedom will be tied via constraint equations.
337  Node *n = spline_node_ptrs[n_nodes_read] =
338  mesh.add_point(Point(xyzw[0], xyzw[1], xyzw[2]));
340  elem->set_node(0, n);
341  elem->subdomain_id() = 1; // Separate id to ease Exodus output
342  spline_nodeelem_ptrs[n] = elem;
343  }
344  ++n_nodes_read;
345 
346  libmesh_error_msg_if(stream.fail(), "Failure to parse node line\n");
347 
348  if (n_nodes_read >= n_spline_nodes)
349  section = N_ELEM_SUBBLOCKS;
350  break;
351  case N_ELEM_SUBBLOCKS:
352  stream >> n_elem_blocks;
353  libmesh_error_msg_if(stream.fail(), "Failure to parse n_elem_blocks\n");
354 
355  block_elem_type.resize(n_elem_blocks);
356  block_n_elem.resize(n_elem_blocks);
357  block_n_nodes.resize(n_elem_blocks);
358  block_n_coef_vec.resize(n_elem_blocks);
359  block_p.resize(n_elem_blocks);
360  block_dim.resize(n_elem_blocks);
361 
362  elem_global_nodes.resize(n_elem_blocks);
363  elem_constraint_rows.resize(n_elem_blocks);
364 
365  n_elem_blocks_read = 0;
366  section = ELEM_SUBBLOCK_HEADER;
367  break;
368  case ELEM_SUBBLOCK_HEADER:
369  stream >> block_elem_type[n_elem_blocks_read];
370  stream >> block_n_elem[n_elem_blocks_read];
371  stream >> block_n_nodes[n_elem_blocks_read];
372  stream >> block_n_coef_vec[n_elem_blocks_read];
373  stream >> block_p[n_elem_blocks_read];
374 
375  libmesh_error_msg_if(stream.fail(), "Failure to parse elem block\n");
376 
377  block_dim[n_elem_blocks_read] = 1; // All blocks here are at least 1D
378 
379  dyna_int_type block_other_p; // Check for isotropic p
380  stream >> block_other_p;
381  if (!stream.fail())
382  {
383  block_dim[n_elem_blocks_read] = 2; // Found a second dimension!
384 
385  if (block_other_p != block_p[n_elem_blocks_read])
386  libmesh_not_implemented(); // We don't support p anisotropy
387 
388  stream >> block_other_p;
389  if (!stream.fail())
390  {
391  block_dim[n_elem_blocks_read] = 3; // Found a third dimension!
392 
393  if (block_other_p != block_p[n_elem_blocks_read])
394  libmesh_not_implemented();
395  }
396  }
397 
398  {
399  auto & block_global_nodes = elem_global_nodes[n_elem_blocks_read];
400  auto & block_constraint_rows = elem_constraint_rows[n_elem_blocks_read];
401 
402  block_global_nodes.resize(block_n_elem[n_elem_blocks_read]);
403  block_constraint_rows.resize(block_n_elem[n_elem_blocks_read]);
404 
405  for (auto e : make_range(block_n_elem[n_elem_blocks_read]))
406  {
407  block_global_nodes[e].resize(block_n_nodes[n_elem_blocks_read]);
408  block_constraint_rows[e].resize(block_n_coef_vec[n_elem_blocks_read]);
409  }
410  }
411 
412  n_elem_blocks_read++;
413  if (n_elem_blocks_read == n_elem_blocks)
414  {
415  n_elem_blocks_read = 0;
416  n_elems_read = 0;
417  section = ELEM_NODES_LINES;
418  }
419  break;
420  case ELEM_NODES_LINES:
421  {
422  const int end_node_to_read =
423  std::min(block_n_nodes[n_elem_blocks_read], n_elem_nodes_read + max_ints_per_line);
424  for (; n_elem_nodes_read != end_node_to_read; ++n_elem_nodes_read)
425  {
426  dyna_int_type node_id;
427  stream >> node_id;
428  node_id--;
429  elem_global_nodes[n_elem_blocks_read][n_elems_read][n_elem_nodes_read] = node_id;
430 
431  // Let's assume that our *only* mid-line breaks are
432  // due to the max_ints_per_line limit. This should be
433  // less flexible but better for error detection.
434  libmesh_error_msg_if(stream.fail(), "Failure to parse elem nodes\n");
435  }
436 
437  if (n_elem_nodes_read == block_n_nodes[n_elem_blocks_read])
438  {
439  n_elem_nodes_read = 0;
440  section = ELEM_COEF_VEC_IDS;
441  }
442  }
443  break;
444  case ELEM_COEF_VEC_IDS:
445  {
446  const int end_cvid_to_read =
447  std::min(block_n_coef_vec[n_elem_blocks_read], n_elem_cvids_read + max_ints_per_line);
448  for (; n_elem_cvids_read != end_cvid_to_read; ++n_elem_cvids_read)
449  {
450  dyna_int_type node_cvid;
451  stream >> node_cvid;
452  node_cvid--;
453 
454  elem_constraint_rows[n_elem_blocks_read][n_elems_read][n_elem_cvids_read] = node_cvid;
455 
456  // Let's assume that our *only* mid-line breaks are
457  // due to the max_ints_per_line limit. This should be
458  // less flexible but better for error detection.
459  libmesh_error_msg_if(stream.fail(), "Failure to parse elem cvids\n");
460  }
461  if (n_elem_cvids_read == block_n_nodes[n_elem_blocks_read])
462  {
463  n_elem_cvids_read = 0;
464  n_elems_read++;
465  section = ELEM_NODES_LINES; // Read another elem, nodes first
466  if (n_elems_read == block_n_elem[n_elem_blocks_read])
467  {
468  n_elems_read = 0;
469  n_elem_blocks_read++;
470  if (n_elem_blocks_read == n_elem_blocks)
471  section = N_COEF_BLOCKS; // Move on to coefficient vectors
472  }
473  }
474  }
475  break;
476  case N_COEF_BLOCKS:
477  {
478  stream >> n_dense_coef_vec_blocks;
479  dyna_int_type n_sparse_coef_vec_blocks;
480  stream >> n_sparse_coef_vec_blocks;
481 
482  libmesh_error_msg_if(stream.fail(), "Failure to parse n_*_coef_vec_blocks\n");
483 
484  if (n_sparse_coef_vec_blocks != 0)
485  libmesh_not_implemented();
486 
487  dense_constraint_vecs.resize(n_dense_coef_vec_blocks);
488  n_coef_vecs_in_subblock.resize(n_dense_coef_vec_blocks);
489  n_coef_comp.resize(n_dense_coef_vec_blocks);
490 
491  section = N_VECS_PER_BLOCK;
492  }
493  break;
494  case N_VECS_PER_BLOCK:
495  stream >> n_coef_vecs_in_subblock[n_coef_headers_read];
496  stream >> n_coef_comp[n_coef_headers_read];
497 
498  libmesh_error_msg_if(stream.fail(), "Failure to parse dense coef subblock header\n");
499 
500  dense_constraint_vecs[n_coef_headers_read].resize
501  (n_coef_vecs_in_subblock[n_coef_headers_read]);
502 
503  for (auto & vec : dense_constraint_vecs[n_coef_headers_read])
504  vec.resize(n_coef_comp[n_coef_headers_read]);
505 
506  n_coef_headers_read++;
507  if (n_coef_headers_read == n_dense_coef_vec_blocks)
508  {
509  n_coef_headers_read = 0;
510  section = COEF_VEC_COMPONENTS;
511  }
512  break;
513  case COEF_VEC_COMPONENTS:
514  {
515  auto & current_vec =
516  dense_constraint_vecs[n_coef_blocks_read][n_coef_vecs_read];
517 
518  const int end_coef_to_read =
519  std::min(n_coef_comp[n_coef_blocks_read],
520  n_coef_comp_read + max_fps_per_line);
521  for (; n_coef_comp_read != end_coef_to_read; ++n_coef_comp_read)
522  {
523  dyna_fp_type coef_comp;
524  stream >> coef_comp;
525 
526  current_vec[n_coef_comp_read] = coef_comp;
527 
528  // Let's assume that our *only* mid-line breaks are
529  // due to the max_fps_per_line limit. This should be
530  // less flexible but better for error detection.
531  libmesh_error_msg_if(stream.fail(), "Failure to parse coefficients\n");
532  }
533  if (n_coef_comp_read == n_coef_comp[n_coef_blocks_read])
534  {
535  n_coef_comp_read = 0;
536  n_coef_vecs_read++;
537  if (n_coef_vecs_read == n_coef_vecs_in_subblock[n_coef_blocks_read])
538  {
539  n_coef_vecs_read = 0;
540  n_coef_blocks_read++;
541  if (n_coef_blocks_read == n_dense_coef_vec_blocks)
542  section = END_OF_FILE;
543  }
544  }
545  }
546  break;
547  default:
548  libmesh_error();
549  }
550 
551  if (section == END_OF_FILE)
552  break;
553  } // if (in)
554  else if (in.eof())
555  libmesh_error_msg("Premature end of file");
556  else
557  libmesh_error_msg("Input stream failure! Perhaps the file does not exist?");
558  }
559 
560  // Merge dense_constraint_vecs blocks
561  if (n_dense_coef_vec_blocks)
562  for (auto coef_vec_block :
563  IntRange<dyna_int_type>(1, n_dense_coef_vec_blocks))
564  {
565  auto & dcv0 = dense_constraint_vecs[0];
566  auto & dcvi = dense_constraint_vecs[coef_vec_block];
567  dcv0.insert(dcv0.end(),
568  std::make_move_iterator(dcvi.begin()),
569  std::make_move_iterator(dcvi.end()));
570  }
571  dense_constraint_vecs.resize(1);
572 
573  // Constraint matrices:
574  // elem_constraint_mat[block_num][elem_num][local_node_index][elem_global_nodes_index] = c
575  std::vector<std::vector<std::vector<std::vector<Real>>>> elem_constraint_mat(n_elem_blocks);
576 
577  // We need to calculate local nodes on the fly, and we'll be
578  // calculating them from constraint matrix columns, and we'll need
579  // to make sure that the same node is found each time it's
580  // calculated from multiple neighboring elements.
581  std::map<std::vector<std::pair<dof_id_type, Real>>, Node *> local_nodes;
582 
583  auto & constraint_rows = mesh.get_constraint_rows();
584 
585  for (auto block_num : make_range(n_elem_blocks))
586  {
587  elem_constraint_mat[block_num].resize(block_n_elem[block_num]);
588 
589  for (auto elem_num :
590  make_range(block_n_elem[block_num]))
591  {
592  // Consult the import element table to determine which element to build
593  const ElementDefinition & elem_defn =
594  find_elem_definition(block_elem_type[block_num],
595  block_dim[block_num],
596  block_p[block_num]);
597 
598  auto elem = Elem::build(elem_defn.type);
599  libmesh_error_msg_if(elem->dim() != block_dim[block_num],
600  "Elem dim " << elem->dim() <<
601  " != block_dim " << block_dim[block_num]);
602 
603  auto & my_constraint_rows = elem_constraint_rows[block_num][elem_num];
604  auto & my_global_nodes = elem_global_nodes[block_num][elem_num];
605  auto & my_constraint_mat = elem_constraint_mat[block_num][elem_num];
606 
607  my_constraint_mat.resize(block_n_coef_vec[block_num]);
608  for (auto spline_node_index :
609  make_range(block_n_coef_vec[block_num]))
610  my_constraint_mat[spline_node_index].resize(elem->n_nodes());
611 
612  for (auto spline_node_index :
613  make_range(block_n_coef_vec[block_num]))
614  {
615  // Find which coef block this elem's vectors are from
616  const dyna_int_type elem_coef_vec_index =
617  my_constraint_rows[spline_node_index];
618 
619  dyna_int_type coef_block_num = 0;
620  dyna_int_type first_block_coef_vec = 0;
621  for (; elem_coef_vec_index >= first_block_coef_vec &&
622  coef_block_num != n_dense_coef_vec_blocks; ++coef_block_num)
623  {
624  first_block_coef_vec += n_coef_vecs_in_subblock[coef_block_num];
625  }
626 
627  // Make sure we did find a valid coef block
628  libmesh_error_msg_if(coef_block_num == n_dense_coef_vec_blocks &&
629  first_block_coef_vec <= elem_coef_vec_index,
630  "Can't find valid constraint coef vector");
631 
632  coef_block_num--;
633 
634  libmesh_error_msg_if
635  (dyna_int_type(elem->n_nodes()) != n_coef_comp[coef_block_num],
636  "Found " << n_coef_comp[coef_block_num] <<
637  " constraint coef vectors for " <<
638  elem->n_nodes() << " nodes");
639 
640  for (auto elem_node_index :
641  make_range(elem->n_nodes()))
642  my_constraint_mat[spline_node_index][elem_node_index] =
643  dense_constraint_vecs[0][elem_coef_vec_index][elem_node_index];
644  }
645 
646  for (auto elem_node_index :
647  make_range(elem->n_nodes()))
648  {
649  dof_id_type global_node_idx = DofObject::invalid_id;
650 
651  // New finite element node data: dot product of
652  // constraint matrix columns with spline node data.
653  // Store that column as a key.
654  std::vector<std::pair<dof_id_type, Real>> key;
655 
656  for (auto spline_node_index :
657  make_range(block_n_coef_vec[block_num]))
658  {
659  const dyna_int_type elem_coef_vec_index =
660  my_constraint_rows[spline_node_index];
661 
662  const Real coef =
663  libmesh_vector_at(dense_constraint_vecs[0],
664  elem_coef_vec_index)[elem_node_index];
665 
666  // Global nodes are supposed to be in sorted order
667  if (global_node_idx != DofObject::invalid_id)
668  libmesh_error_msg_if(my_global_nodes[spline_node_index] <= global_node_idx,
669  "Found unsorted global node");
670 
671  global_node_idx = my_global_nodes[spline_node_index];
672 
673  if (coef != 0) // Ignore irrelevant spline nodes
674  key.emplace_back(global_node_idx, coef);
675  }
676 
677  if (const auto local_node_it = local_nodes.find(key);
678  local_node_it != local_nodes.end())
679  elem->set_node(elem_defn.nodes[elem_node_index],
680  local_node_it->second);
681  else
682  {
683  Point p(0);
684  Real w = 0;
685  std::vector<std::pair<std::pair<const Elem *, unsigned int>, Real>> constraint_row;
686 
687  for (auto spline_node_index :
688  make_range(block_n_coef_vec[block_num]))
689  {
690  const dof_id_type my_node_idx =
691  my_global_nodes[spline_node_index];
692 
693  const dyna_int_type elem_coef_vec_index =
694  my_constraint_rows[spline_node_index];
695 
696  Node * spline_node =
697  libmesh_vector_at(spline_node_ptrs,
698  my_node_idx);
699 
700  const Real coef =
701  libmesh_vector_at(dense_constraint_vecs[0],
702  elem_coef_vec_index)[elem_node_index];
703  p.add_scaled(*spline_node, coef);
704  w += coef * libmesh_vector_at(spline_weights,
705  my_node_idx);
706 
707  // We don't need to store 0 entries;
708  // constraint_rows is a sparse structure.
709  if (coef)
710  {
711  Elem * nodeelem =
712  libmesh_map_find(spline_nodeelem_ptrs, spline_node);
713  constraint_row.emplace_back(std::make_pair(nodeelem, 0), coef);
714  }
715  }
716 
717  Node *n = mesh.add_point(p);
718  if (weight_control_flag)
719  n->set_extra_datum<Real>(weight_index, w);
720  local_nodes[key] = n;
721  elem->set_node(elem_defn.nodes[elem_node_index], n);
722 
723  constraint_rows[n] = constraint_row;
724  }
725  }
726 
727  mesh.add_elem(std::move(elem));
728  }
729  }
730 
731  if (!_keep_spline_nodes)
733 }
734 
735 
737  unsigned int,
738  unsigned int)
739 {
740 }
741 
742 
743 #ifdef LIBMESH_ENABLE_DEPRECATED
745 {
746  libmesh_deprecated();
747 
749 }
750 #endif // LIBMESH_ENABLE_DEPRECATED
751 
752 
753 
756  int dim, int p)
757 {
758  auto eletypes_it =
759  _element_maps.in.find(std::make_tuple(dyna_elem, dim, p));
760 
761  // Make sure we actually found something
762  libmesh_error_msg_if
763  (eletypes_it == _element_maps.in.end(),
764  "Element of type " << dyna_elem <<
765  " dim " << dim <<
766  " degree " << p << " not found!");
767 
768  return eletypes_it->second;
769 }
770 
771 
772 
775  int libmesh_dbg_var(dim),
776  int libmesh_dbg_var(p))
777 {
778  auto eletypes_it =
779  _element_maps.out.find(libmesh_elem);
780 
781  // Make sure we actually found something
782  libmesh_error_msg_if
783  (eletypes_it == _element_maps.out.end(),
784  "Element of type " << libmesh_elem <<
785  " not found!");
786 
787  // Make sure we found the right thing
788  libmesh_assert_equal_to(eletypes_it->second.dim, dim);
789  libmesh_assert_equal_to(eletypes_it->second.p, p);
790 
791 
792  return eletypes_it->second;
793 }
794 
795 
796 
797 
798 } // namespace libMesh
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
Definition: elem_quality.C:42
ElemType
Defines an enum for geometric element types.
virtual void read(const std::string &name) override
Reads in a mesh in the Dyna format from the ASCII file given by name.
Definition: dyna_io.C:139
std::vector< Node * > spline_node_ptrs
Definition: dyna_io.h:159
void add_scaled(const TypeVector< T2 > &, const T &)
Add a scaled value to this vector without creating a temporary.
Definition: type_vector.h:629
constraint_rows_type & get_constraint_rows()
Constraint rows accessors.
Definition: mesh_base.h:1703
virtual Node *& set_node(const unsigned int i)
Definition: elem.h:2558
A Node is like a Point, but with more information.
Definition: node.h:52
int32_t dyna_int_type
The integer type DYNA uses.
Definition: dyna_io.h:116
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
Definition: libmesh.h:310
The IntRange templated class is intended to make it easy to loop over integers which are indices of a...
Definition: int_range.h:53
double dyna_fp_type
The floating-point type DYNA uses.
Definition: dyna_io.h:182
dof_id_type n_elem(const MeshBase::const_element_iterator &begin, const MeshBase::const_element_iterator &end)
Count up the number of elements of a specific type (as defined by an iterator range).
Definition: mesh_tools.C:969
unsigned int dim
void read_mesh(std::istream &in)
Implementation of the read() function.
Definition: dyna_io.C:177
void clear_spline_nodes(MeshBase &)
Remove spline node (for IsoGeometric Analysis meshes) elements and nodes and constraints from the mes...
Definition: mesh_tools.C:1147
Defines mapping from libMesh element types to LS-DYNA element types or vice-versa.
Definition: dyna_io.h:125
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
void clear_spline_nodes()
Removes any spline nodes (both NodeElem and Node), leaving only the FE mesh generated from those spli...
Definition: dyna_io.C:744
void add_def(const ElementDefinition &eledef)
Definition: dyna_io.h:196
bool _keep_spline_nodes
Whether to keep or eventually discard spline nodes.
Definition: dyna_io.h:165
The libMesh namespace provides an interface to certain functionality in the library.
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
static const unsigned int type_to_n_nodes_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of nodes in the element...
Definition: elem.h:650
void iota(ForwardIter first, ForwardIter last, T value)
Utility::iota was created back when std::iota was just an SGI STL extension.
Definition: utility.h:229
This is the MeshBase class.
Definition: mesh_base.h:75
void add_spline_constraints(DofMap &dof_map, unsigned int sys_num, unsigned int var_num)
Constrains finite element degrees of freedom in terms of spline degrees of freedom by adding user-def...
Definition: dyna_io.C:736
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:179
static const ElementDefinition & find_elem_definition(dyna_int_type dyna_elem, int dim, int p)
Finds the ElementDefinition corresponding to a particular element type.
Definition: dyna_io.C:755
const dof_id_type n_nodes
Definition: tecplot_io.C:67
This class defines an abstract interface for Mesh input.
Definition: mesh_base.h:57
std::map< ElemType, ElementDefinition > out
Definition: dyna_io.h:202
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition: elem.C:444
void set_default_mapping_type(const ElemMappingType type)
Set the default master space to physical space mapping basis functions to be used on newly added elem...
Definition: mesh_base.h:821
std::string unzip_file(std::string_view name)
Create an unzipped copy of a bz2 or xz file, returning the name of the now-unzipped file that can be ...
Definition: utility.C:164
libmesh_assert(ctx)
static const dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
Definition: dof_object.h:482
void set_extra_datum(const unsigned int index, const T value)
Sets the value on this object of the extra datum associated with index, which should have been obtain...
Definition: dof_object.h:1126
static ElementMaps build_element_maps()
A static function used to construct the _element_maps struct, statically.
Definition: dyna_io.C:53
static const int max_fps_per_line
How many can we find on a line?
Definition: dyna_io.h:187
virtual void clear()
Deletes all the element and node data that is currently stored.
Definition: mesh_base.C:920
unsigned int add_node_datum(const std::string &name, bool allocate_data=true, const T *default_value=nullptr)
Register a datum (of type T) to be added to each node in the mesh.
Definition: mesh_base.h:2341
DynaIO(MeshBase &mesh, bool keep_spline_nodes=true)
Constructor.
Definition: dyna_io.C:130
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
subdomain_id_type subdomain_id() const
Definition: elem.h:2582
std::unordered_map< Node *, Elem * > spline_nodeelem_ptrs
Definition: dyna_io.h:160
static ElementMaps _element_maps
A static ElementMaps object that is built statically and used by all instances of this class...
Definition: dyna_io.h:213
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition: int_range.h:140
void set_default_mapping_data(const unsigned char data)
Set the default master space to physical space mapping basis functions to be used on newly added elem...
Definition: mesh_base.h:839
static const int max_ints_per_line
How many can we find on a line?
Definition: dyna_io.h:177
struct which holds a map from LS-DYNA to libMesh element numberings and vice-versa.
Definition: dyna_io.h:193
std::vector< unsigned int > nodes
Definition: dyna_io.h:142
processor_id_type processor_id() const
std::map< Key, ElementDefinition > in
Definition: dyna_io.h:206
ElementDefinition(ElemType type_in, dyna_int_type dyna_type_in, dyna_int_type dim_in, dyna_int_type p_in)
Definition: dyna_io.C:98
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
uint8_t dof_id_type
Definition: id_types.h:67