# pylint: disable=C0103,R0902,R0904,R0914,W0612
"""
All solid elements are defined in this file. This includes:
* CHEXA8
* CHEXA20
* CPENTA6
* CPENTA15
* CTETRA4
* CTETRA10
All solid elements are SolidElement and Element objects.
"""
from __future__ import (nested_scopes, generators, division, absolute_import,
print_function, unicode_literals)
from six.moves import range
from numpy import dot, cross, array, matrix, zeros
from numpy.linalg import solve, norm
from pyNastran.bdf.cards.elements.elements import Element
from pyNastran.utils.mathematics import Area, gauss
from pyNastran.bdf.bdfInterface.assign_type import (integer, integer_or_blank, fields)
[docs]def volume4(n1, n2, n3, n4):
r"""
Gets the volume, :math:`V`, of the tetrahedron.
.. math:: V = \frac{(a-d) \cdot \left( (b-d) \times (c-d) \right) }{6}
"""
V = -dot((n1 - n4), cross(n2 - n4, n3 - n4)) / 6.
return V
[docs]def area_centroid(n1, n2, n3, n4):
"""
Gets the area, :math:`A`, and centroid of a quad.::
1-----2
| / |
| / |
4-----3
"""
a = n1 - n2
b = n2 - n4
area1 = Area(a, b)
c1 = (n1 + n2 + n4) / 3.
a = n2 - n4
b = n2 - n3
area2 = Area(a, b)
c2 = (n2 + n3 + n4) / 3.
area = area1 + area2
try:
centroid = (c1 * area1 + c2 * area2) / area
except FloatingPointError:
msg = '\nc1=%r\narea1=%r\n' % (c1, area1)
msg += 'c2=%r\narea2=%r' % (c2, area2)
raise FloatingPointError(msg)
return(area, centroid)
[docs]class SolidElement(Element):
_field_map = {1: 'nid', 2:'pid'}
def __init__(self, card, data):
Element.__init__(self, card, data)
[docs] def _update_field_helper(self, n, value):
if n - 3 < len(self.nodes):
self.nodes[n - 3] = value
else:
raise KeyError('Field %r=%r is an invalid %s entry.' % (n, value, self.type))
[docs] def cross_reference(self, model):
raise NotImplementedError('Element type=%r must implement cross_reference')
[docs] def Eid(self):
return self.eid
[docs] def E(self):
return self.pid.mid.E()
[docs] def G(self):
return self.pid.mid.G()
[docs] def Nu(self):
return self.pid.mid.Nu()
[docs] def Volume(self):
"""
Base volume method that should be overwritten
"""
pass
[docs] def Mass(self):
"""
Calculates the mass of the solid element
Mass = Rho * Volume
"""
return self.Rho() * self.Volume()
[docs] def Mid(self):
"""
Returns the material ID as an integer
"""
return self.pid.Mid()
[docs] def Rho(self):
"""
Returns the density
"""
try:
return self.pid.mid.rho
except AttributeError:
print("self.pid = %s" % (self.pid))
print("self.pid.mid = %s" % (str(self.pid.mid)))
raise
[docs] def _is_same_card(self, elem, debug=False):
if self.type != elem.type:
return False
fields1 = [self.eid, self.Pid()] + self.nodes
fields2 = [elem.eid, elem.Pid()] + elem.nodes
if debug:
print("fields1=%s fields2=%s" % (fields1, fields2))
return self._is_same_fields(fields1, fields2)
[docs] def raw_fields(self):
list_fields = [self.type, self.eid, self.Pid()] + self.node_ids
return list_fields
#def write_card(self, size=8, is_double=False):
#card = self.raw_fields()
#msg2 = self.write_card()
##msg1 = self.comment() + print_card_8(card)
##assert msg1 == msg2, 'write_card != write_card\n%s---\n%s\n%r\n%r' % (msg1, msg2, msg1, msg2)
#return msg2
[docs]class CHEXA8(SolidElement):
"""
+-------+-----+-----+----+----+----+----+----+----+
| CHEXA | EID | PID | G1 | G2 | G3 | G4 | G5 | G6 |
+-------+-----+-----+----+----+----+----+----+----+
| | G7 | G8 | | | | | | |
+-------+-----+-----+----+----+----+----+----+----+
"""
type = 'CHEXA'
asterType = 'HEXA8'
calculixType = 'C3D8'
[docs] def write_card(self, size=8, is_double=False):
data = [self.eid, self.Pid()] + self.node_ids
msg = ('CHEXA %8i%8i%8i%8i%8i%8i%8i%8i\n'
' %8i%8i\n' % tuple(data))
return self.comment() + msg
def __init__(self, card=None, data=None, comment=''):
SolidElement.__init__(self, card, data)
if comment:
self._comment = comment
if card:
#: Element ID
self.eid = integer(card, 1, 'eid')
#: Property ID
self.pid = integer(card, 2, 'pid')
nids = [
integer(card, 3, 'nid1'),
integer(card, 4, 'nid2'),
integer(card, 5, 'nid3'),
integer(card, 6, 'nid4'),
integer(card, 7, 'nid5'),
integer(card, 8, 'nid6'),
integer(card, 9, 'nid7'),
integer(card, 10, 'nid8')
]
assert len(card) == 11, 'len(CHEXA8 card) = %i' % len(card)
else:
self.eid = data[0]
self.pid = data[1]
nids = data[2:]
assert len(data) == 10, 'len(data)=%s data=%s' % (len(data), data)
self.prepare_node_ids(nids)
assert len(self.nodes) == 8
[docs] def cross_reference(self, model):
msg = ' which is required by %s eid=%s' % (self.type, self.eid)
self.nodes = model.Nodes(self.nodes, allowEmptyNodes=False, msg=msg)
self.pid = model.Property(self.pid, msg=msg)
[docs] def _verify(self, xref=False):
eid = self.Eid()
pid = self.Pid()
assert isinstance(eid, int)
assert isinstance(pid, int)
for i, nid in enumerate(self.node_ids):
assert isinstance(nid, int), 'nid%i is not an integer; nid=%s' %(i, nid)
if xref:
c = self.Centroid()
v = self.Volume()
assert isinstance(v, float)
for i in range(3):
assert isinstance(c[i], float)
[docs] def Centroid(self):
"""
Averages the centroids at the two faces
"""
(n1, n2, n3, n4, n5, n6, n7, n8) = self.nodePositions()
A1, c1 = area_centroid(n1, n2, n3, n4)
A2, c2 = area_centroid(n5, n6, n7, n8)
c = (c1 + c2) / 2.
return c
[docs] def Volume(self):
(n1, n2, n3, n4, n5, n6, n7, n8) = self.nodePositions()
(A1, c1) = area_centroid(n1, n2, n3, n4)
(A2, c2) = area_centroid(n5, n6, n7, n8)
V = (A1 + A2) / 2. * norm(c1 - c2)
return abs(V)
[docs] def nodeIDs(self):
return self.node_ids
@property
def node_ids(self):
return self._nodeIDs(allowEmptyNodes=False)
@node_ids.setter
def node_ids(self, value):
raise ValueError("You cannot set node IDs like this...modify the node objects")
[docs]class CHEXA20(SolidElement):
"""
+-------+-----+-----+-----+-----+-----+-----+-----+-----+
| CHEXA | EID | PID | G1 | G2 | G3 | G4 | G5 | G6 |
+-------+-----+-----+-----+-----+-----+-----+-----+-----+
| | G7 | G8 | G9 | G10 | G11 | G12 | G13 | G14 |
+-------+-----+-----+-----+-----+-----+-----+-----+-----+
| | G15 | G16 | G17 | G18 | G19 | G20 | | |
+-------+-----+-----+-----+-----+-----+-----+-----+-----+
"""
type = 'CHEXA'
asterType = 'HEXA20'
calculixType = 'C3D20'
[docs] def write_card(self, size=8, is_double=False):
nodes = self.node_ids
nodes2 = ['' if node is None else '%8i' % node for node in nodes[8:]]
data = [self.eid, self.Pid()] + nodes[:8] + nodes2
msg = ('CHEXA %8i%8i%8i%8i%8i%8i%8i%8i\n'
' %8i%8i%8s%8s%8s%8s%8s%8s\n'
' %8s%8s%8s%8s%8s%8s' % tuple(data))
return self.comment() + msg.rstrip() + '\n'
def __init__(self, card=None, data=None, comment=''):
SolidElement.__init__(self, card, data)
if comment:
self._comment = comment
if card:
#: Element ID
self.eid = integer(card, 1, 'eid')
#: Property ID
self.pid = integer(card, 2, 'pid')
nids = [integer(card, 3, 'nid1'), integer(card, 4, 'nid2'),
integer(card, 5, 'nid3'), integer(card, 6, 'nid4'),
integer(card, 7, 'nid5'), integer(card, 8, 'nid6'),
integer(card, 9, 'nid7'), integer(card, 10, 'nid8'),
integer_or_blank(card, 11, 'nid9'),
integer_or_blank(card, 12, 'nid10'),
integer_or_blank(card, 13, 'nid11'),
integer_or_blank(card, 14, 'nid12'),
integer_or_blank(card, 15, 'nid13'),
integer_or_blank(card, 16, 'nid14'),
integer_or_blank(card, 17, 'nid15'),
integer_or_blank(card, 18, 'nid16'),
integer_or_blank(card, 19, 'nid17'),
integer_or_blank(card, 20, 'nid18'),
integer_or_blank(card, 21, 'nid19'),
integer_or_blank(card, 22, 'nid20')]
assert len(card) <= 23, 'len(CHEXA20 card) = %i' % len(card)
else:
self.eid = data[0]
self.pid = data[1]
nids = [d if d > 0 else None for d in data[2:]]
self.prepare_node_ids(nids, allow_empty_nodes=True)
msg = 'len(nids)=%s nids=%s' % (len(nids), nids)
assert len(self.nodes) <= 20, msg
[docs] def cross_reference(self, model):
msg = ' which is required by %s eid=%s' % (self.type, self.eid)
self.nodes = model.Nodes(self.nodes, allowEmptyNodes=True, msg=msg)
self.pid = model.Property(self.pid, msg=msg)
[docs] def _verify(self, xref=False):
eid = self.Eid()
pid = self.Pid()
assert isinstance(eid, int)
assert isinstance(pid, int)
for i, nid in enumerate(self.node_ids):
assert nid is None or isinstance(nid, int), 'nid%i is not an integer/blank; nid=%s' %(i, nid)
if xref:
c = self.Centroid()
v = self.Volume()
assert isinstance(v, float)
for i in range(3):
assert isinstance(c[i], float)
[docs] def Centroid(self):
"""
.. seealso:: CHEXA8.Centroid
"""
(n1, n2, n3, n4, n5,
n6, n7, n8, n9, n10,
n11, n12, n13, n14, n15,
n16, n17, n18, n19, n20) = self.nodePositions()
(A1, c1) = area_centroid(n1, n2, n3, n4)
(A2, c2) = area_centroid(n5, n6, n7, n8)
c = (c1 + c2) / 2.
return c
[docs] def Volume(self):
"""
.. seealso:: CHEXA8.Volume
"""
(n1, n2, n3, n4, n5,
n6, n7, n8, n9, n10,
n11, n12, n13, n14, n15,
n16, n17, n18, n19, n20) = self.nodePositions()
(A1, c1) = area_centroid(n1, n2, n3, n4)
(A2, c2) = area_centroid(n5, n6, n7, n8)
V = (A1 + A2) / 2. * norm(c1 - c2)
return abs(V)
[docs] def nodeIDs(self):
return self.node_ids
@property
def node_ids(self):
return self._nodeIDs(allowEmptyNodes=True)
@node_ids.setter
def node_ids(self, value):
raise ValueError("You cannot set node IDs like this...modify the node objects")
[docs]class CPENTA6(SolidElement):
"""
+--------+-----+-----+----+----+----+----+----+----+
| CPENTA | EID | PID | G1 | G2 | G3 | G4 | G5 | G6 |
+--------+-----+-----+----+----+----+----+----+----+
::
*----------*
/ \ / \
/ A \ / c \
*---*-----*-----*
V = (A1+A2)/2 * norm(c1-c2)
C = (c1-c2)/2
"""
type = 'CPENTA'
asterType = 'PENTA6'
calculixType = 'C3D6'
[docs] def write_card(self, size=8, is_double=False):
nodes = self.node_ids
data = [self.eid, self.Pid()] + nodes
msg = 'CPENTA %8i%8i%8i%8i%8i%8i%8i%8i\n' % tuple(data)
return self.comment() + msg
def __init__(self, card=None, data=None, comment=''):
SolidElement.__init__(self, card, data)
if comment:
self._comment = comment
if card:
#: Element ID
self.eid = integer(card, 1, 'eid')
#: Property ID
self.pid = integer(card, 2, 'pid')
nids = [
integer(card, 3, 'nid1'),
integer(card, 4, 'nid2'),
integer(card, 5, 'nid3'),
integer(card, 6, 'nid4'),
integer(card, 7, 'nid5'),
integer(card, 8, 'nid6'),
]
assert len(card) == 9, 'len(CPENTA6 card) = %i' % len(card)
else:
self.eid = data[0]
self.pid = data[1]
nids = data[2:]
assert len(data) == 8, 'len(data)=%s data=%s' % (len(data), data)
self.prepare_node_ids(nids)
assert len(self.nodes) == 6
[docs] def cross_reference(self, model):
msg = ' which is required by %s eid=%s' % (self.type, self.eid)
self.nodes = model.Nodes(self.nodes, allowEmptyNodes=False, msg=msg)
self.pid = model.Property(self.pid, msg=msg)
[docs] def getFaceAreaCentroidNormal(self, nidOpposite, nid):
nids = self.node_ids[:6]
indx1 = nids.index(nid)
indx2 = nids.index(nidOpposite)
# offset so it's easier to map the nodes with the QRG
pack = [indx1 + 1, indx2 + 1]
pack.sort()
mapper = {
# reverse points away from the element
[1, 2]: [1, 2, 3], # close
[2, 3]: [1, 2, 3],
[1, 3]: [1, 2, 3],
[4, 5]: [4, 5, 6], # far-reverse
[5, 6]: [4, 5, 6],
[4, 6]: [4, 5, 6],
[1, 5]: [1, 2, 5, 4], # bottom
[2, 4]: [1, 2, 5, 4],
[1, 6]: [1, 3, 6, 4], # left-reverse
[3, 4]: [1, 3, 6, 4],
[2, 6]: [2, 5, 6, 3], # right
[3, 5]: [2, 3, 6, 5],
}
pack2 = mapper[pack]
if len(pack2) == 3:
(n1, n2, n3) = pack2
faceNodeIDs = [n1, n2, n3]
n1i = nids.index(n1 - 1)
n2i = nids.index(n2 - 1)
n3i = nids.index(n3 - 1)
p1 = self.nodes[n1i].Position()
p2 = self.nodes[n2i].Position()
p3 = self.nodes[n3i].Position()
a = p1 - p2
b = p1 - p3
centroid = (p1 + p2 + p3) / 3.
else:
(n1, n2, n3, n4) = pack2
n1i = nids.index(n1 - 1)
n2i = nids.index(n2 - 1)
n3i = nids.index(n3 - 1)
n4i = nids.index(n4 - 1)
faceNodeIDs = [n1, n2, n3, n4]
p1 = self.nodes[n1i].Position()
p2 = self.nodes[n2i].Position()
p3 = self.nodes[n3i].Position()
p4 = self.nodes[n4i].Position()
a = p1 - p3
b = p2 - p4
centroid = (p1 + p2 + p3 + p4) / 4.
normal = cross(a, b)
n = norm(normal)
area = 0.5 * n
return area, centroid, normal / n
[docs] def getFaceNodesAndArea(self, nidOpposite, nid):
nids = self.node_ids[:6]
indx1 = nids.index(nid)
indx2 = nids.index(nidOpposite)
# offset so it's easier to map the nodes with the QRG
pack = [indx1 + 1, indx2 + 1]
pack.sort()
mapper = {
# reverse points away from the element
[1, 2]: [1, 2, 3], # close
[2, 3]: [1, 2, 3],
[1, 3]: [1, 2, 3],
[4, 5]: [4, 5, 6], # far-reverse
[5, 6]: [4, 5, 6],
[4, 6]: [4, 5, 6],
[1, 5]: [1, 2, 5, 4], # bottom
[2, 4]: [1, 2, 5, 4],
[1, 6]: [1, 3, 6, 4], # left-reverse
[3, 4]: [1, 3, 6, 4],
[2, 6]: [2, 5, 6, 3], # right
[3, 5]: [2, 3, 6, 5],
}
pack2 = mapper[pack]
if len(pack2) == 3:
(n1, n2, n3) = pack2
faceNodeIDs = [n1, n2, n3]
n1i = nids.index(n1 - 1)
n2i = nids.index(n2 - 1)
n3i = nids.index(n3 - 1)
p1 = self.nodes[n1i].Position()
p2 = self.nodes[n2i].Position()
p3 = self.nodes[n3i].Position()
a = p1 - p2
b = p1 - p3
A = Area(a, b)
else:
(n1, n2, n3, n4) = pack2
n1i = nids.index(n1 - 1)
n2i = nids.index(n2 - 1)
n3i = nids.index(n3 - 1)
n4i = nids.index(n4 - 1)
faceNodeIDs = [n1, n2, n3, n4]
p1 = self.nodes[n1i].Position()
p2 = self.nodes[n2i].Position()
p3 = self.nodes[n3i].Position()
p4 = self.nodes[n4i].Position()
a = p1 - p3
b = p2 - p4
A = Area(a, b)
return [faceNodeIDs, A]
[docs] def _verify(self, xref=False):
eid = self.Eid()
pid = self.Pid()
nids = self.node_ids
assert isinstance(eid, int)
assert isinstance(pid, int)
for i, nid in enumerate(nids):
assert isinstance(nid, int), 'nid%i is not an integer; nid=%s' %(i, nid)
if xref:
c = self.Centroid()
v = self.Volume()
assert isinstance(v, float)
for i in range(3):
assert isinstance(c[i], float)
[docs] def Centroid(self):
(n1, n2, n3, n4, n5, n6) = self.nodePositions()
c1 = (n1 + n2 + n3) / 3.
c2 = (n4 + n5 + n6) / 3.
c = (c1 + c2) / 2.
return c
[docs] def Volume(self):
(n1, n2, n3, n4, n5, n6) = self.nodePositions()
A1 = Area(n3 - n1, n2 - n1)
A2 = Area(n6 - n4, n5 - n4)
c1 = (n1 + n2 + n3) / 3.
c2 = (n4 + n5 + n6) / 3.
V = (A1 + A2) / 2. * norm(c1 - c2)
return abs(V)
[docs] def raw_fields(self):
list_fields = ['CPENTA', self.eid, self.Pid()] + self._nodeIDs(allowEmptyNodes=False)
return list_fields
[docs] def nodeIDs(self):
return self.node_ids
@property
def node_ids(self):
return self._nodeIDs(allowEmptyNodes=False)
@node_ids.setter
def node_ids(self, value):
raise ValueError("You cannot set node IDs like this...modify the node objects")
[docs]class CPENTA15(SolidElement):
"""
+---------+-----+-----+----+-----+-----+-----+-----+-----+
| CPENTA | EID | PID | G1 | G2 | G3 | G4 | G5 | G6 |
+---------+-----+-----+----+-----+-----+-----+-----+-----+
| | G7 | G8 | G9 | G10 | G11 | G12 | G13 | G14 |
+---------+-----+-----+----+-----+-----+-----+-----+-----+
| | G15 | | | | | | | |
+---------+-----+-----+----+-----+-----+-----+-----+-----+
"""
type = 'CPENTA'
asterType = 'PENTA15'
calculixType = 'C3D15'
[docs] def write_card(self, size=8, is_double=False):
nodes = self.node_ids
nodes2 = ['' if node is None else '%8i' % node for node in nodes[6:]]
data = [self.eid, self.Pid()] + nodes[:6] + nodes2
msg = ('CPENTA %8i%8i%8i%8i%8i%8i%8i%8i\n'
' %8s%8s%8s%8s%8s%8s%8s%8s\n'
' %8s' % tuple(data))
return self.comment() + msg.rstrip() + '\n'
def __init__(self, card=None, data=None, comment=''):
SolidElement.__init__(self, card, data)
if comment:
self._comment = comment
if card:
#: Element ID
self.eid = integer(card, 1, 'eid')
#: Property ID
self.pid = integer(card, 2, 'pid')
nids = [
integer(card, 3, 'nid1'),
integer(card, 4, 'nid2'),
integer(card, 5, 'nid3'),
integer(card, 6, 'nid4'),
integer(card, 7, 'nid5'),
integer(card, 8, 'nid6'),
integer_or_blank(card, 9, 'nid7'),
integer_or_blank(card, 10, 'nid8'),
integer_or_blank(card, 11, 'nid9'),
integer_or_blank(card, 12, 'nid10'),
integer_or_blank(card, 13, 'nid11'),
integer_or_blank(card, 14, 'nid12'),
integer_or_blank(card, 15, 'nid13'),
integer_or_blank(card, 16, 'nid14'),
integer_or_blank(card, 17, 'nid15'),
]
assert len(card) <= 18, 'len(CPENTA15 card) = %i' % len(card)
else:
self.eid = data[0]
self.pid = data[1]
nids = [d if d > 0 else None for d in data[2:]]
assert len(data) == 17, 'len(data)=%s data=%s' % (len(data), data)
self.prepare_node_ids(nids, allow_empty_nodes=True)
assert len(self.nodes) <= 15
[docs] def cross_reference(self, model):
msg = ' which is required by %s eid=%s' % (self.type, self.eid)
self.nodes = model.Nodes(self.nodes, allowEmptyNodes=True, msg=msg)
self.pid = model.Property(self.pid, msg=msg)
[docs] def _verify(self, xref=False):
eid = self.Eid()
pid = self.Pid()
nids = self.node_ids
assert isinstance(eid, int)
assert isinstance(pid, int)
for i, nid in enumerate(nids):
assert nid is None or isinstance(nid, int), 'nid%i is not an integer/blank; nid=%s' %(i, nid)
if xref:
c = self.Centroid()
v = self.Volume()
assert isinstance(v, float)
for i in range(3):
assert isinstance(c[i], float)
[docs] def Centroid(self):
"""
.. seealso:: CPENTA6.Centroid
"""
(n1, n2, n3, n4, n5,
n6, n7, n8, n9, n10,
n11, n12, n13, n14, n15) = self.nodePositions()
c1 = (n1 + n2 + n3) / 3.
c2 = (n4 + n5 + n6) / 3.
c = (c1 - c2) / 2.
return c
[docs] def Volume(self):
"""
.. seealso:: CPENTA6.Volume
"""
(n1, n2, n3, n4, n5,
n6, n7, n8, n9, n10,
n11, n12, n13, n14, n15) = self.nodePositions()
A1 = Area(n3 - n1, n2 - n1)
A2 = Area(n6 - n4, n5 - n4)
c1 = (n1 + n2 + n3) / 3.
c2 = (n4 + n5 + n6) / 3.
V = (A1 + A2) / 2. * norm(c1 - c2)
return abs(V)
[docs] def nodeIDs(self):
return self.node_ids
@property
def node_ids(self):
return self._nodeIDs(allowEmptyNodes=True)
@node_ids.setter
def node_ids(self, value):
raise ValueError("You cannot set node IDs like this...modify the node objects")
[docs]class CPYRAM5(SolidElement):
"""
+--------+-----+-----+-----+-----+-----+-----+-----+-----+
| CPYRAM | EID | PID | G1 | G2 | G3 | G4 | G5 | |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+
"""
type = 'CPYRAM'
#asterType = 'CPYRAM5'
#calculixType = 'C3D5'
[docs] def write_card(self, size=8, is_double=False):
nodes = self.node_ids
data = [self.eid, self.Pid()] + nodes
msg = ('CPYRAM %8i%8i%8i%8i%8i%8i%8i' % tuple(data))
return self.comment() + msg.rstrip() + '\n'
def __init__(self, card=None, data=None, comment=''):
SolidElement.__init__(self, card, data)
if comment:
self._comment = comment
if card:
#: Element ID
self.eid = integer(card, 1, 'eid')
#: Property ID
self.pid = integer(card, 2, 'pid')
nids = [integer(card, 3, 'nid1'), integer(card, 4, 'nid2'),
integer(card, 5, 'nid3'), integer(card, 6, 'nid4'),
integer(card, 7, 'nid5')]
assert len(card) == 8, 'len(CPYRAM5 1card) = %i' % len(card)
else:
self.eid = data[0]
self.pid = data[1]
nids = [d if d > 0 else None for d in data[2:]]
self.prepare_node_ids(nids)
msg = 'len(nids)=%s nids=%s' % (len(nids), nids)
assert len(self.nodes) <= 20, msg
[docs] def cross_reference(self, model):
msg = ' which is required by %s eid=%s' % (self.type, self.eid)
self.nodes = model.Nodes(self.nodes, allowEmptyNodes=True, msg=msg)
self.pid = model.Property(self.pid, msg=msg)
[docs] def _verify(self, xref=False):
eid = self.Eid()
pid = self.Pid()
nids = self.node_ids
assert isinstance(eid, int)
assert isinstance(pid, int)
for i, nid in enumerate(nids):
assert nid is None or isinstance(nid, int), 'nid%i is not an integer/blank; nid=%s' %(i, nid)
if xref:
c = self.Centroid()
v = self.Volume()
assert isinstance(v, float)
for i in range(3):
assert isinstance(c[i], float)
[docs] def Centroid(self):
"""
.. seealso:: CPYRAM5.Centroid
"""
(n1, n2, n3, n4, n5) = self.nodePositions()
A1, c1 = area_centroid(n1, n2, n3, n4)
c = (c1 + n5) / 2.
return c
[docs] def Volume(self):
"""
.. seealso:: CPYRAM5.Volume
"""
(n1, n2, n3, n4, n5) = self.nodePositions()
A1, c1 = area_centroid(n1, n2, n3, n4)
V = A1 / 3. * norm(c1 - n5)
return abs(V)
[docs] def nodeIDs(self):
return self.node_ids
@property
def node_ids(self):
return self._nodeIDs(allowEmptyNodes=False)
@node_ids.setter
def node_ids(self, value):
raise ValueError("You cannot set node IDs like this...modify the node objects")
[docs]class CPYRAM13(SolidElement):
"""
+--------+-----+-----+-----+-----+-----+-----+-----+-----+
| CPYRAM | EID | PID | G1 | G2 | G3 | G4 | G5 | G6 |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+
| | G7 | G8 | G9 | G10 | G11 | G12 | | |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+
"""
type = 'CPYRAM'
#asterType = 'CPYRAM13'
#calculixType = 'C3D13'
[docs] def write_card(self, size=8, is_double=False):
nodes = self.node_ids
nodes2 = ['' if node is None else '%8i' % node for node in nodes[5:]]
data = [self.eid, self.Pid()] + nodes[:5] + nodes2
msg = ('CPYRAM %8i%8i%8i%8i%8i%8i%8i%8s\n'
' %8s%8s%8s%8s%8s%8s%s' % tuple(data))
return self.comment() + msg.rstrip() + '\n'
def __init__(self, card=None, data=None, comment=''):
SolidElement.__init__(self, card, data)
if comment:
self._comment = comment
if card:
#: Element ID
self.eid = integer(card, 1, 'eid')
#: Property ID
self.pid = integer(card, 2, 'pid')
nids = [integer(card, 3, 'nid1'), integer(card, 4, 'nid2'),
integer(card, 5, 'nid3'), integer(card, 6, 'nid4'),
integer(card, 7, 'nid5'),
integer_or_blank(card, 8, 'nid6'),
integer_or_blank(card, 9, 'nid7'),
integer_or_blank(card, 10, 'nid8'),
integer_or_blank(card, 11, 'nid9'),
integer_or_blank(card, 12, 'nid10'),
integer_or_blank(card, 13, 'nid11'),
integer_or_blank(card, 14, 'nid12'),
integer_or_blank(card, 15, 'nid13')]
assert len(card) <= 16, 'len(CPYRAM13 1card) = %i' % len(card)
else:
self.eid = data[0]
self.pid = data[1]
nids = [d if d > 0 else None for d in data[2:]]
self.prepare_node_ids(nids, allow_empty_nodes=True)
msg = 'len(nids)=%s nids=%s' % (len(nids), nids)
assert len(self.nodes) <= 13, msg
[docs] def cross_reference(self, model):
msg = ' which is required by %s eid=%s' % (self.type, self.eid)
self.nodes = model.Nodes(self.nodes, allowEmptyNodes=True, msg=msg)
self.pid = model.Property(self.pid, msg=msg)
[docs] def _verify(self, xref=False):
eid = self.Eid()
pid = self.Pid()
nids = self.node_ids
assert isinstance(eid, int)
assert isinstance(pid, int)
for i, nid in enumerate(nids):
assert nid is None or isinstance(nid, int), 'nid%i is not an integer/blank; nid=%s' %(i, nid)
if xref:
c = self.Centroid()
v = self.Volume()
assert isinstance(v, float)
for i in range(3):
assert isinstance(c[i], float)
[docs] def Centroid(self):
"""
.. seealso:: CPYRAM5.Centroid
"""
(n1, n2, n3, n4, n5,
n6, n7, n8, n9, n10,
n11, n12, n13) = self.nodePositions()
A1, c1 = area_centroid(n1, n2, n3, n4)
c = (c1 + n5) / 2.
return c
[docs] def Volume(self):
"""
.. seealso:: CPYRAM5.Volume
"""
(n1, n2, n3, n4, n5,
n6, n7, n8, n9, n10,
n11, n12, n13) = self.nodePositions()
A1, c1 = area_centroid(n1, n2, n3, n4)
V = A1 / 2. * norm(c1 - n5)
return abs(V)
[docs] def nodeIDs(self):
return self.node_ids
@property
def node_ids(self):
return self._nodeIDs(allowEmptyNodes=True)
@node_ids.setter
def node_ids(self, value):
raise ValueError("You cannot set node IDs like this...modify the node objects")
[docs]class CTETRA4(SolidElement):
"""
+--------+-----+-----+----+----+----+----+
| CTETRA | EID | PID | G1 | G2 | G3 | G4 |
+--------+-----+-----+----+----+----+----+
"""
type = 'CTETRA'
asterType = 'TETRA4'
calculixType = 'C3D4'
[docs] def write_card(self, size=8, is_double=False):
nodes = self.node_ids
data = [self.eid, self.Pid()] + nodes
msg = 'CTETRA %8i%8i%8i%8i%8i%8i\n' % tuple(data)
return self.comment() + msg
def __init__(self, card=None, data=None, comment=''):
SolidElement.__init__(self, card, data)
if comment:
self._comment = comment
if card:
#: Element ID
self.eid = integer(card, 1, 'eid')
#: Property ID
self.pid = integer(card, 2, 'pid')
nids = [integer(card, 3, 'nid1'),
integer(card, 4, 'nid2'),
integer(card, 5, 'nid3'),
integer(card, 6, 'nid4'), ]
assert len(card) == 7, 'len(CTETRA4 card) = %i' % len(card)
else:
self.eid = data[0]
self.pid = data[1]
nids = data[2:]
assert len(data) == 6, 'len(data)=%s data=%s' % (len(data), data)
self.prepare_node_ids(nids)
assert len(self.nodes) == 4
[docs] def cross_reference(self, model):
msg = ' which is required by %s eid=%s' % (self.type, self.eid)
self.nodes = model.Nodes(self.nodes, allowEmptyNodes=False, msg=msg)
self.pid = model.Property(self.pid, msg=msg)
[docs] def _verify(self, xref=False):
eid = self.Eid()
pid = self.Pid()
nids = self.node_ids
assert isinstance(eid, int)
assert isinstance(pid, int)
for i, nid in enumerate(nids):
assert isinstance(nid, int), 'nid%i is not an integer; nid=%s' %(i, nid)
if xref:
c = self.Centroid()
v = self.Volume()
assert isinstance(v, float)
for i in range(3):
assert isinstance(c[i], float)
[docs] def Volume(self):
(n1, n2, n3, n4) = self.nodePositions()
return volume4(n1, n2, n3, n4)
[docs] def Centroid(self):
(n1, n2, n3, n4) = self.nodePositions()
return (n1 + n2 + n3 + n4) / 4.
[docs] def getFaceNodes(self, nid_opposite, nid=None):
assert nid is None, nid
nids = self.node_ids[:4]
indx = nids.index(nid_opposite)
nids.pop(indx)
return nids
[docs] def getFaceAreaCentroidNormal(self, nid_opposite, nid=None):
n1, n2, n3 = self.getFaceNodes(nid_opposite)
faceNodeIDs = [n1, n2, n3]
p1 = self.nodes[n1].Position()
p2 = self.nodes[n2].Position()
p3 = self.nodes[n3].Position()
a = p1 - p2
b = p1 - p3
normal = cross(a, b)
n = norm(normal)
A = 0.5 * n
centroid = (p1 + p2 + p3) / 3.
return A, centroid, normal / n
[docs] def nodeIDs(self):
return self.node_ids
@property
def node_ids(self):
return self._nodeIDs(allowEmptyNodes=False)
@node_ids.setter
def node_ids(self, value):
raise ValueError("You cannot set node IDs like this...modify the node objects")
[docs]class CTETRA10(SolidElement):
"""
+--------+-----+-----+-----+-----+-----+----+-----+-----+
| CTETRA | EID | PID | G1 | G2 | G3 | G4 | G5 | G6 |
+--------+-----+-----+-----+-----+-----+----+-----+-----+
| | G7 | G8 | G9 | G10 | | | | |
+--------+-----+-----+-----+-----+-----+----+-----+-----+
+--------+-----+-----+-----+-----+-----+----+-----+-----+
| CTETRA | 1 | 1 | 239 | 229 | 516 | 99 | 335 | 103 |
+--------+-----+-----+-----+-----+-----+----+-----+-----+
| | 265 | 334 | 101 | 102 | | | | |
+--------+-----+-----+-----+-----+-----+----+-----+-----+
"""
type = 'CTETRA'
asterType = 'TETRA10'
calculixType = 'C3D10'
[docs] def write_card(self, size=8, is_double=False):
nodes = self.node_ids
nodes2 = ['' if node is None else '%8i' % node for node in nodes[4:]]
data = [self.eid, self.Pid()] + nodes[:4] + nodes2
msg = ('CTETRA %8i%8i%8i%8i%8i%8i%8s%8s\n'
' %8s%8s%8s%8s' % tuple(data))
return self.comment() + msg.rstrip() + '\n'
def __init__(self, card=None, data=None, comment=''):
SolidElement.__init__(self, card, data)
if comment:
self._comment = comment
if card:
#: Element ID
self.eid = integer(card, 1, 'eid')
#: Property ID
self.pid = integer(card, 2, 'pid')
nids = [integer(card, 3, 'nid1'),
integer(card, 4, 'nid2'),
integer(card, 5, 'nid3'),
integer(card, 6, 'nid4'),
integer_or_blank(card, 7, 'nid5'),
integer_or_blank(card, 8, 'nid6'),
integer_or_blank(card, 9, 'nid7'),
integer_or_blank(card, 10, 'nid8'),
integer_or_blank(card, 11, 'nid9'),
integer_or_blank(card, 12, 'nid10'), ]
assert len(card) <= 13, 'len(CTETRA10 card) = %i' % len(card)
else:
self.eid = data[0]
self.pid = data[1]
nids = [d if d > 0 else None for d in data[2:]]
assert len(data) == 12, 'len(data)=%s data=%s' % (len(data), data)
self.prepare_node_ids(nids, allow_empty_nodes=True)
assert len(self.nodes) <= 10
[docs] def cross_reference(self, model):
msg = ' which is required by %s eid=%s' % (self.type, self.eid)
self.nodes = model.Nodes(self.nodes, allowEmptyNodes=True, msg=msg)
self.pid = model.Property(self.pid, msg=msg)
[docs] def _verify(self, xref=False):
eid = self.Eid()
pid = self.Pid()
nids = self.node_ids
assert isinstance(eid, int)
assert isinstance(pid, int)
for i, nid in enumerate(nids):
assert nid is None or isinstance(nid, int), 'nid%i is not an integer/blank; nid=%s' %(i, nid)
if xref:
c = self.Centroid()
v = self.Volume()
assert isinstance(v, float)
for i in range(3):
assert isinstance(c[i], float)
[docs] def N_10(self, g1, g2, g3, g4):
N1 = g1 * (2 * g1 - 1)
N2 = g2 * (2 * g2 - 1)
N3 = g3 * (2 * g3 - 1)
N4 = g4 * (2 * g4 - 1)
N5 = 4 * g1 * g2
N6 = 4 * g2 * g3
N7 = 4 * g3 * g1
N8 = 4 * g1 * g4
N9 = 4 * g2 * g4
N10 = 4 * g3 * g4
return (N1, N2, N3, N4, N5, N6, N7, N8, N9, N10)
[docs] def Volume(self):
"""
Gets the volume, :math:`V`, of the primary tetrahedron.
.. seealso:: CTETRA4.Volume
"""
(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10) = self.nodePositions()
return volume4(n1, n2, n3, n4)
[docs] def Centroid(self):
"""
Gets the cenroid of the primary tetrahedron.
.. seealso:: CTETRA4.Centroid
"""
(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10) = self.nodePositions()
return (n1 + n2 + n3 + n4) / 4.
[docs] def getFaceNodes(self, nidOpposite, nid=None):
nids = self.node_ids[:4]
indx = nids.index(nidOpposite)
nids.pop(indx)
return nids
[docs] def nodeIDs(self):
return self.node_ids
@property
def node_ids(self):
return self._nodeIDs(allowEmptyNodes=True)
@node_ids.setter
def node_ids(self, value):
raise ValueError("You cannot set node IDs like this...modify the node objects")