a C++ Parser for NASTRAN card

A

arnuld

on Jul 16th, 2007, Erik Wikström gave me this exercise for starting
with real-life C++ code:


-------------------------------------------
So you basically want a proposal for a project which does not require
the usage of third party libraries and which is not to difficult.

I've got one for you, build a parser for a subset of the NASTRAN card
format, the format is as follows, each line is divided into columns of
8 character each and there are 6 columns per row (totalling 48 chars/row).

There are two kinds of records of interest for you, the first type
represents a point in space and has the word "GRID" written in the first
column, the second column is the ID of the point, the third column is
empty while the fourth, fifth, and sixth is the X, Y, and Z coordinates,
respectively, of the point. An example row:

GRID 1209 0000.0000008.0000010.000

This represents the point (0,9,10) in 3D space.

A note on exponents: When writing numbers as exponents we usually write
1.23e4 or 9.87e-6, in the files they skip the 'e' so those two numbers
would be 1.23+4 and 9.87-6 respectively.


The second type of record of interest represents a triangle and contains
information about which points are the corners of the triangle and which
object it belongs to. The format is as follows: First column contains
the word "CTRIA3", second column is the ID of the triangle, third the ID
of the object the triangle belongs to and the fourth to sixth columns
contains an ID of a point which makes out the corners of the triangle.

CTRIA3 0117 11 1198 1209 1210

This is triangle nr 117, belonging to object 11, its corners are located
at the points 1198, 1209, and 1210.

Construct a program which reads such a file and constructs a data-
structure containing information about what objects are in the model,
and for each objects have a list of all the triangles that makes up the
object. For each triangle store information about its corners, its
area, its centre (mass centre will do), and surface normal (assume
clockwise ordering of the corners). If you want an extra challenge also
make a list of all neighbours of the triangles, that is other triangles
that share shares an edge with it (remember that it does not have to be 3,
it can be less).

Some of the data will require some linear algebra to get, I hope you've
had a course on the subject, if not you might want to skip some of it.
Also comp.graphics.algorithms, alt.math, and sci.math might be helpful.


OK, so what is all this you might ask, and why should you do it? While
it's might not the most exiting assignment in the world (and will be
totally useless to you) it is a "real" project. What I described above
specifies the parser used by a program I've written that performs
simulations of heat transfer used by the automotive industry.

It really is not a very complicated task, there are two important
pieces, the first is to correctly read the data from the file which
will require some fiddling with IO-streams but you should be familiar with
the basics by now. The other part is to organise the data you read in,
start by designing classes representing the "things" in the program, such
as objects as such.
--------------------------------

here is the full list of input: http://dpaste.com/hold/37024/


Erik said i could write this program usign Classes. I have only one
idea about this program: I need to put that input into a simple text file
but then how to read all those things fromthere into different veriables ?
and from where to start ? and how does

GRID 1209 0000.0000008.0000010.000

This represents the point (0,9,10) in 3D space ?

how he calculated the 3 co-ordinates. I only see 1 co-ordinate and that
is: 0000.0000008.0000010.000
 
J

James Kanze

on Jul 16th, 2007, Erik Wikström gave me this exercise for
starting with real-life C++ code:
I've got one for you, build a parser for a subset of the
NASTRAN card format, the format is as follows, each line is
divided into columns of 8 character each and there are 6
columns per row (totalling 48 chars/row).
There are two kinds of records of interest for you, the first
type represents a point in space and has the word "GRID"
written in the first column, the second column is the ID of
the point, the third column is empty while the fourth, fifth,
and sixth is the X, Y, and Z coordinates, respectively, of the
point. An example row:
GRID 1209 0000.0000008.0000010.000
This represents the point (0,9,10) in 3D space.

That should be (0,8.10), of course. And shades of Fortran,
there's a subtle tricky bit in there for a beginner: the numeric
values aren't separated.
A note on exponents: When writing numbers as exponents we
usually write 1.23e4 or 9.87e-6, in the files they skip the
'e' so those two numbers would be 1.23+4 and 9.87-6
respectively.

