MAST
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
nastran_io.cpp
Go to the documentation of this file.
1 /*
2  * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit
3  * Copyright (C) 2013-2020 Manav Bhatia and MAST authors
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 // C++ includes.
21 #include <vector>
22 #include <map>
23 
24 // libMesh includes.
25 #include <libmesh/point.h>
26 #include <libmesh/elem.h>
27 #include <libmesh/string_to_enum.h>
28 #include <libmesh/boundary_info.h>
29 // #include <libmesh/utility.h>
30 #include <libmesh/libmesh_common.h>
31 #include <libmesh/mesh_input.h>
32 // #include <libmesh/elem.h>
33 
34 #include "base/mast_config.h"
35 
36 // MAST includes.
37 #include "mesh/nastran_io.h"
38 #include "libfort/fort.hpp"
39 
40 
41 MAST::NastranIO::NastranIO(libMesh::MeshBase& mesh, const bool python_preinit):
42 libMesh::MeshInput<libMesh::MeshBase> (mesh),
43 python_preinitialized(python_preinit)
44 {
45  // Initialize Python if it hasn't already been initialized.
47  {
49  }
50 }
51 
52 
54 {
56  {
58  }
59 }
60 
61 
62 std::map<uint64_t, libMesh::Node*> MAST::NastranIO::get_nastran_to_libmesh_node_map()
63 {
65 }
66 
67 
68 std::map<const libMesh::Node*, uint64_t> MAST::NastranIO::get_libmesh_to_nastran_node_map()
69 {
71 }
72 
73 
74 std::map<uint64_t, libMesh::Elem*> MAST::NastranIO::get_nastran_to_libmesh_elem_map()
75 {
77 }
78 
79 
80 std::map<libMesh::Elem*, uint64_t> MAST::NastranIO::get_libmesh_to_nastran_elem_map()
81 {
83 }
84 
85 
87 {
88  std::map<int, std::set<int>> property_id_to_subdomain_id_map;
89  for (const auto& item : nastran_pid_elemtype_to_libmesh_subdomain_map)
90  {
91  int pid = item.first.first;
92  int sid = item.second;
93  property_id_to_subdomain_id_map[pid].insert(sid);
94  }
95 
96  return property_id_to_subdomain_id_map;
97 }
98 
99 
101 {
103 }
104 
105 void MAST::NastranIO::read_nodes(BDFModel* model, libMesh::MeshBase& the_mesh)
106 {
107  // Get the nodes from the bulk data file
108  std::vector<std::vector<double>> nodes = getNodes(model);
109 
110  // Reserve space in the mesh for the nodes and elements
111  the_mesh.reserve_nodes(model->nNodes);
112 
113  // Add the nodes to the mesh
114  uint64_t i = 0;
115  for (const auto& node : nodes)
116  {
117  double x=node[1], y=node[2], z=node[3];
118  uint64_t nid=node[0];
119  the_mesh.add_point(libMesh::Point(x, y, z), nid);
120  nastran_to_libmesh_node_map[nid] = the_mesh.node_ptr(nid);
121  libmesh_to_nastran_node_map[the_mesh.node_ptr(nid)] = nid;
122  i++;
123  }
124 
125 }
126 
127 
128 void MAST::NastranIO::read_elements(BDFModel* model, libMesh::MeshBase& the_mesh)
129 {
130  // Reserve space in the mesh for the nodes and elements
131  the_mesh.reserve_elem(model->nElems);
132 
133  // Get the elements from the bulk data file
134  // Map of <string, vector<vector<int>>>, first is name of element type and
135  // second is vector of EID, PID, and Node_Numbers in that order.
136  std::map<std::string, std::vector<std::vector<int>>> elements = getElements(model);
137 
138  // Loop through all the elements and add them to the mesh
139  uint64_t k = 0;
140  uint64_t z = 1;
141  for (const auto& item : elements) // Loop through element types on outer loop
142  {
143  // Determine the appropriate libMesh element type
144  libMesh::ElemType elem_type;
145  if (nastran_to_libmesh_elem_type_map.find(item.first) ==
147  {
148  libmesh_error_msg("ERROR: " << item.first
149  << " not found in nastran_to_libmesh_elem_type_map map in nastran_io.h");
150  }
151  else
152  {
153  elem_type = nastran_to_libmesh_elem_type_map[item.first];
154  }
155 
156  // Loop through all elements that belong to this element type on inner loop
157  for (uint i=0; i<item.second.size(); i++)
158  {
159  // Add the element to the mesh and sepcify its ID and nodes
160  libMesh::Elem * elem = the_mesh.add_elem(libMesh::Elem::build(elem_type).release());
161  const libMesh::dof_id_type eid = item.second[i][0];
162  elem->set_id(k);
163  nastran_to_libmesh_elem_map[eid] = the_mesh.elem_ptr(k);
164  libmesh_to_nastran_elem_map[the_mesh.elem_ptr(k)] = eid;
165  elem->set_id(eid);
166 
167  // Determine element type and property ID
168  // This is used to determine the subdomain id and separates elements
169  // into subdomains based on property id and element type. This is
170  // needed because some output formats (i.e. exodus) do not support
171  // multiple element types in one subdomain.
172  const libMesh::subdomain_id_type pid = item.second[i][1];
173  const int elemtype = int(elem->type());
174  if (nastran_pid_elemtype_to_libmesh_subdomain_map.find({pid, elemtype}) ==
176  { // If the {pid, elemtype} pair is not yet defined in the map, define it.
178  z++;
179  }
180 
181  // Set the element subdomain
182  const libMesh::subdomain_id_type sid = nastran_pid_elemtype_to_libmesh_subdomain_map[{pid, elemtype}];
183  elem->subdomain_id() = sid;
184 
185  // Set the nodes which belong to this element
186  for (uint j=2; j<(item.second[i].size()); j++)
187  {
188  uint node_num = item.second[i][j];
189  libMesh::dof_id_type nid = nastran_to_libmesh_node_map[node_num]->id();
190  elem->set_node(j-2) = the_mesh.node_ptr(nid);
191  }
192 
193  k++; // Increment element counter
194  } // End for loop over elements of same type
195  } // End for loop over element types
196 }
197 
198 
199 void MAST::NastranIO::read_node_boundaries(BDFModel* model, libMesh::MeshBase& the_mesh)
200 {
201  // Currently we simply translate all the SPC ID's that show up inside the BDF
202  // over into node boundaries in libMesh.
203 
204  std::map<std::string, std::vector<int>> SPCs = getSPCs(model);
205  uint j=1;
206  for (const auto& spc : SPCs)
207  {
208  for (uint i=0; i<spc.second.size(); i++)
209  {
210  the_mesh.boundary_info->add_node(nastran_to_libmesh_node_map[spc.second[i]], j);
211  }
212  j++;
213  }
214 }
215 
216 
217 void MAST::NastranIO::read (const std::string& filename)
218 {
219  // Get a reference to the mesh we are reading
220  libMesh::MeshBase& the_mesh = MeshInput<libMesh::MeshBase>::mesh();
221 
222  // Clear any existing mesh data
223  the_mesh.clear();
224 
225  // Read the Nastran BDF using pyNastran
226  BDFModel* model = buildBDFModel(filename);
227 
228  // Set the dimensions of the mesh
229  the_mesh.set_mesh_dimension(model->nDims);
230 
231  // Add nodes from the model to the mesh
232  read_nodes(model, the_mesh);
233 
234  // Add elements from the model to the mesh
235  read_elements(model, the_mesh);
236 
237  // Add nodal boundary conditions defined as SPCs from the model to the mesh
238  read_node_boundaries(model, the_mesh);
239 
240  // Prepare mesh for use.
241  the_mesh.prepare_for_use();
242 }
243 
244 
246 {
247  // Get a reference to the mesh we are reading
248  libMesh::MeshBase& the_mesh = MeshInput<libMesh::MeshBase>::mesh();
249 
250  // Clear any existing mesh data
251  the_mesh.clear();
252 
253  // Set the dimensions of the mesh
254  the_mesh.set_mesh_dimension(model->nDims);
255 
256  // Add nodes from the model to the mesh
257  read_nodes(model, the_mesh);
258 
259  // Add elements from the model to the mesh
260  read_elements(model, the_mesh);
261 }
262 
263 
265 {
266  // StackOverFlow, "Use generated header file from Cython"
267  // - related to using multi-stage imports
268  int status = PyImport_AppendInittab("pynastran_io", PyInit_pynastran_io);
269  if(status==-1){
270  libmesh_error_msg("ERROR: During Python import for pynastran_io.");
271  }
272  Py_Initialize();
273 
274  PyObject* pynastran_module = PyImport_ImportModule("pynastran_io");
275 
276  if(pynastran_module==NULL){
277  PyErr_Print(); // Prints out error that occurred back in the Python interpreter.
278  Py_Finalize();
279  libmesh_error_msg("ERROR: During Python initialization for pynastran_io.");
280  }
281  python_initialized = true;
282 }
283 
284 
286 {
287  Py_Finalize();
288  python_initialized = false;
289 }
290 
291 
293  fort::table table;
294  table << fort::header << "Nastran Property ID" << "libMesh/MAST Subdomain ID" << fort::endr;
295 
296  std::string sid_str; // must reduce std::set of libMesh subdomain IDs to string for table output.
297  for (const auto& id_pair: get_nastran_property_to_libmesh_subdomains_map()) {
298  table << std::to_string(id_pair.first);
299  for (const auto& sid: id_pair.second) {
300  sid_str.append(std::to_string(sid) + " ");
301  }
302  table << sid_str << fort::endr;
303  }
304  libMesh::out << std::endl << "DOMAIN MAPPING" << std::endl;
305  libMesh::out << table.to_string() << std::endl;
306 }
307 
308 
309 void MAST::printElementMap(std::map<std::string, std::vector<std::vector<int>>> elementMap)
310 {
311  // Iterate through element types
312  for (const auto& item : elementMap)
313  {
314  libMesh::out << "Element Type: " << item.first << std::endl;
315 
316  // Iterate through elements
317  for (const auto& elem : item.second)
318  {
319  libMesh::out << "Element ID: " << elem[0] << "\tPID: " << elem[1] << "\tNodes: ";
320  // Iterate through nodes
321  for (uint j=2; j<elem.size(); j++)
322  {
323  libMesh::out << elem[j] << "\t";
324  }
325  libMesh::out << "" << std::endl;
326  }
327  }
328 }
329 
330 
331 void MAST::printNodeCoords(std::vector<std::vector<double>> nodes)
332 {
333  // Iterate through nodes
334  for (const auto& node : nodes)
335  {
336  libMesh::out << "Node # " << node[0] << ":\t" << node[1] << "\t" << node[2] << "\t" << node[3] << "\t" << std::endl;
337  }
338 }
339 
void print_pid_to_subdomain_id_map()
Print map between Nastran property ID&#39;s (PID) to libMesh subdomain ID&#39;s (SID) to libMesh::out.
Definition: nastran_io.cpp:292
NastranIO(libMesh::MeshBase &mesh, const bool python_preinit=false)
Constructor.
Definition: nastran_io.cpp:41
std::map< uint64_t, libMesh::Node * > nastran_to_libmesh_node_map
Mapping from Nastran grid IDs from BDF input to pointers to libMesh/MAST nodes.
Definition: nastran_io.h:157
std::map< const libMesh::Node *, uint64_t > get_libmesh_to_nastran_node_map()
Returns mapping between libMesh/MAST nodes and Nastran BDF grid ID&#39;s.
Definition: nastran_io.cpp:68
std::map< uint64_t, libMesh::Elem * > nastran_to_libmesh_elem_map
Mapping from Nastran element IDs from BDF input to pointers to libMesh/MAST elements.
Definition: nastran_io.h:161
void read_node_boundaries(BDFModel *model, libMesh::MeshBase &the_mesh)
Definition: nastran_io.cpp:199
__PYX_EXTERN_C std::map< std::string, std::vector< std::vector< int > > > getElements(struct BDFModel *)
__PYX_EXTERN_C std::vector< std::vector< double > > getNodes(struct BDFModel *)
void printNodeCoords(std::vector< std::vector< double >> nodes)
Definition: nastran_io.cpp:331
virtual ~NastranIO()
Destructor.
Definition: nastran_io.cpp:53
void read_elements(BDFModel *model, libMesh::MeshBase &the_mesh)
Definition: nastran_io.cpp:128
std::map< libMesh::Elem *, uint64_t > get_libmesh_to_nastran_elem_map()
Returns mapping between libMesh/MAST elements and Nastran BDF element ID&#39;s.
Definition: nastran_io.cpp:80
__PYX_EXTERN_C struct BDFModel * buildBDFModel(std::string)
void read_nodes(BDFModel *model, libMesh::MeshBase &the_mesh)
Definition: nastran_io.cpp:105
std::map< std::pair< int, int >, int > get_nastran_pid_elemtype_to_libmesh_subdomain_map()
Provides mapping between Nastran property ID & element-type pairs and corresponding libMesh/MAST subdomai...
Definition: nastran_io.cpp:100
std::map< std::string, libMesh::ElemType > nastran_to_libmesh_elem_type_map
Map from Nastran elements to equivalent libMesh/MAST element types.
Definition: nastran_io.h:185
std::map< libMesh::Elem *, uint64_t > libmesh_to_nastran_elem_map
Mapping from libMesh/MAST element pointers to Nastran element IDs from BDF input. ...
Definition: nastran_io.h:163
void initialize_python()
Definition: nastran_io.cpp:264
__PYX_EXTERN_C std::map< std::string, std::vector< int > > getSPCs(struct BDFModel *)
bool python_initialized
Indicates is Python has been initialized.
Definition: nastran_io.h:154
int nNodes
Definition: pynastran_io.h:19
int nElems
Definition: pynastran_io.h:20
void printElementMap(std::map< std::string, std::vector< std::vector< int >>> elementMap)
Definition: nastran_io.cpp:309
std::map< uint64_t, libMesh::Elem * > get_nastran_to_libmesh_elem_map()
Returns mapping between Nastran BDF element ID&#39;s and libMesh/MAST elements.
Definition: nastran_io.cpp:74
virtual void read(const std::string &filename) override
Read ASCII NASTRAN BDF given by filename.
Definition: nastran_io.cpp:217
std::map< uint64_t, libMesh::Node * > get_nastran_to_libmesh_node_map()
Returns mapping between Nastran BDF grid ID&#39;s and libMesh/MAST nodes.
Definition: nastran_io.cpp:62
void finalize_python()
Definition: nastran_io.cpp:285
const bool python_preinitialized
Indicates if Python was initialized outside of NastranIO class.
Definition: nastran_io.h:152
std::map< const libMesh::Node *, uint64_t > libmesh_to_nastran_node_map
Mapping from libMesh/MAST node pointers to Nastran grid IDs from BDF input.
Definition: nastran_io.h:159
std::map< std::pair< int, int >, int > nastran_pid_elemtype_to_libmesh_subdomain_map
Mapping from Nastran property ID/element-type pair to libMesh/MAST subdomain.
Definition: nastran_io.h:175
std::map< int, std::set< int > > get_nastran_property_to_libmesh_subdomains_map()
Returns mapping between Nastran property ID&#39;s and sets of libMesh/MAST subdomains.
Definition: nastran_io.cpp:86