[MOAB-dev] r3171 - MOAB/trunk

bmsmith6 at wisc.edu bmsmith6 at wisc.edu
Tue Sep 29 10:22:50 CDT 2009


Author: bmsmith
Date: 2009-09-29 10:22:50 -0500 (Tue, 29 Sep 2009)
New Revision: 3171

Modified:
   MOAB/trunk/MBReaderWriterSet.cpp
   MOAB/trunk/ReadNASTRAN.cpp
   MOAB/trunk/ReadNASTRAN.hpp
Log:
Improved reader by:
-checking for file format
-get tokens from fixed-length fields instead of using whitespace
-using null-terminated strings
-better parsing of real numbers



Modified: MOAB/trunk/MBReaderWriterSet.cpp
===================================================================
--- MOAB/trunk/MBReaderWriterSet.cpp	2009-09-27 15:19:59 UTC (rev 3170)
+++ MOAB/trunk/MBReaderWriterSet.cpp	2009-09-29 15:22:50 UTC (rev 3171)
@@ -80,7 +80,8 @@
   
   register_factory( ReadMCNP5::factory, NULL, "MCNP5 format", "meshtal", "MESHTAL" );
   
-  register_factory( ReadNASTRAN::factory, NULL, "NASTRAN format", "nas", "NAS" );
+  const char* nastran_sufxs[] = { "nas", "bdf" };
+  register_factory( ReadNASTRAN::factory, NULL, "NASTRAN format", nastran_sufxs, "NAS" );
 
   register_factory( ReadABAQUS::factory, NULL, "ABAQUS INP mesh format", "abq", "Abaqus mesh" );
   

Modified: MOAB/trunk/ReadNASTRAN.cpp
===================================================================
--- MOAB/trunk/ReadNASTRAN.cpp	2009-09-27 15:19:59 UTC (rev 3170)
+++ MOAB/trunk/ReadNASTRAN.cpp	2009-09-29 15:22:50 UTC (rev 3171)
@@ -83,7 +83,6 @@
   bool debug = false;
   if (debug) std::cout << "begin ReadNASTRAN::load_file" << std::endl;
   MBErrorCode result;
-  FILE* file = fopen( filename, "r" );
 
   // create the file set
   result = MBI->create_meshset(MESHSET_SET, file_set);
@@ -98,36 +97,38 @@
                            MB_TYPE_INTEGER, material_tag, 0);
   if(MB_SUCCESS!=result && MB_ALREADY_ALLOCATED!=result) return result;
 
-  // IMPORTANT: these are the same as the MOAB enums. Currently only vertices,
-  // tets, and prisms are supported. Implement more as needed.
-  const char* const data_type_names[] = { "GRID",     // MBVERTEX
-                                          "MBEDGE",
-                                          "MBTRI",
-                                          "MBQUAD",
-                                          "MBPOLYGON",
-                                          "CTETRA",   // MBTET
-                                          "MBPYRAMID",
-                                          "CPENTA",   // MBPRISM
-                                          "MBKNIFE",
-                                          "MBHEX",
-                                          "MBPOLYHEDRON", 
-                                          "MBENTITYSET",
-                                          "MBMAXTYPE" };
-
-  /* Count the entities of each type in the file. If the token is not
-  matched assume that it is something else in the file (not an error).
-  During the next read we will check for errors.
-  This is used to allocate the node array. Let the tokenizer run out of 
-  scope (and thus call fclose). There is no other way to rewind the 
-  tokenizer. */
+  // Count the entities of each type in the file. This is used to allocate the node array. 
   int entity_count[MBMAXTYPE];
   for(int i=0; i<MBMAXTYPE; i++) entity_count[i] = 0;