Another input conversion problem. (Again, IMHO, not for
beginners.)
The second type of record of interest represents a triangle
and contains information about which points are the corners of
the triangle and which object it belongs to. The format is as
follows: First column contains the word "CTRIA3", second
column is the ID of the triangle, third the ID of the object
the triangle belongs to and the fourth to sixth columns
contains an ID of a point which makes out the corners of the
triangle.
CTRIA3 0117 11 1198 1209 1210
This is triangle nr 117, belonging to object 11, its corners
are located at the points 1198, 1209, and 1210.

And if I understand the specification above, this could also
appear as:
CTRIA3 0117 11000011980000120900001210

[...]
--------------------------------
here is the full list of input: http://dpaste.com/hold/37024/
Erik said i could write this program usign Classes. I have
only one idea about this program: I need to put that input
into a simple text file but then how to read all those things
fromthere into different veriables ? and from where to start?
and how does
GRID 1209 0000.0000008.0000010.000
This represents the point (0,9,10) in 3D space ?

Read the specification of the file. Each line is a sequence of
8 byte fields. If I insert a | between each field, I get:
GRID | 1209| |0000.000|0008.000|0010.000
CTRIA3 | 0117| 11| 1198| 1209| 1210

In other words, the last three fields are "0000.000", "0008.000"
and "0010.000". In other words, the point (0,8,10). (The 9 is
probably just a typo.)
how he calculated the 3 co-ordinates. I only see 1 co-ordinate
and that is: 0000.0000008.0000010.000

And what kind of value has three decimal points in it?

The simplest way to handle this sort of input is to read the
file line by line, chop it up into fields, and then parse each
field:

std::string line ;
std::getline( source, line ) ;
if ( line.size() !- 64 ) {
// I think we've got a problem...
} else {
std::vector fields ;
for ( int i = 0 ; i < 6 ; ++ i ) {
fields.push_back( line.substr( 8 * i, 8 ) ) ;
}
}

(I'd probably actually do this a bit more generically, reading
the field positions from an array. The principle is the same,
but the generic solution isn't more difficult, and would allow
fields of varying length.)

When you need a numeric value from a field, you use the string
value to initialize an istringstream, and read from it.

For the rest---in fact, probably long before you start worrying
about how to read the file, you should try to define the types
you'll need to deal with the problem. Two candidates,
obviously, are Grid and Triangle, but you'll probably find
others.
 
L

LR

arnuld said:
on Jul 16th, 2007, Erik Wikström gave me this exercise for starting
with real-life C++ code:

This looks like a really great project!


CTRIA3 0117 11 1198 1209 1210

This is triangle nr 117, belonging to object 11, its corners are located
at the points 1198, 1209, and 1210.


Doesn't 11 denote the real constant set for element 117? Does Nastran
call this an object?



Construct a program which reads such a file and constructs a data-
structure containing information about what objects are in the model,
and for each objects have a list of all the triangles that makes up the
object. For each triangle store information about its corners,

Angle? Or the point itself? Or the number of the GRID point.
its
area, its centre (mass centre will do), and surface normal (assume
clockwise ordering of the corners).

The lengths of each side can be useful. It's always nice if these are
all the close to the same length. There can be problems when one side is
much smaller than the another.

I'm not sure that you want to store these things unless you use them
alot. Having methods that return the information might, might, be
better. Or not.


If you want an extra challenge also
make a list of all neighbours of the triangles, that is other triangles
that share shares an edge with it (remember that it does not have to be 3,
it can be less).

And it can be more too, right?


Wouldn't it be useful to provide the real constants, at least thickness
for the CTRIA3 and density, so we could calculate the volume and mass of
the model?

Some of the data will require some linear algebra to get, I hope you've
had a course on the subject, if not you might want to skip some of it.
Also comp.graphics.algorithms, alt.math, and sci.math might be helpful.

You might also want to check out some of the engineering ngs.

