Welcome to pyNastran’s documentation for v0.7!¶
The pyNastran software interfaces to Nastran’s complicated input and output files and provides a simplified interface to read/edit/write the various files. The software is compatible currently being used on Windows, Linux, and Mac.
The BDF reader/editor/writer supports about 230 cards including coordinate systems. Card objects have methods to access data such as Mass, Area, etc. The BDF writer writes a small field formatted file, but makes full use of the 8-character Nastran field. The OpenMDAO BDF parametrization syntax is also supported.
The OP2 reader supports static/transient results, which unless you analyzing frequency response data should be good enough. It also supports F06 Writing for most of the objects. Results include: displacement, velocity, acceleration, temperature, eigenvectors, eigenvalues, SPC forces, MPC forces, grid point forces, load vectors, applied loads, strain energy, as well as stress and strain.
The F06 reader/writer works for simple problems, but it’s still preliminary. At this point, you should just use the OP2 reader. It’s faster, more robust, and supports more results. The F06 reader is more used as a verification tool for the OP2 reader.
The Python OP4 reader/writer supports reading ASCII/binary sparse and dense matrices, and writing ASCII matrices..
A simple GUI has been developed that can view BDF models and display static/dynamic stress/strain/displacement/eignevectors (they must be real!) results from the OP2. Additionally, Cart3d, Usm3d, Tetgen, STL, and Panair are somewhat supported and included for use.
pyNastran Manual¶
Brief Project Overview¶
Since the 1960’s NASTRAN (NASA Structural ANalysis) has been used to solve structural/thermal/aerodynamic/dynamics/etc. problems. The file formats were originally developed by MSC for a product now called MSC Nastran. There have been many spinoff version of NASTRAN that have been created based on the 2001 source code release of MSC Nastran in 2002 after settlement with the FTC (Federal Trade Commisson). There is now NX Nastran and NEi Nastran, which are developed independently.
pyNastran is at it’s core an API (Application Programming Interface) to the legacy formats used by Nastran. These files include the BDF, F06, OP2, OP4, and PCH files. Other code has been added to pyNastran in order to drive development of the software in order to be able to solve other engineering problems. For example, Code_Aster, an open-source finite element code developed by the EDF (Electricity of France), has a Nastran to Code_Aster converter that is in development. The development has helped to define the API for the loads in order to be able to extract them in a way that makes sense. However, this is not the focus of the software.
Target Audience¶
pyNastran target audience are users of Nastran and therefore are expected to be familiar with the software. This has greatly reduced the necessity of documenting every variable exhaustively as users can easily reference existing Nastran documentation. The BDF file has roughly 700 cards availble to a user with 238 being currently supported by pyNastran. The majority of the cards, defined as separate Python classes, are not documented. However, the Quick Reference Guide (QRG) defines each input to the card. A user with the QRG should have little effort in understanding what the various objects do. However, for convenience, it’s still good to document variables.
pyNastran target audience largely uses MATLAB, a matrix based programming language, and typically has little experience with general programming. There are also users that know Python, but have never used a class or a dictionary, which makes an API seems complicated.
bdf¶
Introduction¶
This is meant as a tutorial on how to use the pyNastran pyNastran.bdf.bdf.BDF class
The head/tail/file_slice methods can be found at:
These examples can be found at:
Example 1: Read/Write¶
this example will demonstate:
- reading the BDF
- getting some basic information
- writing the BDF
our model
>>> import pyNastran
>>> pkg_path = pyNastran.__path__[0]
>>> test_path = os.path.join(pkg_path, '..', 'models', 'solid_bending')
>>> bdf_filename = os.path.join(test_path, 'solid_bending.bdf')
instantiate the model
>>> from pyNastran.bdf.bdf import BDF
>>> model = BDF()
>>> model.read_bdf(bdf_filename)
print information about the model
>>> print(model.get_bdf_stats())
---BDF Statistics---
SOL 101
bdf.loads[1]
FORCE: 23
bdf.loads[2]
LOAD: 1
bdf.params
PARAM : 2
bdf.nodes
GRID : 72
bdf.elements
CTETRA : 186
bdf.properties
PSOLID : 1
bdf.materials
MAT1 : 1
bdf.coords
CORD2R : ???
write the file
>>> bdf_filename_out = os.path.join(test_path, 'solid_bending_out.bdf')
>>> model.write_bdf(bdf_filename_out)
looking at the output
>>> print(file_slice(bdf_filename_out, 94, 100))
GRID 71 .500008 1.61116 3.
GRID 72 .500015 1.00001 3.
$ELEMENTS_WITH_PROPERTIES
PSOLID 1 1
CTETRA 1 1 8 13 67 33
CTETRA 2 1 8 7 62 59
write the file with large field format; double precision
>>> bdf_filename_out2 = os.path.join(test_path, 'solid_bending_out2.bdf')
>>> model.write_bdf(bdf_filename_out2, size=16, is_double=False)
>>> print(file_slice(bdf_filename_out2, 166, 175))
GRID* 71 .500008 1.61116
* 3.
GRID* 72 .500015 1.00001
* 3.
$ELEMENTS_WITH_PROPERTIES
PSOLID 1 1
CTETRA 1 1 8 13 67 33
CTETRA 2 1 8 7 62 59
CTETRA 3 1 8 45 58 66
write the file with large field format; double precision
>>> bdf_filename_out3 = os.path.join(test_path, 'solid_bending_out3.bdf')
>>> model.write_bdf(bdf_filename_out3, size=16, is_double=True)
>>> print(file_slice(bdf_filename_out3, 166, 175))
GRID* 71 5.0000800000D-011.6111600000D+00
* 3.0000000000D+00
GRID* 72 5.0001500000D-011.0000100000D+00
* 3.0000000000D+00
$ELEMENTS_WITH_PROPERTIES
PSOLID 1 1
CTETRA 1 1 8 13 67 33
CTETRA 2 1 8 7 62 59
CTETRA 3 1 8 45 58 66
Example 2: Printing Nodes¶
this example will demonstate:
- writing cards
our model
>>> import pyNastran
>>> pkg_path = pyNastran.__path__[0]
>>> test_path = os.path.join(pkg_path, '..', 'models', 'solid_bending')
>>> bdf_filename = os.path.join(test_path, 'solid_bending.bdf')
instantiate the model
>>> from pyNastran.bdf.bdf import BDF
>>> model = BDF()
>>> model.read_bdf(bdf_filename, xref=True)
>>> f = open('junk.out', 'w')
Method 1 - using objects¶
GRIDs
>>> for nid,node in sorted(model.nodes.items()):
>>> f.write(node.write_card(size=8, is_double=False))
GRIDSET
>>> if model.gridSet:
>>> f.write(model.gridSet.write_card(size=8, is_double=False))
SPOINTs
>>> if model.spoints:
>>> f.write(model.spoints.write_card(size=8, is_double=False))
CORDx
>>> for cid,coord in sorted(model.coords.items()):
>>> if cid != 0: # if CID=0 is the global frame, skip it
>>> f.write(coord)
Method 2 - using built-in methods¶
>>> model._write_nodes(f)
>>> model._write_coords(f)
Example 3: Printing Elements/Properties¶
Print the Element ID and associated Node and Property to an Output File
note this skips rigidElements
this example will demonstate:
- using the BDF class to write cards/properties
our model
>>> import pyNastran
>>> pkg_path = pyNastran.__path__[0]
>>> test_path = os.path.join(pkg_path, '..', 'models', 'solid_bending')
>>> bdf_filename = os.path.join(test_path, 'solid_bending.bdf')
instantiate the model
>>> from pyNastran.bdf.bdf import BDF
>>> model = BDF()
>>> model.read_bdf(bdf_filename, xref=True)
>>> f = open('junk.out', 'w')
Method 1 - using objects¶
>>> for eid, element in sorted(model.elements.items()):
>>> f.write(element.write_card(size=8, is_double=False))
>>> for pid, prop in sorted(model.properties.items()):
>>> f.write(prop.write_card(size=8, is_double=False))
Method 2 - using built-in method¶
>>> model._write_elements_properties(f)
Method 3 - using built-in methods¶
>>> model._write_elements(f)
>>> model._write_properties(f)
Example 4: Get Element ID & Type¶
Print the Element ID and its type(e.g. CQUAD4, CTRIA3, etc.) to a file
note this skips rigidElements
this example will demonstate:
- accessing element type information
our model
>>> import pyNastran
>>> pkg_path = pyNastran.__path__[0]
>>> test_path = os.path.join(pkg_path, '..', 'models', 'solid_bending')
>>> bdf_filename = os.path.join(test_path, 'solid_bending.bdf')
instantiate the model
>>> from pyNastran.bdf.bdf import BDF
>>> model = BDF()
>>> model.read_bdf(bdf_filename, xref=True)
>>> f = open('junk.out', 'w')
Method 1 - using objects¶
>>> for eid,element in sorted(model.elements.items()):
>>> msg = 'eid=%s type=%s\n' %(eid, element.type)
>>> f.write(msg)
Example 5: Get Elements by Node ID¶
this example will demonstate:
- getting the list of elements that share a certain node
our model
>>> import pyNastran
>>> pkg_path = pyNastran.__path__[0]
>>> test_path = os.path.join(pkg_path, '..', 'models', 'solid_bending')
>>> bdf_filename = os.path.join(test_path, 'solid_bending.bdf')
instantiate the model
>>> from pyNastran.bdf.bdf import BDF
>>> model = BDF()
>>> model.read_bdf(bdf_filename, xref=True)
>>> f = open('junk.out', 'w')
given a Node, get the Elements Attached to that Node
assume node 55
doesnt support 0d/1d elements yet
>>> nid_to_eids_map = model.get_node_id_to_element_ids_map()
>>> eids = nid_to_eids_map[55]
convert to elements instead of element IDs
>>> elements = []
>>> for eid in eids:
>>> elements.append(model.Element(eid))
>>> print("eids = %s" % eids)
>>> print("elements =\n %s" % elements)
Example 6: Get Elements by Property ID¶
this example will demonstate:
- getting a list of elements that have a certain property
our model
>>> import pyNastran
>>> pkg_path = pyNastran.__path__[0]
>>> test_path = os.path.join(pkg_path, '..', 'models', 'sol_101_elements')
>>> bdf_filename = os.path.join(test_path, 'static_solid_shell_bar.bdf')
instantiate the model
>>> from pyNastran.bdf.bdf import BDF
>>> model = BDF()
>>> model.read_bdf(bdf_filename, xref=True)
>>> f = open('junk.out', 'w')
Creating a List of Elements based on a Property ID
assume pid=1
>>> pid_to_eids_map = model.get_property_id_to_element_ids_map()
>>> eids4 = pid_to_eids_map[4] # PSHELL
>>> print("eids4 = %s" % eids4)
eids4 = [6, 7, 8, 9, 10, 11]
convert to elements instead of element IDs
>>> elements4 = []
>>> for eid in eids4:
>>> elements4.append(model.Element(eid))
just to verify
>>> elem = model.elements[eids4[0]]
>>> print(elem.pid)
PSHELL 4 1 .25 1 1
Example 7: Get Elements by Material ID¶
this example will demonstate:
- getting a list of elements that have a certain material
our model
>>> import pyNastran
>>> pkg_path = pyNastran.__path__[0]
>>> test_path = os.path.join(pkg_path, '..', 'models', 'sol_101_elements')
>>> bdf_filename = os.path.join(test_path, 'static_solid_shell_bar.bdf')
instantiate the model
>>> from pyNastran.bdf.bdf import BDF
>>> model = BDF()
>>> model.read_bdf(bdf_filename, xref=True)
>>> f = open('junk.out', 'w')
assume you want the eids for material 10
>>> pid_to_eids_map = model.get_property_id_to_element_ids_map()
>>> mid_to_pids_map = model.get_material_id_to_property_ids_map()
>>> pids1 = mid_to_pids_map[1]
>>> print('pids1 = %s' % pids1)
pids1 = [1, 2, 3, 4, 5]
>>> eids = []
>>> for pid in pids1:
>>> eids += pid_to_eids_map[pid]
convert to elements instead of element IDs
>>> elements = []
>>> for eid in eids:
>>> element = model.Element(eid)
>>> elements.append(element)
>>> print(str(element).rstrip())
CBAR 13 1 15 19 0. 1. 0.
$ Direct Text Input for Bulk Data
$ Pset: "shell" will be imported as: "pshell.1"
CHEXA 1 2 2 3 4 1 8 5
6 7
CPENTA 2 2 6 8 5 10 11 9
CPENTA 3 2 6 7 8 10 12 11
CTETRA 4 2 10 11 9 13
CTETRA 5 2 10 12 11 13
CROD 14 3 16 20
CROD 15 3 17 21
CQUAD4 6 4 4 1 14 15
CQUAD4 7 4 3 2 17 16
CTRIA3 8 4 4 3 16
CTRIA3 9 4 16 15 4
CTRIA3 10 4 1 2 17
CTRIA3 11 4 17 14 1
$
CBEAM 12 5 14 18 0. 1. 0. GGG
op2¶
Introduction¶
This is meant as a tutorial on how to use the pyNastran pyNastran.op2.op2.OP2 class
This page runs through examples relating to the vectorized OP2. The vectorized OP2 is preferred as it uses about 20% of the memory as the non-vectorized version of the OP2. It’s slower to parse as it has to do two passes, but calculations will be much faster.
Note that a static model is a SOL 101 or SOL 144. A dynamic/”transient” solution is any transient/modal/load step/frequency based solution (e.g. 103, 109, 145).
The head/tail/file_slice methods can be found at:
These examples can be found at:
Example 1: Read Write¶
This example will demonstate:
- reading the OP2
- getting some basic information
- writing the F06
our model
>>> import pyNastran
>>> pkg_path = pyNastran.__path__[0]
>>> test_path = os.path.join(pkg_path, '..', 'models', 'solid_bending')
>>> op2_filename = os.path.join(test_path, 'solid_bending.op2')
>>> f06_filename = os.path.join(test_path, 'solid_bending_out.f06')
instantiate the model
>>> from pyNastran.op2.op2 import OP2
>>> model = OP2()
>>> model.read_op2(op2_filename, vectorized=True)
>>> print(model.get_op2_stats())
op2.displacements[1]
type=RealDisplacementArray nnodes=72
data: [t1, t2, t3, r1, r2, r3] shape=[1, 72, 6] dtype=float32
gridTypes
lsdvmns = [1]
op2.spc_forces[1]
type=RealSPCForcesArray nnodes=72
data: [t1, t2, t3, r1, r2, r3] shape=[1, 72, 6] dtype=float32
gridTypes
lsdvmns = [1]
op2.ctetra_stress[1]
type=RealSolidStressArray nelements=186 nnodes=930
nodes_per_element=5 (including centroid)
eType, cid
data: [1, nnodes, 10] where 10=[oxx, oyy, ozz, txy, tyz, txz, o1, o2, o3, von_mises]
data.shape = (1, 930, 10)
element types: CTETRA
lsdvmns = [1]
>>> model.write_f06(f06_filename)
F06:
RealDisplacementArray SUBCASE=1
RealSPCForcesArray SUBCASE=1
RealSolidStressArray SUBCASE=1 - CTETRA
>>> print(tail(f06_filename, 21))
0 186 0GRID CS 4 GP
0 CENTER X 9.658666E+02 XY -2.978357E+01 A 2.559537E+04 LX-0.02 0.20 0.98 -1.094517E+04 2.288671E+04
Y 7.329372E+03 YZ 5.895411E+02 B -7.168877E+01 LY-1.00-0.03-0.01
Z 2.454026E+04 ZX -5.050599E+03 C 7.311813E+03 LZ 0.03-0.98 0.20
0 8 X 9.658666E+02 XY -2.978357E+01 A 2.559537E+04 LX-0.02 0.20 0.98 -1.094517E+04 2.288671E+04
Y 7.329372E+03 YZ 5.895411E+02 B -7.168877E+01 LY-1.00-0.03-0.01
Z 2.454026E+04 ZX -5.050599E+03 C 7.311813E+03 LZ 0.03-0.98 0.20
0 62 X 9.658666E+02 XY -2.978357E+01 A 2.559537E+04 LX-0.02 0.20 0.98 -1.094517E+04 2.288671E+04
Y 7.329372E+03 YZ 5.895411E+02 B -7.168877E+01 LY-1.00-0.03-0.01
Z 2.454026E+04 ZX -5.050599E+03 C 7.311813E+03 LZ 0.03-0.98 0.20
0 4 X 9.658666E+02 XY -2.978357E+01 A 2.559537E+04 LX-0.02 0.20 0.98 -1.094517E+04 2.288671E+04
Y 7.329372E+03 YZ 5.895411E+02 B -7.168877E+01 LY-1.00-0.03-0.01
Z 2.454026E+04 ZX -5.050599E+03 C 7.311813E+03 LZ 0.03-0.98 0.20
0 58 X 9.658666E+02 XY -2.978357E+01 A 2.559537E+04 LX-0.02 0.20 0.98 -1.094517E+04 2.288671E+04
Y 7.329372E+03 YZ 5.895411E+02 B -7.168877E+01 LY-1.00-0.03-0.01
Z 2.454026E+04 ZX -5.050599E+03 C 7.311813E+03 LZ 0.03-0.98 0.20
1 MSC.NASTRAN JOB CREATED ON 28-JAN-12 AT 12:52:32 JANUARY 28, 2012 pyNastran v0.7.1 PAGE 3
1 * * * END OF JOB * * *
Example 2: Displacement (static)¶
This example will demonstate:
- calculating total deflection of the nodes for a static case for a vectorized OP2
- calculate von mises stress and max shear
our model
>>> import pyNastran
>>> pkg_path = pyNastran.__path__[0]
>>> test_path = os.path.join(pkg_path, '..', 'models', 'solid_bending')
>>> op2_filename = os.path.join(test_path, 'solid_bending.op2')
>>> out_filename = os.path.join(test_path, 'solid_bending.out')
instantiate the model
>>> from pyNastran.op2.op2 import OP2
>>> model = OP2()
>>> model.read_op2(op2_filename, vectorized=True)
>>> print(model.get_op2_stats())
we’re analyzing a static problem, so itime=0
we’re also assuming subcase 1
>>> itime = 0
>>> isubcase = 1
get the displacement object
>>> disp = model.displacements[isubcase]
displacement is an array
# data = [tx, ty, tz, rx, ry, rz]
# for some itime
# all the nodes -> :
# get [tx, ty, tz] -> :3
>>> txyz = disp.data[itime, :, :3]
calculate the total deflection of the vector
>>> from numpy.linalg import norm
>>> total_xyz = norm(txyz, axis=1)
since norm’s axis parameter can be tricky, we’ll double check the length
>>> nnodes = disp.data.shape[1]
>>> assert len(total_xyz) == nnodes
we could also have found nnodes by using the attribute.
It has an underscore because the object is also used for elements.
>>> nnodes2 = disp._nnodes
>>> assert nnodes == nnodes2
>>> assert nnodes == 72
additionally we know we have 72 nodes from the shape:
op2.displacements[1]
type=RealDisplacementArray nnodes=72
data: [t1, t2, t3, r1, r2, r3] shape=[1, 72, 6] dtype=float32
gridTypes
lsdvmns = [1]
now we’ll loop over the nodes and print the total deflection
>>> msg = 'nid, gridtype, tx, ty, tz, txyz'
>>> print(msg)
>>> for (nid, grid_type), txyz, total_xyzi in zip(disp.node_gridtype, txyz, total_xyz):
>>> msg = '%s, %s, %s, %s, %s, %s' % (nid, grid_type, txyz[0], txyz[1], txyz[2], total_xyzi)
>>> print(msg)
nid, gridtype, tx, ty, tz, txyz
1, 1, 0.00764469, 4.01389e-05, 0.000111137, 0.00764561
2, 1, 0.00762899, 5.29171e-05, 0.000142154, 0.0076305
3, 1, 0.00944763, 6.38675e-05, 7.66179e-05, 0.00944816
4, 1, 0.00427092, 2.62277e-05, 7.27848e-05, 0.00427162
5, 1, 0.00152884, 1.71054e-05, -3.47525e-06, 0.00152894
...
Example 3: Eigenvector (transient)¶
This example will demonstate:
- calculate von mises stress and max shear for solid elements for a static case for a vectorized OP2
our model
>>> import pyNastran
>>> pkg_path = pyNastran.__path__[0]
>>> test_path = os.path.join(pkg_path, '..', 'models', 'solid_bending')
>>> op2_filename = os.path.join(test_path, 'solid_bending.op2')
>>> out_filename = os.path.join(test_path, 'solid_bending.out')
instantiate the model
>>> from pyNastran.op2.op2 import OP2
>>> model = OP2()
>>> model.read_op2(op2_filename, vectorized=True)
>>> print(model.get_op2_stats())
op2.ctetra_stress[1]
type=RealSolidStressArray nelements=186 nnodes=930
nodes_per_element=5 (including centroid)
eType, cid
data: [1, nnodes, 10] where 10=[oxx, oyy, ozz, txy, tyz, txz, o1, o2, o3, von_mises]
data.shape = (1, 930, 10)
element types: CTETRA
lsdvmns = [1]
we’re analyzing a static problem, so itime=0
we’re also assuming subcase 1
>>> itime = 0
>>> isubcase = 1
get the stress object (there is also cpenta_stress and chexa_stress as well as ctetra_strain/cpenta_strain/chexa_strain)
>>> stress = model.ctetra_stress[isubcase]
The stress/strain data can often be von_mises/max_shear (same for fiber_distance/curvature), so check!
#data = [oxx, oyy, ozz, txy, tyz, txz, o1, o2, o3, von_mises]
>>> o1 = stress.data[itime, :, 6]
>>> o3 = stress.data[itime, :, 8]
>>> if stress.is_von_mises():
>>> max_shear = (o1 - o3) / 2.
>>> von_mises = stress.data[itime, :, 9]
>>> else:
>>> from numpy import sqrt
>>> o2 = data[itime, :, 8]
>>> von_mises = sqrt(0.5*((o1-o2)**2 + (o2-o3)**2, (o3-o1)**2))
>>> max_shear = stress.data[itime, :, 9]
>>> for (eid, node), vm, ms in zip(stress.element_node, von_mises, max_shear):
>>> print(eid, 'CEN/4' if node == 0 else node, vm, ms)
1 CEN/4 15900.2 2957.35
1 8 15900.2 2957.35
1 13 15900.2 2957.35
1 67 15900.2 2957.35
1 33 15900.2 2957.35
2 CEN/4 16272.3 6326.18
2 8 16272.3 6326.18
2 7 16272.3 6326.18
2 62 16272.3 6326.18
2 59 16272.3 6326.18
Note that because element_node is an integer array, the centroid is 0. We renamed it to CEN/4 when we wrote it
Example 4: Solid Stress (static)¶
This example will demonstate:
- calculating total deflection of the nodes for a dynamic case for a vectorized OP2
our model
>>> import pyNastran
>>> pkg_path = pyNastran.__path__[0]
>>> test_path = os.path.join(pkg_path, '..', 'models', 'plate_py')
>>> op2_filename = os.path.join(test_path, 'plate_py.op2')
ut_filename = os.path.join(test_path, ‘solid_bending.out’)
instantiate the model
>>> from pyNastran.op2.op2 import OP2
>>> model = OP2()
>>> model.read_op2(op2_filename, vectorized=True)
>>> print(model.get_op2_stats())
op2.eigenvectors[1]
type=RealEigenvectorArray ntimes=10 nnodes=231
data: [t1, t2, t3, r1, r2, r3] shape=[10, 231, 6] dtype=float32
gridTypes
modes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
eigrs = [-0.00037413835525512695, -0.00022113323211669922, -0.0001882314682006836, -0.00010025501251220703, 0.0001621246337890625, 0.00
07478296756744385, 1583362560.0, 2217974016.0, 10409966592.0, 11627085824.0]
mode_cycles = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> isubcase = 1
>>> eigenvector = model.eigenvectors[isubcase]
“time/mode/frequency are stored by id, so to get mode 5:
>>> modes = eigenvector._times # it may not be "time" so we don't use the name "time"
>>> from numpy import where
>>> imode5 = where(modes == 5)[0]
>>> txyz = eigenvector.data[imode5, :, :3]
calculate the total deflection of the vector
>>> from numpy.linalg import norm
>>> total_xyz = norm(txyz, axis=1)
get the eigenvalue
>>> print('eigr5 = %s' % eigenvector.eigrs[imode5])
eigr5 = 0.000162124633789
Example 5: Isotropic Plate Stress (static)¶
This example will demonstate:
- print the fiber distance and the max principal stress for a static case for a vectorized OP2
our model
>>> import pyNastran
>>> pkg_path = pyNastran.__path__[0]
>>> test_path = os.path.join(pkg_path, '..', 'models', 'sol_101_elements')
>>> op2_filename = os.path.join(test_path, 'static_solid_shell_bar.op2')
instantiate the model
>>> from pyNastran.op2.op2 import OP2
>>> model = OP2()
>>> model.read_op2(op2_filename, vectorized=True)
>>> print(model.get_op2_stats())
op2.cquad4_stress[1]
type=RealPlateStressArray nelements=2 nnodes_per_element=5 nlayers=2 ntotal=20
data: [1, ntotal, 8] where 8=[fiber_distance, oxx, oyy, txy, angle, omax, omin, von_mises]
data.shape=(1L, 20L, 8L)
element types: CQUAD4
lsdvmns = [1]
>>> isubcase = 1
>>> itime = 0 # this is a static case
>>> stress = model.cquad4_stress[isubcase]
>>> assert stress.nnodes == 5, 'this is a bilinear quad'
write the data
#[fiber_dist, oxx, oyy, txy, angle, majorP, minorP, ovm]
>>> eids = stress.element_node[:, 0]
>>> nids = stress.element_node[:, 1]
>>> if stress.is_fiber_distance():
>>> fiber_dist = stress.data[itime, :, 0]
>>> else:
>>> raise RuntimeError('found fiber curvature; expected fiber distance')
>>> maxp = stress.data[itime, :, 5]
>>> for (eid, nid, fdi, maxpi) in zip(eids, nids, fiber_dist, maxp):
>>> print(eid, 'CEN/4' if nid == 0 else nid, fdi, maxpi)
6 CEN/4 -0.125 8022.26
6 CEN/4 0.125 12015.9
6 4 -0.125 7580.84
6 4 0.125 11872.9
6 1 -0.125 8463.42
6 1 0.125 12158.9
6 14 -0.125 8463.69
6 14 0.125 12158.9
6 15 -0.125 7581.17
6 15 0.125 11872.9
7 CEN/4 -0.125 10016.3
7 CEN/4 0.125 10019.5
7 3 -0.125 10307.1
7 3 0.125 10311.0
7 2 -0.125 9725.54
7 2 0.125 9727.9
7 17 -0.125 9725.54
7 17 0.125 9728.06
7 16 -0.125 10307.1
7 16 0.125 10311.1
note we have 2 layers (upper and lower surface) for any PSHELL-based elements
Example 6: Composite Plate Stress (static)¶
This example will demonstate:
- print the fiber distance and the max principal stress for a static case for a vectorized OP2
our model
>>> import pyNastran
>>> pkg_path = pyNastran.__path__[0]
>>> test_path = os.path.join(pkg_path, '..', 'models', 'sol_101_elements')
>>> op2_filename = os.path.join(test_path, 'static_solid_comp_bar.op2')
instantiate the model
>>> from pyNastran.op2.op2 import OP2
>>> model = OP2()
>>> model.read_op2(op2_filename, vectorized=True)
>>> print(model.get_op2_stats())
op2.ctria3_composite_stress[1]
type=RealCompositePlateStressArray nelements=4 ntotal=18
data: [1, ntotal, 9] where 9=[o11, o22, t12, t1z, t2z, angle, major, minor, max_shear]
data.shape = (1, 18, 9)
element types: CTRIA3
lsdvmns = [1]
>>> isubcase = 1
>>> itime = 0 # this is a static case
>>> stress = model.ctria3_composite_stress[isubcase]
In the previous example, we had an option for a variable number of nodes for the CQUAD4s (1/5), but only nnodes=1 for the CTRIA3s.
In this example, we have 4 layers on one element and 5 on another, but they’re all at the centroid.
#[o11, o22, t12, t1z, t2z, angle, major, minor, ovm]
>>> eids = stress.element_layer[:, 0]
>>> layers = stress.element_layer[:, 1]
>>> maxp = stress.data[itime, :, 6]
>>> if stress.is_fiber_distance():
>>> fiber_dist = stress.data[itime, :, 0]
>>> else:
>>> raise RuntimeError('found fiber curvature; expected fiber distance')
>>> maxp = stress.data[itime, :, 5]
>>> for (eid, layer, maxpi) in zip(eids, layers, maxp):
>>> print(eid, 'CEN/4', layer, maxpi)
7 CEN/4 1 89.3406
7 CEN/4 2 89.3745
7 CEN/4 3 89.4313
7 CEN/4 4 89.5115
8 CEN/4 1 -85.6691
8 CEN/4 2 -85.6121
8 CEN/4 3 -85.5193
8 CEN/4 4 -85.3937
8 CEN/4 5 -85.2394
9 CEN/4 1 86.3663
9 CEN/4 2 86.6389
9 CEN/4 3 87.0977
9 CEN/4 4 87.7489
10 CEN/4 1 -87.6962
10 CEN/4 2 -87.4949
10 CEN/4 3 -87.1543
10 CEN/4 4 -86.6662
10 CEN/4 5 -86.0192
pyNastran Package¶
This is the pyNastran.rst file for v0.7.
bdf Package¶
This is the pyNastran.bdf.rst file.
bdf Module¶
bdf_Methods Module¶
bdf_replacer Module¶
caseControlDeck Module¶
deprecated Module¶
fieldWriter Module¶
field_writer_8 Module¶
field_writer_16 Module¶
field_writer_double Module¶
Defines functions for double precision 16 character field writing.
- pyNastran.bdf.field_writer_double.print_card_double(fields, wipe_fields=True)[source]¶
Prints a nastran-style card with 16-character width fields.
Parameters: - fields – all the fields in the BDF card (no trailing Nones)
- wipe_fields – some cards (e.g. PBEAM) have ending fields that need to be there, others cannot have them.
Note
An internal field value of None or ‘’ will be treated as a blank field
Note
A large field format follows the 8-16-16-16-16-8 = 80 format where the first 8 is the card name or blank (continuation). The last 8-character field indicates an optional continuation, but because it’s a left-justified unneccessary field, print_card doesnt use it.
>>> fields = ['DUMMY', 1, 2, 3, None, 4, 5, 6, 7, 8.] >>> print_card_double(fields) DUMMY* 1 2 3 * 4 5 6 7 * 8.0000000000D+00 *
subcase Module¶
Subcase creation/extraction class
- class pyNastran.bdf.subcase.Subcase(id=0)[source]¶
Bases: object
Subcase creation/extraction class
- cross_reference(model)[source]¶
Method crossReference:
Parameters: - self – the Subcase object
- model – the BDF object
Note
this is not integrated and probably never will be as it’s not really that necessary. it’s only really useful when running an analysis.
- finish_subcase()[source]¶
Removes the subcase parameter from the subcase to avoid printing it in a funny spot
Parameters: self – the Subcase object
- get_analysis_code(sol)[source]¶
Maps the solution number to the OP2 analysis code.
- 8 - post-buckling (maybe 7 depending on NLPARM???)
- # not important
- 3/4 - differential stiffness (obsolete)
- 11 - old geometric nonlinear statics
- 12 - contran (???)
Todo
verify
- get_device_code(options, value)[source]¶
Gets the device code of a given set of options and value
Parameters: - self – the Subcase object
- options – the options for a parameter
- value – the value of the parameter
- get_format_code(options, value)[source]¶
Gets the format code that will be used by the op2 based on the options.
Parameters: - self – the Subcase object
- options – the options for a parameter
- value – the value of the parameter
Todo
not done...only supports REAL, IMAG, PHASE, not RANDOM
- get_parameter(param_name)[source]¶
Gets the [value, options] for a subcase.
Parameters: - self – the Subcase object
- param_name – the case control parameter to check for
model = BDF() model.read_bdf(bdf_filename) case_control = model.caseControlDeck subcase1 = case_control.subcases[1] value, options = subcase1['LOAD']
- get_sort_code(options, value)[source]¶
Gets the sort code of a given set of options and value
Parameters: - self – the Subcase object
- options – the options for a parameter
- value – the value of the parameter
- get_stress_code(key, options, value)[source]¶
Method get_stress_code:
Note
the individual element must take the stress_code and reduce
it to what the element can return. For example, for an isotropic CQUAD4 the fiber field doesnt mean anything.
BAR - no von mises/fiber ISOTROPIC - no fiber
Todo
how does the MATERIAL bit get turned on? I’m assuming it’s element dependent...
- get_table_code(sol, table_name, options)[source]¶
Gets the table code of a given parameter. For example, the DISPLACMENT(PLOT,POST)=ALL makes an OUGV1 table and stores the displacement. This has an OP2 table code of 1, unless you’re running a modal solution, in which case it makes an OUGV1 table of eigenvectors and has a table code of 7.
Parameters: - self – the Subcase object
- options – the options for a parameter
- value – the value of the parameter
- print_param(key, param)[source]¶
Prints a single entry of the a subcase from the global or local subcase list.
Parameters: self – the Subcase object
- solCodeMap = {64: 106, 1: 101, 66: 106, 68: 106, 76: 101, 144: 101, 21: 101, 24: 101, 26: 101, 99: 129, 187: 101, 61: 101}¶
utils Module¶
write_path Module¶
- Defines following useful methods:
- write_include
- pyNastran.bdf.write_path._split_path(abspath)[source]¶
Takes a path and splits it into the various components.
This is a helper method for write_include
- pyNastran.bdf.write_path.write_include(filename, is_windows=True)[source]¶
Writes a bdf INCLUDE file line given an imported filename.
Parameters: - filename – the filename to write
- is_windows – Windows has a special format for writing INCLUDE files so the format for a BDF that will run on Linux and Windows is different. We could check the platform, but since you might need to change platforms, it’s an option (default=True)
For a model that will run on Linux:
..code-blocK:: python
fname = r’/opt/NASA/test1/test2/test3/test4/formats/pynastran_v0.6/pyNastran/bdf/model.inc’ write_include(fname, is_windows=False)We want:
..code-blocK:: python
- INCLUDE /opt/NASA/test1/test2/test3/test4/formats/pynastran_v0.6/
- pyNastran/bdf/model.inc
bdfInterface Package¶
addCard Module¶
- class pyNastran.bdf.bdfInterface.addCard.AddMethods[source]¶
Bases: object
- add_creep_material(material, allowOverwrites=False)[source]¶
Note
May be removed in the future. Are CREEP cards materials? They have an MID, but reference structural materials.
assign_type Module¶
Parses Nastran fields
- pyNastran.bdf.bdfInterface.assign_type._get_dtype(value)[source]¶
Get the type of the input value in a form that is clear.
Parameters: value – the value to get the type of
- pyNastran.bdf.bdfInterface.assign_type.blank(card, ifield, fieldname, default=None)[source]¶
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- default – the default value for the field (default=None)
- pyNastran.bdf.bdfInterface.assign_type.components(card, ifield, fieldname)[source]¶
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- pyNastran.bdf.bdfInterface.assign_type.components_or_blank(card, ifield, fieldname, default=None)[source]¶
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- default – the default value for the field (default=None)
- pyNastran.bdf.bdfInterface.assign_type.double(card, ifield, fieldname)[source]¶
Converts a field into a double
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- pyNastran.bdf.bdfInterface.assign_type.double_or_blank(card, ifield, fieldname, default=None)[source]¶
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- default – the default value for the field (default=None)
- pyNastran.bdf.bdfInterface.assign_type.double_or_string(card, ifield, fieldname)[source]¶
Converts a field into a double or a string
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- pyNastran.bdf.bdfInterface.assign_type.double_string_or_blank(card, ifield, fieldname, default=None)[source]¶
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- default – the default value for the field (default=None)
Returns value: a double, string, or default value
Raises SyntaxError: if there is an invalid type
- pyNastran.bdf.bdfInterface.assign_type.field(card, ifield, fieldname)[source]¶
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- pyNastran.bdf.bdfInterface.assign_type.fields(f, card, fieldname, i, j=None)[source]¶
Todo
improve fieldname
- pyNastran.bdf.bdfInterface.assign_type.integer(card, ifield, fieldname)[source]¶
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- pyNastran.bdf.bdfInterface.assign_type.integer_double_or_blank(card, ifield, fieldname, default=None)[source]¶
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- default – the default value for the field (default=None)
- pyNastran.bdf.bdfInterface.assign_type.integer_double_or_string(card, ifield, fieldname)[source]¶
Converts a field into an integer, double or a string
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- pyNastran.bdf.bdfInterface.assign_type.integer_double_string_or_blank(card, ifield, fieldname, default=None)[source]¶
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- default – the default value for the field (default=None)
- pyNastran.bdf.bdfInterface.assign_type.integer_or_blank(card, ifield, fieldname, default=None)[source]¶
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- default – the default value for the field (default=None)
- pyNastran.bdf.bdfInterface.assign_type.integer_or_double(card, ifield, fieldname)[source]¶
Converts a field into an integer or double
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
Returns value: the value with the proper type
Raises SyntaxError: if there’s an invalid type
- pyNastran.bdf.bdfInterface.assign_type.integer_or_string(card, ifield, fieldname)[source]¶
Converts a field into an integer or string
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- default – the default value for the field (default=None)
- pyNastran.bdf.bdfInterface.assign_type.integer_string_or_blank(card, ifield, fieldname, default=None)[source]¶
Converts a field into an integer, string or sets the default using a blank value
Parameters: - card – BDF card as a list
- ifield – field number
- fieldname – name of field
- default – the default value for the field (default=None)
- pyNastran.bdf.bdfInterface.assign_type.interpret_value(value_raw, card='')[source]¶
Converts a value from nastran format into python format.
Parameters: - raw_value – a string representation of a value
- card –
???
Returns value: the Nastran reprentation of the value
BDF_Card Module¶
Defines the BDFCard class that is passed into the various Nastran cards.
- class pyNastran.bdf.bdfInterface.BDF_Card.BDFCard(card=None, debug=False)[source]¶
Bases: object
A BDFCard is a list that has a default value of None for fields out of range.
- field(i, default=None)[source]¶
Gets the ith field on the card
Parameters: - self – the object pointer
- i (integer) – the ith field on the card (following list notation)
- default – the default value for the field
Returns value: the value on the ith field
- fields(i=0, j=None, defaults=None)[source]¶
Gets multiple fields on the card
Parameters: - self – the object pointer
- i (integer >= 0) – the ith field on the card (following list notation)
- j (integer or None (default=end of card)) – the jth field on the card (None means till the end of the card)
- defaults – the default value for the field (as a list) len(defaults)=i-j-1
Returns value: the values on the ith-jth fields
bdf_writeMesh Module¶
crossReference Module¶
Links up the various cards in the BDF.
For example, with cross referencing...
>>> model = BDF()
>>> model.read_bdf(bdf_filename, xref=True)
>>> nid1 = 1
>>> node1 = model.nodes[nid1]
>>> node.nid
1
>>> node.xyz
[1., 2., 3.]
>>> node.Cid()
3
>>> node.cid
CORD2S, 3, 1, 0., 0., 0., 0., 0., 1.,
1., 0., 0.
# get the position in the global frame
>>> node.Position()
[4., 5., 6.]
# get the position with respect to another frame
>>> node.PositionWRT(model, cid=2)
[4., 5., 6.]
Without cross referencing...
>>> model = BDF()
>>> model.read_bdf(bdf_filename, xref=True)
>>> nid1 = 1
>>> node1 = model.nodes[nid1]
>>> node.nid
1
>>> node.xyz
[1., 2., 3.]
>>> node.Cid()
3
>>> node.cid
3
# get the position in the global frame
>>> node.Position()
Error!
Cross-referencing allows you to easily jump across cards and also helps with calculating things like position, area, and mass. The BDF is designed around the idea of cross-referencing, so it’s recommended that you use it.
- class pyNastran.bdf.bdfInterface.crossReference.XrefMesh[source]¶
Bases: object
Links up the various cards in the BDF.
The main BDF class defines all the parameters that are used.
- _cross_reference_coordinates()[source]¶
Links up all the coordinate cards to other coordinate cards and nodes
- _cross_reference_elements()[source]¶
Links the elements to nodes, properties (and materials depending on the card).
- _cross_reference_masses()[source]¶
Links the mass to nodes, properties (and materials depending on the card).
- _cross_reference_materials()[source]¶
Links the materials to materials (e.g. MAT1, CREEP) often this is a pass statement
- cross_reference(xref=True, xref_elements=True, xref_properties=True, xref_materials=True, xref_loads=True, xref_constraints=True, xref_aero=True)[source]¶
Links up all the cards to the cards they reference
Parameters: - xref – cross references the model (default=True)
- xref_element – set cross referencing of elements (default=True)
- xref_properties – set cross referencing of properties (default=True)
- xref_materials – set cross referencing of materials (default=True)
- xref_loads – set cross referencing of loads (default=True)
- xref_constraints – set cross referencing of constraints (default=True)
- xref_aero – set cross referencing of CAERO/SPLINEs (default=True)
To only cross-reference nodes:
model = BDF() model.read_bdf(bdf_filename, xref=False) model.cross_reference(xref=True, xref_loads=False, xref_constraints=False, xref_materials=False, xref_properties=False, xref_aero=False, xref_masses=False)
Warning
be careful if you call this method
getCard Module¶
cards Package¶
aero Module¶
baseCard Module¶
bdf_sets Module¶
bdf_tables Module¶
constraints Module¶
contact Module¶
coordinateSystems Module¶
dmig Module¶
dynamic Module¶
materials Module¶
material_deps Module¶
methods Module¶
nodes Module¶
optimization Module¶
params Module¶
utils Module¶
- pyNastran.bdf.cards.utils.build_table_lines(fields, nstart=1, nend=0)[source]¶
Builds a table of the form:
DESVAR DVID1 DVID2 DVID3 DVID4 DVID5 DVID6 DVID7 DVID8 -etc.- UM VAL1 VAL2 -etc.- and then pads the rest of the fields with None’s
Parameters: - fields (list of values) – the fields to enter, including DESVAR
- nStart – the number of blank fields at the start of the line (default=1)
- nStart – int
- nEnd – the number of blank fields at the end of the line (default=0)
- nEnd – int
Note
will be used for DVPREL2, RBE1, RBE3
Warning
only works for small field format???
test Package¶
all_tests Module¶
bdf_test Module¶
bdf_unit_tests Module¶
compare_card_content Module¶
get_uniq_fields Module¶
run_nastran_double_precision Module¶
test_bdf Module¶
test_case_control_deck Module¶
test_field_writer Module¶
test_openmdao Module¶
- class pyNastran.bdf.test.unit.test_assign_type.ExtendedTestCase(methodName='runTest')[source]¶
Bases: unittest.case.TestCase
Create an instance of the class that will use the named test method when executed. Raises a ValueError if the instance does not have a method with the specified name.
- class pyNastran.bdf.test.unit.test_assign_type.Test(methodName='runTest')[source]¶
Bases: pyNastran.bdf.test.unit.test_assign_type.ExtendedTestCase
Create an instance of the class that will use the named test method when executed. Raises a ValueError if the instance does not have a method with the specified name.
f06 Package¶
This is the pyNastran.f06.rst file.
f06 Module¶
f06Writer Module¶
f06_classes Module¶
f06_formatting Module¶
op2 Package¶
This is the pyNastran.op2.rst file.
op2 Module¶
op2_scalar Module¶
fortran_format Module¶
- class pyNastran.op2.fortran_format.FortranFormat[source]¶
Bases: object
Parameters: self – the OP2 object pointer - _get_record_length()[source]¶
The record length helps us figure out data block size, which is used to quickly size the arrays. We just need a bit of meta data and can jump around quickly.
- _read_subtable_results(table4_parser, record_len)[source]¶
# if reading the data # 0 - non-vectorized # 1 - 1st pass to size the array (vectorized) # 2 - 2nd pass to read the data (vectorized)
- _stream_record(debug=True)[source]¶
Creates a “for” loop that keeps giving us records until we’re done.
Parameters: self – the OP2 object pointer
- get_nmarkers(n, rewind=True)[source]¶
Gets n markers, so if n=2, it will get 2 markers.
Parameters: - self – the OP2 object pointer
- n – number of markers to get
- rewind – should the file be returned to the starting point
Retval markers: list of [1, 2, 3, ...] markers
- goto(n)[source]¶
Jumps to position n in the file
Parameters: - self – the OP2 object pointer
- n – the position to goto
- isAllSubcases = None¶
stores if the user entered [] for iSubcases
- is_valid_subcase()[source]¶
Lets the code check whether or not to read a subcase
Parameters: self – the OP2 object pointer Retval is_valid: should this subcase defined by self.isubcase be read?
- passer(data)[source]¶
dummy function used for unsupported tables :param self: the OP2 object pointer
- read_block()[source]¶
- Reads a block following a pattern of:
- [nbytes, data, nbytes]
Retval data: the data in binary
- read_markers(markers)[source]¶
Gets specified markers, where a marker has the form of [4, value, 4]. The “marker” corresponds to the value, so 3 markers takes up 9 integers. These are used to indicate position in the file as well as the number of bytes to read.
Parameters: - self – the OP2 object pointer
- markers – markers to get; markers = [-10, 1]
- skip_block()[source]¶
- Skips a block following a pattern of:
- [nbytes, data, nbytes]
Parameters: self – the OP2 object pointer Retval data: since data can never be None, a None value indicates something bad happened.
op2_helper Module¶
op2_common Module¶
op2_f06_common Module¶
vector_utils Module¶
resultObjects Package¶
op2_Objects Module¶
- class pyNastran.op2.resultObjects.op2_Objects.ScalarObject(data_code, isubcase, apply_data_code=True)[source]¶
Bases: pyNastran.op2.resultObjects.op2_Objects.BaseScalarObject
- append_data_member(var_name, value_name)[source]¶
this appends a data member to a variable that may or may not exist
- print_data_members()[source]¶
Prints out the “unique” vals of the case. Uses a provided list of data_code[‘dataNames’] to set the values for each subcase. Then populates a list of self.name+’s‘ (by using setattr) with the current value. For example, if the variable name is ‘mode’, we make self.modes. Then to extract the values, we build a list of of the variables that were set like this and then loop over them to print their values.
This way there is no dependency on one result type having [‘mode’] and another result type having [‘mode’,’eigr’,’eigi’].
tableObject Module¶
tables Package¶
ogs Module¶
ogpwg Module¶
utils Package¶
This is the pyNastran.utils.rst file.