-  { FileTokenizer tokens( file, readMeshIface );
-    while( !tokens.eof() ) {
-      int data = tokens.match_token( data_type_names ) -1;
-      if(-1 != data) entity_count[data]++;
-    }
-  }   
+ 
+  /* Determine the line_format of the first line. Assume that the entire file 
+     has the same format. */  
+  std::string line;
+  std::ifstream file (filename);
+  getline(file,line);
+  line_format format;
+  result = determine_line_format( line, format );
+  if(MB_SUCCESS != result) return result;
+
+  /* Count the number of each entity in the file. This allows one to allocate
+     a sequential array of vertex handles. */
+  while(!file.eof()) {
+    // Cut the line into fields as determined by the line format.
+    // Use a vector to allow for an unknown number of tokens (continue lines).
+    // Continue lines are not implemented.
+    std::vector<std::string> tokens;
+    tokens.reserve(10); // assume 10 fields to avoid extra vector resizing
+    result = tokenize_line( line, format, tokens );
+    if(MB_SUCCESS != result) return result;
+
+    // Process the tokens of the line. The first token describes the entity type.
+    MBEntityType type;
+    result = determine_entity_type( tokens.front(), type );
+    if(MB_SUCCESS != result) return result;
+    entity_count[type]++;
+    getline(file,line);
+  }      
+
   if(debug) {
     for(int i=0; i<MBMAXTYPE; i++) {
       std::cout << "entity_count[" << i << "]=" << entity_count[i] << std::endl;
@@ -135,79 +136,203 @@
   }
 
   /* If we assume that the node ids are continuous, then the node ids can be
-  easily mapped to vertex handles. If they are not continuous then the node
-  ids themselves will need to be used to create connectivity. It is very 
-  slow to find each node by its id because this is a tag call. */
+     easily mapped to vertex handles. If they are not continuous then the node
+     ids themselves will need to be used to create connectivity. It is very 
+     slow to find each node by its id because this is a tag call. */
   bool node_ids_are_continuous = true;
 
   // Now that the number of vertices is known, create the vertices.
   MBEntityHandle start_vert = NULL;
   std::vector<double*> coord_arrays(3);
   result = readMeshIface->get_node_arrays( 3, entity_count[0], MB_START_ID,
-                                           start_vert, coord_arrays );
+					   start_vert, coord_arrays );
   if(MB_SUCCESS != result) return result;
   if(0 == start_vert) return MB_FAILURE; // check for NULL
   int vert_index = 0;
   if(debug) std::cout << "allocated coord arrays" << std::endl;
 
-  // Read the file again and build the entities. Each line in the file
-  // represents one entity.
-  file = fopen( filename, "r" );
-  FileTokenizer tokens( file, readMeshIface );
-  while( !tokens.eof() ) {
-    // these have been enumerated to match MBEntityTypes
-    int data = tokens.match_token( data_type_names ) -1;
-    MBEntityType datatype = (MBEntityType)data;
-    if(debug) {
-      std::cout << "MBVERTEX=" << MBVERTEX << " datatype=" << datatype << std::endl;
-    }
+  // Read the file again to create the entities.
+  file.clear();  // clear eof state from object
+  file.seekg(0); // rewind file
+  while (!file.eof()) {
+    getline(file,line);
 
-    // the eof was found
-    if( tokens.eof() ) {
-      break;
+    // Cut the line into fields as determined by the line format.
+    // Use a vector to allow for an unknown number of tokens (continue lines).
+    // Continue lines are not implemented.
+    std::vector<std::string> tokens;
+    tokens.reserve(10); // assume 10 fields to avoid extra vector resizing
+    result = tokenize_line( line, format, tokens );
+    if(MB_SUCCESS != result) return result;
 
-    // no matching entity was found
-    } else if(-1 == datatype ) {
-      return MB_NOT_IMPLEMENTED;
+    // Process the tokens of the line. The first token describes the entity type.
+    MBEntityType type;
+    result = determine_entity_type( tokens.front(), type );
+    if(MB_SUCCESS != result) return result;
 
-    // a vertex line was found
-    } else if(MBVERTEX == datatype) {
+    // Create the entity.
+    if(MBVERTEX == type) {
       result = read_node(tokens, id_tag, file_set, debug, coord_arrays, 
-                         vert_index, start_vert, node_ids_are_continuous ); 
+			 vert_index, start_vert, node_ids_are_continuous ); 
       if(MB_SUCCESS != result) return result;
-
-    // an element line was found
     } else {
-      result = read_element(tokens, id_tag, material_tag, datatype, file_set, 
-                            debug, start_vert, node_ids_are_continuous ); 
+      result = read_element(tokens, id_tag, material_tag, type, file_set, 
+			    debug, start_vert, node_ids_are_continuous ); 
       if(MB_SUCCESS != result) return result;
     }
-  } 
+  }
+  
+  file.close();
   return MB_SUCCESS;
 }
 