OK, so what is all this you might ask, and why should you do it? While
it's might not the most exiting assignment in the world (and will be
totally useless to you) it is a "real" project. What I described above
specifies the parser used by a program I've written that performs
simulations of heat transfer used by the automotive industry.


It really is not a very complicated task, there are two important
pieces, the first is to correctly read the data from the file which
will require some fiddling with IO-streams but you should be familiar with
the basics by now. The other part is to organise the data you read in,
start by designing classes representing the "things" in the program, such
as objects as such.

You'll probably find std::map to be extremely useful for this project.


I have a few comments.

You may want to start with something smaller. Make a file with just a
few CTRIA3 cards. To begin with make at least one of the dimensions on
the GRID cards, maybe Z, all zero. This might be easier to debug at first.

AFAIK, the cards don't have to be in ascending order, and the numbers of
the grid or elements don't have to be sequential. It might be possible
for GRID 985 to be followed by 992 for example.

Remember, the people (your users) who create these files aren't always
as careful as we have to be. So after you get the basics down you'll
want to check that the triangles have three unique points.

$ a comment card. Useful, no?
$ this is an error!
CTRIA3 1999 13 1408 1419 1408


You might also want to check for things like this:

$
$ this might be an error. It probably is.
CTRIA3 1412 13 1408 1419 1407
CTRIA3 1415 13 1419 1407 1408


BTW, when you get around to it, and you start to think about how to
check for these kinds of things, you might want to think about how you'd
handle other elements, for example, CHEXA which is an eight point solid.


arnuld, this really does look like a great project. Please let us know
how it goes.

LR
 
E

Erik Wikström

arnuld wrote:


Doesn't 11 denote the real constant set for element 117? Does Nastran
call this an object?

You might be right, all I know is that (in the models I saw) the number
indicates a set of triangles that make up one object. I never used
Nastran itself, the format was used because other applications could all
understand it.
Angle? Or the point itself? Or the number of the GRID point.


The lengths of each side can be useful. It's always nice if these are
all the close to the same length. There can be problems when one side is
much smaller than the another.

I'm not sure that you want to store these things unless you use them
alot. Having methods that return the information might, might, be
better. Or not.

Depends of course on what you want to do with the information, I choose
those more or less at random since it adds some to the project. If you
can come up with an idea of what to do with the data from the file that
would of course make things even better.
And it can be more too, right?

Only with weird geometries.
Wouldn't it be useful to provide the real constants, at least thickness
for the CTRIA3 and density, so we could calculate the volume and mass of
the model?

I never had this data available, but I suppose it is just a matter of
creating a new file that maps from what I called object number to some
extra data.
 
L

LR

Depends of course on what you want to do with the information, I choose
those more or less at random since it adds some to the project. If you
can come up with an idea of what to do with the data from the file that
would of course make things even better.

Hmmm... how about constructing a stiffness matrix and... ;)

Well, maybe these:

Find the center of mass for the entire model, not just the individual
elements.

Find out if any of the elements are unconnected from the rest of the model.

Find out if any of the GRID points are unused.

See if there are any gaps between elements. For example, given
line AXB
Triangle A B C
Triangle A D X
Triangle X D B

Look for GRID points that are so close together they should be
eliminated, and write a new valid file.

Check to see if the sides of the elements are all oriented in the same
way relative to their connectivity. That is, suppose you have a
geometry that looks like a V in cross section, then you'd want all the
normals to be "outside" the V or "inside" the V, but probably not both.

Allow the user to pick a group of elements and break each triangle into
two or three more triangles, generating a new valid file. Extra credit
for placing any new GRID points created on smoothed curves.

Write code that allows you to add two model files together.

Some of the above implies some interesting uses of std::set, some of it
implies some challenges with floating point math.

Only with weird geometries.

I don't see what would be weird about that. Plenty of things might have
geometries that look like or could map to a T or X cross sections.


LR
 
J

James Kanze

In message
[...]
how he calculated the 3 co-ordinates. I only see 1 co-ordinate
and that is: 0000.0000008.0000010.000
And what kind of value has three decimal points in it?
An IP address? Every structure needs connectivity ;-)