+  /* Determine the type of NASTRAN line: small field, large field, or free field.
+     small field: each line has 10 fields of 8 characters
+     large field: 1x8, 4x16, 1x8. Field 1 must have an asterisk following the character string
+     free field: each line entry must be separated by a comma
+     Implementation tries to avoid more searches than necessary. */
+MBErrorCode ReadNASTRAN::determine_line_format( const std::string line, 
+                                                  line_format &format ) {
+  std::string::size_type found_asterisk = line.find("*");
+  if(std::string::npos != found_asterisk) {
+      format = LARGE_FIELD;
+      return MB_SUCCESS;
+    } else {
+      std::string::size_type found_comma = line.find(",");
+      if(std::string::npos != found_comma) {
+	format = FREE_FIELD;
+	return MB_SUCCESS;
+      } else {
+	format = SMALL_FIELD;
+	return MB_SUCCESS;
+      }
+    }
+  }
+
+  /* Tokenize the line. Continue-lines have not been implemented. */
+MBErrorCode ReadNASTRAN::tokenize_line(const std::string line, const line_format format, 
+				       std::vector<std::string> &tokens ) { 
+  size_t line_size = line.size();
+  switch(format) {
+  case SMALL_FIELD: {
+    // Expect 10 fields of 8 characters.
+    // The sample file does not have all 10 fields in each line
+    const int field_length = 8;
+    unsigned int n_tokens = line_size / field_length;
+    for(unsigned int i=0; i<n_tokens; i++) {
+      tokens.push_back( line.substr(i*field_length,field_length) );
+    }
+    break; 
+  } case LARGE_FIELD:
+    return MB_NOT_IMPLEMENTED;
+    break;
+  case FREE_FIELD:
+    return MB_NOT_IMPLEMENTED;
+    break;
+  default:
+    return MB_FAILURE;
+  }
+
+  return MB_SUCCESS;
+}
+
+MBErrorCode ReadNASTRAN::determine_entity_type( const std::string first_token, 
+                                                  MBEntityType &type ) {
+  if     (0==first_token.compare("GRID    ")) type = MBVERTEX;
+  else if(0==first_token.compare("CTETRA  ")) type = MBTET;
+  else if(0==first_token.compare("CPENTA  ")) type = MBPRISM;
+  else if(0==first_token.compare("CHEXA   ")) type = MBHEX;
+  else return MB_NOT_IMPLEMENTED;
+
+  return MB_SUCCESS;
+}
+
+// Just one example of coordinates:
+    /* GRID           1       03.9804546.9052-15.6008-1    
+       has the coordinates: ( 3.980454, 6.9052e-1, 5.6008e-1 )
+       GRID      200005       04.004752-3.985-15.4955-1  
+       has the coordinates: ( 4.004752, -3.985e-1, 5.4955e-1 ) */
+MBErrorCode ReadNASTRAN::get_real( const std::string token, double &real ) {
+  std::string significand = token;
+  std::string exponent = "0";
+
+  // Cut off the first digit because a "-" could be here indicating a negative
+  // number. Instead we are looking for a negative exponent.
+  std::string back_token = token.substr(1);
+  
+  // A minus that is not the first digit is always a negative exponent
+  std::string::size_type found_minus = back_token.find("-");
+  if(std::string::npos != found_minus) {
+    // separate the significand from the exponent at the "-"
+    exponent = token.substr( found_minus+1 );
+    significand = token.substr( 0, found_minus+1 );
+
+    // if the significand has an "E", remove it
+    if(std::string::npos != significand.find("E")) 
+      // Assume the "E" is at the end of the significand.
+      significand = significand.substr( 1, significand.size()-2 );
+
+    // If a minus does not exist past the 1st digit, but an "E" or "+" does, then 
+    // it is a positive exponent. First look for an "E",
+  } else { 
+    std::string::size_type found_E = token.find("E");
+    if(std::string::npos != found_E) {
+      significand = token.substr(0, found_E-1);
+      exponent = token.substr(found_E+1);
+      // if there is a "+" on the exponent, cut it off
+      std::size_t found_plus = exponent.find("+");
+      if(std::string::npos != found_plus) {
+	exponent = exponent.substr(found_plus+1);
+      }
+    } else {
+      // if there is a "+" on the exponent, cut it off
+      std::size_t found_plus = token.find("+");
+      if(std::string::npos != found_plus) {
+	significand = token.substr(0, found_plus-1);
+	exponent = token.substr(found_plus+1);
+      }
+    }
+  }
+    
+  // now assemble the real number
+  double signi = atof(significand.c_str());
+  double expon = atof(exponent.c_str());
+
+  if(HUGE_VAL==signi || HUGE_VAL==expon) return MB_FAILURE;
+  real = signi * pow( 10, expon );
+  return MB_SUCCESS;
+}
+
 /* It has been determined that this line is a vertex. Read the rest of
    the line and create the vertex. */
-MBErrorCode ReadNASTRAN::read_node( FileTokenizer &tokens, 
-                                    MBTag id_tag,
-                                    const MBEntityHandle file_set,
-                                    const bool debug, 
-                                    std::vector<double*> coord_arrays, 
-                                    int &vert_index, 
-                                    const MBEntityHandle start_vert,
-                                    bool &node_ids_are_continuous ) {
+MBErrorCode ReadNASTRAN::read_node( const std::vector<std::string> tokens, 
+				      MBTag id_tag,
+				      const MBEntityHandle file_set,
+				      const bool debug, 
+				      std::vector<double*> coord_arrays, 
+				      int &vert_index, 
+				      const MBEntityHandle start_vert,
+				      bool &node_ids_are_continuous ) {
   // read the node's id (unique)
   MBErrorCode result;
-  int id;
-  if( !tokens.get_integers(1, &id) ) return MB_FAILURE;;
+  int id = atoi(tokens[1].c_str());
 
+  // read the node's coordinate system number
+  // "0" or blank refers to the basic coordinate system.
+  int coord_system = atoi(tokens[2].c_str());
+  if(0 != coord_system) {
+    std::cerr << "ReadNASTRAN: alternative coordinate systems not implemented" 
+              << std::endl;
+    return MB_NOT_IMPLEMENTED;    
+  }
+
   // read the coordinates
-  const char* coords_string = tokens.get_string();
-  if (!coords_string) return MB_FAILURE;
-  if(debug) std::cout << "coords_string=" << coords_string << std::endl; 
   double coords[3];
-  result = parse_coords( coords_string, coords, debug );
-  if(MB_SUCCESS != result) return result;
+  for(unsigned int i=0; i<3; i++) {
+    result = get_real( tokens[i+3], coords[i] );
+    if(MB_SUCCESS != result) return result;
+    if(debug) std::cout << "read_node: coords[" << i << "]=" << coords[i] << std::endl;
+  }
 
   // create the node
   MBEntityHandle vert = start_vert+vert_index;
@@ -231,83 +356,31 @@
   return MB_SUCCESS;
 }
 
-/* The coordinates are difficult to parse. Below are some samples. */
-MBErrorCode ReadNASTRAN::parse_coords( const char *coords_string, 
-                                       double     coords[],
-                                       const bool debug ) {
-  /* GRID           1       03.9804546.9052-15.6008-1    
-     has the coordinates: ( 3.980454, 6.9052e-1, 5.6008e-1 )
-     GRID      200005       04.004752-3.985-15.4955-1  
-     has the coordinates: ( 4.004752, -3.985e-1, 5.4955e-1 ) */
-  char x[9], y[8], z[8];
-  strncpy(x, coords_string,                     9); //will copy first 4 characters
-  strncpy(y, coords_string+sizeof(x),           8);
-  strncpy(z, coords_string+sizeof(x)+sizeof(y), 8);
-  if(debug) std::cout << "x=" << x << " y=" << y << " z=" << z << std::endl;
-
-  // returns memory location of last match if found. returns null if not found.
-  char *x_loc, *y_loc, *z_loc;
-  x_loc = strrchr(x,'-'); // - x + 1;
-  y_loc = strrchr(y,'-'); // - y + 1;
-  z_loc = strrchr(z,'-'); // - z + 1;
-  if(debug) std::cout << "loc=" << x_loc << " " << y_loc << " " << z_loc << std::endl;
-
-  // copies( destination memory address, source memory address, size to copy)
-  // copy only the exponent, if it exists.
-  char exp_x[9], exp_y[8], exp_z[8];
-  if(0 != x_loc) {
-    memcpy(exp_x, x_loc, 9);
-    coords[0] = atof(x) * pow(10, atof(exp_x));
-  } else {
-    coords[0] = atof(x);
-  }
-  if(0 != y_loc) {
-    memcpy(exp_y, y_loc, 8 );
-    coords[1] = atof(y) * pow(10, atof(exp_y));
-  } else {
-    coords[1] = atof(y);
-  }
-  if(0 != z_loc) {
-    memcpy(exp_z, z_loc, 8-(int)(z_loc-z) );
-    coords[2] = atof(z)*pow(10, atof(exp_z));;
-  } else {
-    coords[2] = atof(z);
-  }
-  //std::cout << "exp=" << exp_x << " " << exp_y << " " << exp_z << std::endl;
-  if(debug) std::cout << "coords[]=" << coords[0] << " " << coords[1] 
-                      << " " << coords[2] << std::endl;
-
-  return MB_SUCCESS;
-}
-
 /* The type of element has already been identified. Read the rest of the
    line and create the element. Assume that all of the nodes have already
    been created. */
-MBErrorCode ReadNASTRAN::read_element( FileTokenizer &tokens, 
-                                       MBTag id_tag, 
-                                       MBTag material_tag, 
-                                       const MBEntityType element_type,
-                                       const MBEntityHandle file_set, 
-                                       const bool debug, 
-                                       const MBEntityHandle start_vert,
-                                       const bool node_ids_are_continuous ) {
+MBErrorCode ReadNASTRAN::read_element( const std::vector<std::string> tokens, 
+				       MBTag id_tag, 
+				       MBTag material_tag, 
+				       const MBEntityType element_type,
+				       const MBEntityHandle file_set, 
+				       const bool debug, 
+				       const MBEntityHandle start_vert,
+				       const bool node_ids_are_continuous ) {
 
   // read the element's id (unique) and material set
   MBErrorCode result;
-  int id;
-  bool res = tokens.get_integers(1, &id);
-  if(false == res) return MB_FAILURE;
-  int material;
-  res = tokens.get_integers(1, &material);
-  if(false == res) return MB_FAILURE;
+  int id = atoi(tokens[1].c_str());    
+  int material = atoi(tokens[2].c_str());
 
   // the size of the connectivity array depends on the element type
   int n_conn = MBCN::VerticesPerEntity(element_type);
   
   // read the connected node ids from the file
   int conn[n_conn];
-  res = tokens.get_integers(n_conn, conn);
-  if(false == res) return MB_FAILURE;
+  for(int i=0; i<n_conn; i++) {
+    conn[i] = atoi(tokens[3+i].c_str());
+  }
 
   /* Get the vertex handles with those node ids. If the nodes do not have
      continuous ids we need to do a very slow tag search for global ids.
@@ -321,7 +394,7 @@
       void *vert_id_val[] = {&conn[i]};
       MBRange vert;
       result = MBI->get_entities_by_type_and_tag( file_set, MBVERTEX, &id_tag, 
-                                                  vert_id_val, 1, vert );
+						  vert_id_val, 1, vert );
       if(MB_SUCCESS != result) return result;
       if(1 != vert.size()) return MB_FAILURE; // only one vertex should have this global id 
       conn_verts[i] = vert.front();
@@ -340,7 +413,7 @@
   void *mat_val[] = {&material};
   MBRange material_set;
   result = MBI->get_entities_by_type_and_tag( file_set, MBENTITYSET, &material_tag, 
-                                                mat_val, 1, material_set );
+					      mat_val, 1, material_set );
   if(MB_SUCCESS != result) return result;   
   if(0 == material_set.size()) {
     MBEntityHandle new_material_set;

Modified: MOAB/trunk/ReadNASTRAN.hpp
===================================================================
--- MOAB/trunk/ReadNASTRAN.hpp	2009-09-27 15:19:59 UTC (rev 3170)
+++ MOAB/trunk/ReadNASTRAN.hpp	2009-09-29 15:22:50 UTC (rev 3171)
@@ -79,8 +79,23 @@
 
   const MBTag* fileIDTag;                                      
   int nodeId, elemId;
+
+  enum line_format { SMALL_FIELD,                     
+                     LARGE_FIELD,                 
+                     FREE_FIELD }; 
+
+  MBErrorCode determine_line_format( const std::string line, 
+                                     line_format &format );
   
-  MBErrorCode read_node(FileTokenizer        &tokens, 
+  MBErrorCode tokenize_line( const std::string line, 
+                             const line_format format,
+                             std::vector<std::string> &tokens );  
+
+  MBErrorCode determine_entity_type( const std::string token, MBEntityType &type); 
+
+  MBErrorCode get_real( const std::string, double &real );
+
+  MBErrorCode read_node(const std::vector<std::string> tokens, 
                         MBTag                id_tag, 
                         const MBEntityHandle file_set, 
                         const bool           debug, 
@@ -89,11 +104,7 @@
                         const MBEntityHandle start_vert,
                         bool                 &node_ids_are_continuous );
 
-  MBErrorCode parse_coords( const char *coords_string, 
-                            double     coords[], 
-                            const bool debug ); 
-
-  MBErrorCode read_element(FileTokenizer        &tokens, 
+  MBErrorCode read_element(const std::vector<std::string> tokens, 
                            MBTag                id_tag, 
                            MBTag                material_tag,
                            const MBEntityType   element_type,



More information about the moab-dev mailing list