:). Yes. (Although technically, in an IP address, I don't
think that one can call them *decimal* points.) Although I've
never seen an IP address in quite that format (but the number of
dots is correct!).

More generally, yes. Given the precedence of domain names, I
tend to use dot's to separate levels in any hierarchy. It's as
good a convention as anything else.
 
J

James Kanze

Hmmm... how about constructing a stiffness matrix and... ;)
Well, maybe these:
Find the center of mass for the entire model, not just the
individual elements.
Find out if any of the elements are unconnected from the rest
of the model.
Find out if any of the GRID points are unused.
See if there are any gaps between elements. For example, given
line AXB
Triangle A B C
Triangle A D X
Triangle X D B
Look for GRID points that are so close together they should be
eliminated, and write a new valid file.
Check to see if the sides of the elements are all oriented in
the same way relative to their connectivity. That is, suppose
you have a geometry that looks like a V in cross section, then
you'd want all the normals to be "outside" the V or "inside"
the V, but probably not both.
Allow the user to pick a group of elements and break each
triangle into two or three more triangles, generating a new
valid file. Extra credit for placing any new GRID points
created on smoothed curves.
Write code that allows you to add two model files together.
Some of the above implies some interesting uses of std::set,
some of it implies some challenges with floating point math.

Most of them imply some very great challenges with floating
point math. Just off hand, the only one I'd be capable of doing
is finding whether any of the GRID points are unused. And I
don't consider myself a beginner, nor particularly incompetent.
Just not a specialist in numeric processing. (I know enough
about it to know that I don't know enough about it, but that's
about it.)

There are probably problems which could be posed which don't
require much numeric processing, but I'm sceptical. The input
is in floating point, to begin with, even something as simple as
trying to determine whether the file describes a single closed
solid or not will involve significant analysis of the actual
floating point arithmetic involved.
 
E

Erik Wikström

I don't see what would be weird about that. Plenty of things might have
geometries that look like or could map to a T or X cross sections.

Mmm, yes. I only saw the data used to describe surfaces, they never had
any depth. But if we assume that they do then it would make sense.
 
L

LR

James said:
Most of them imply some very great challenges with floating
point math.

Yes, you're right, I was indulging my, ahem, talent for understatement.

Just off hand, the only one I'd be capable of doing
is finding whether any of the GRID points are unused.

I think there are a few of the others that you could do as well.

What I failed to make clear, is that at least two of the problems are
very difficult, maybe impossible, to solve in the general case.

So some of the problems should be restated to be a small subset of what
I said.

For example, writing code that allows two models to be added together,
perhaps only provide solutions for cases where we will attach the models
together at GRID points that are less than a fixed distance, provided by
the user, from each other.

I think that makes the problem a little more tractable.

I was perhaps a little too optimistic in stating these in such an open
ended way.

In any case, these are problems that shouldn't be tackled until the more
basic work suggested by Eric Wikstrom is completed. And please allow me
to repeat that I think it's a great project.


And I
don't consider myself a beginner, nor particularly incompetent.
Just not a specialist in numeric processing. (I know enough
about it to know that I don't know enough about it, but that's
about it.)

I tend to think of myself as a beginner. And I'm certainly not a
specialist in numeric processing either. At least a few of the problems
above have more to do with manipulating sets than with numeric
processing. Something else I'm not a specialist in.


There are probably problems which could be posed which don't
require much numeric processing, but I'm sceptical.

I think there are three problems in the group above which require no
numeric processing, because the connections we are concerned with are
logical rather than numeric. IE the possibility of two triangles
'wrongly' intersecting numerically does not concern an FEA solver, even
though we might like to know about it, since it's probably 'wrong'.

The three problems are:
1) Unconnected element. Could be two unconnected groups.
2) Unused GRID point.
3) Gap between triangles.

Three is a little tricky, because there will be some geometries where
this is the right thing to do.

The input
is in floating point, to begin with, even something as simple as
trying to determine whether the file describes a single closed
solid or not will involve significant analysis of the actual
floating point arithmetic involved.


A single closed solid? I'm not sure I follow that. But given the nature
of the input, and if I understand what you mean, I think this question,
while somewhat open ended, might boil down to: Do any two triangles
intersect other than sharing one line in common. I don't think this is
insurmountable in a practical sense. But certainly not simple.


LR
 
C

Craig Scott

Most of them imply some very great challenges with floating
point math. Just off hand, the only one I'd be capable of doing
is finding whether any of the GRID points are unused. And I
don't consider myself a beginner, nor particularly incompetent.
Just not a specialist in numeric processing. (I know enough
about it to know that I don't know enough about it, but that's
about it.)

There are probably problems which could be posed which don't
require much numeric processing, but I'm sceptical. The input
is in floating point, to begin with, even something as simple as
trying to determine whether the file describes a single closed
solid or not will involve significant analysis of the actual
floating point arithmetic involved.

Hard to pick which post to reply to, so don't take it personally James
that I picked yours. ;)

Having done this and similar things in my current job, I would suggest
that a good thing to consider, even for a beginner, is what effect
will it have on your design if someone later wants to support
different element types other than just CTRIA3? This is a design
question and not something numerically hard, and it gets the person
thinking about how flexible their design is rather than how to solve a
particular one-off problem.

Another useful question to ask is can you find a formal document which
defines the file format? There are lots of different 3D mesh file
formats and plenty of software tries to/must be able to read and write
them. That means ensuring that your own software implements the
standard for the file format properly. For a beginner project such as
the one discussed in this thread, I think it would be sufficient just
to have the person go through the task of finding the document and
confirming some statement or answering some question about it that is
relevant to the task (eg is it possible/allowable to include some kind
of text tag on a GRID statement?). The reason I suggest this task is
that in practice, this is what you have to do to write good quality 3D
mesh readers and writers. It isn't C++, more part of good software
engineering practice.

If you want to get a little more interesting, get your hands on a
really big input file. This will test how well your reader code
scales. Since the CTRIA3 elements refer to GRID entries by ID numbers
that are not necessarily sequential, you've got a number lookup to
perform. How you do that can be really important for performance if
the file is very large.

Other miscellaneous thoughts in no particular order:

What if a GRID is repeated with the same ID? Is that an error?

If I've just concatenated two NASTRAN files and they share common
nodes that should be merged (we did this frequently at one company I
worked for), should I check that nodes with the same ID have the same
data for the rest of the line too?

What if I wanted to assign data to each of the GRID nodes once I'd
read them in? How would I store that in my data structures? Start with
something simple, like storing just one floating point number per
node.

Do I need the normal vector of the CTRIA3 elements? This is easy to
calculate, except that the triangular elements can degenerate into
splinters and have a zero normal vector. This is numerical and might
be outside the areas you want the person to deal with though.

If I wanted to know all the GRID nodes that were inside a given axis-
aligned cube, how could I do that efficiently? Classic computer
science problem, but not necessarily easy. There's a whole class of
problems here....

Nothing beats pictures! Can you find an open source 3D mesh viewer and
re-export your NASTRAN file out into a format that the 3D viewer
supports? A Vtk file format may be worth looking at, and it would
provide an interesting way of using the data read in because its file
format is structured differently to NASTRAN. A useful thing about this
step is that it can be a great way to quickly and easily check if your
reader is reading in the data correctly, since anything you read
incorrectly will frequently show up as a very obvious misplaced node
or element in the 3D scene when you look at it in the viewer.

HTH
 
C

Craig Scott

If I wanted to know all the GRID nodes that were inside a given axis-
aligned cube, how could I do that efficiently? Classic computer
science problem, but not necessarily easy. There's a whole class of
problems here....

Argh! The question I *meant* to pose was, what if I wanted to know all
the GRID nodes within some distance of a point. Was already thinking
about implementation when I wrote the first post. ;)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top