Source code for pyNastran.bdf.cards.elements.shell

# pylint: disable=C0103,R0902,R0904,R0914,C0302
"""
All shell elements are defined in this file.  This includes:

 * CTRIA3
 * CTRIA6
 * CTRIAX
 * CTRIAX6
 * CSHEAR
 * CQUAD
 * CQUAD4
 * CQUAD8
 * CQUADR
 * CQUADX

All tris are TriShell, ShellElement, and Element objects.
All quads are QuadShell, ShellElement, and Element objects.
"""
from __future__ import (nested_scopes, generators, division, absolute_import,
                        print_function, unicode_literals)
from six.moves import range

from numpy import array, eye, cross, allclose
from numpy.linalg import det, norm  # inv

from pyNastran.bdf.deprecated import ShellElementDeprecated
from pyNastran.bdf.field_writer_8 import set_blank_if_default, set_default_if_blank
from pyNastran.bdf.cards.baseCard import Element
from pyNastran.utils.mathematics import Area, norm, centroid_triangle
from pyNastran.bdf.bdfInterface.assign_type import (integer, integer_or_blank,
    double_or_blank, integer_double_or_blank, blank)
from pyNastran.bdf.field_writer_8 import print_card_8, print_field_8
from pyNastran.bdf.field_writer_16 import print_card_16
from pyNastran.bdf.cards.utils import wipe_empty_fields

[docs]def _triangle_area_centroid_normal(nodes): """ Returns area,centroid,unitNormal :param nodes: list of three triangle vertices :: n = Normal = a x b Area = 1/2 * |a x b| V = <v1,v2,v3> |V| = sqrt(v1^0.5+v2^0.5+v3^0.5) = norm(V) Area = 0.5 * |n| unitNormal = n/|n| """ (n0, n1, n2) = nodes vector = cross(n0 - n1, n0 - n2) length = norm(vector) normal = vector / length if not allclose(norm(normal), 1.): msg = ('function _triangle_area_centroid_normal, check...\n' 'a = {0}\nb = {1}\nnormal = {2}\nlength = {3}\n'.format( n0 - n1, n0 - n2, normal, length)) raise RuntimeError(msg) return (0.5 * length, (n0 + n1 + n2) / 3., normal)
[docs]def _normal(a, b): """Finds the unit normal vector of 2 vectors""" vector = cross(a, b) normal = vector / norm(vector) assert allclose(norm(normal), 1.) return normal
[docs]class ShellElement(Element, ShellElementDeprecated): type = 'ShellElement' def __init__(self, card, data): Element.__init__(self, card, data)
[docs] def Eid(self): return self.eid
[docs] def Area(self): raise NotImplementedError('Area undefined for %s' % self.type)
[docs] def Thickness(self): """ Returns the thickness """ return self.pid.Thickness()
[docs] def mid(self): """ Returns the material .. todo:: possibly remove this """ return self.pid.mid()
[docs] def Mid(self): """ Returns the material ID .. todo:: possibly remove this """ return self.pid.Mid()
[docs] def Nsm(self): """ Returns the non-structural mass """ return self.pid.Nsm()
[docs] def MassPerArea(self): """ Returns the mass per area """ return self.pid.MassPerArea()
[docs] def Mass(self): r""" .. math:: m = \frac{m}{A} A \f] """ A = self.Area() mpa = self.pid.MassPerArea() try: return mpa * A except TypeError: msg = 'mass/area=%s area=%s pidType=%s' % (mpa, A, self.pid.type) raise TypeError(msg)
[docs] def flipNormal(self): raise NotImplementedError('flipNormal undefined for %s' % self.type)
[docs]class TriShell(ShellElement): def __init__(self, card, data): ShellElement.__init__(self, card, data)
[docs] def get_edges(self): """ Returns the edges """ return [(self.nodes[0], self.nodes[1]), (self.nodes[1], self.nodes[2]), (self.nodes[2], self.nodes[0])]
[docs] def Thickness(self): """ Returns the thickness """ return self.pid.Thickness()
[docs] def AreaCentroidNormal(self): """ Returns area,centroid, normal as it's more efficient to do them together Returns ------- area : float the area centroid : (3,) array the centroid normal : (3,) array the normal vector """ (n0, n1, n2) = self.nodePositions() return _triangle_area_centroid_normal([n0, n1, n2])
[docs] def Area(self): r""" Get the area, :math:`A`. .. math:: A = \frac{1}{2} \lvert (n_0-n_1) \times (n_0-n_2) \rvert""" (n0, n1, n2) = self.nodePositions() a = n0 - n1 b = n0 - n2 area = Area(a, b) return area
[docs] def Normal(self): r""" Get the normal vector, :math:`n`. .. math:: n = \frac{(n_0-n_1) \times (n_0-n_2)} {\lvert (n_0-n_1) \times (n_0-n_2) \lvert} """ (n1, n2, n3) = self.nodePositions() try: n = _normal(n1 - n2, n1 - n3) except: msg = 'ERROR computing normal vector for eid=%i.\n' % self.eid msg += ' nid1=%i n1=%s\n' % (self.nodes[0].nid, n1) msg += ' nid2=%i n2=%s\n' % (self.nodes[1].nid, n2) msg += ' nid3=%i n3=%s\n' % (self.nodes[2].nid, n3) raise RuntimeError(msg) return n
[docs] def Centroid(self): r""" Get the centroid. .. math:: CG = \frac{1}{3} (n_0+n_1+n_2) """ (n0, n1, n2) = self.nodePositions() centroid = centroid_triangle(n0, n1, n2) return centroid
[docs] def MassMatrix(self, isLumped=True): """ 6x6 mass matrix triangle http://www.colorado.edu/engineering/cas/courses.d/IFEM.d/IFEM.Ch32.d/IFEM.Ch32.pdf """ mass = self.Mass() # rho*A*t if isLumped: # lumped mass matrix Mass = mass / 3 * eye(6) else: # consistent mass M = eye(6) * 2. M[2, 0] = M[4, 0] = M[0, 2] = M[0, 4] = 1. M[3, 1] = M[5, 1] = M[1, 3] = M[1, 5] = 1. M[4, 2] = M[2, 4] = 1. M[5, 3] = M[5, 3] = 1. Mass = mass / 12 * M return Mass
[docs]class CTRIA3(TriShell): type = 'CTRIA3' asterType = 'TRIA3' calculixType = 'S3' _field_map = {1: 'eid', 2:'pid', 6:'thetaMcid', 7:'zOffset', 10:'TFlag', 11:'T1', 12:'T2', 13:'T3'}
[docs] def _update_field_helper(self, n, value): if n == 3: self.nodes[0] = value elif n == 4: self.nodes[1] = value elif n == 5: self.nodes[2] = value else: raise KeyError('Field %r=%r is an invalid %s entry.' % (n, value, self.type))
def __init__(self, card=None, data=None, comment=''): TriShell.__init__(self, card, data) if comment: self._comment = comment if card: #: Element ID self.eid = integer(card, 1, 'eid') #: Property ID self.pid = integer_or_blank(card, 2, 'pid', self.eid) nids = [integer(card, 3, 'n1'), integer(card, 4, 'n2'), integer(card, 5, 'n3')] self.thetaMcid = integer_double_or_blank(card, 6, 'thetaMcid', 0.0) self.zOffset = double_or_blank(card, 7, 'zOffset', 0.0) blank(card, 8, 'blank') blank(card, 9, 'blank') self.TFlag = integer_or_blank(card, 10, 'TFlag', 0) self.T1 = double_or_blank(card, 11, 'T1', 1.0) self.T2 = double_or_blank(card, 12, 'T2', 1.0) self.T3 = double_or_blank(card, 13, 'T3', 1.0) assert len(card) <= 14, 'len(CTRIA3 card) = %i' % len(card) else: self.eid = data[0] self.pid = data[1] nids = data[2:5] self.thetaMcid = data[5] self.zOffset = data[6] self.TFlag = data[7] self.T1 = data[8] self.T2 = data[9] self.T3 = data[10] if self.T1 == -1.0: self.T1 = 1.0 if self.T2 == -1.0: self.T2 = 1.0 if self.T3 == -1.0: self.T3 = 1.0 self.prepare_node_ids(nids) assert len(self.nodes) == 3
[docs] def cross_reference(self, model): msg = ' which is required by CTRIA3 eid=%s' % self.eid self.nodes = model.Nodes(self.nodes, msg=msg) self.pid = model.Property(self.pid, msg=msg)
[docs] def _verify(self, xref=True): 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: assert self.pid.type in ['PSHELL', 'PCOMP', 'PCOMPG', 'PLPLANE'], 'pid=%i self.pid.type=%s' % (pid, self.pid.type) if not self.pid.type in ['PLPLANE']: t = self.Thickness() assert isinstance(t, float), 'thickness=%r' % t mass = self.Mass() assert isinstance(mass, float), 'mass=%r' % mass a, c, n = self.AreaCentroidNormal() assert isinstance(a, float), 'Area=%r' % a for i in range(3): assert isinstance(c[i], float) assert isinstance(n[i], float)
#def Thickness(self): #if self.T1 + self.T2 + self.T3 > 0.0: # if self.TFlag == 0: # t = self.pid.Thickness() # T1 = self.T1 / t # T2 = self.T2 / t # T3 = self.T3 / t # else: # T1 = self.T1 # T2 = self.T2 # T3 = self.T3 # t = (T1+T2+T3)/3. #else: # t = self.pid.Thickness() #return t
[docs] def flipNormal(self): """ :: 1 1 * * --> * * * * * * 2-----3 3-----2 """ (n1, n2, n3) = self.nodes self.nodes = [n1, n3, n2]
[docs] def Interp(self, un): """ Interpolation based on the area coordinates """ (n0, n1, n2) = self.nodePositions() nc = (n0 + n1 + n2) / 3. a = n0 - nc b = n1 - nc c = n2 - nc tA1 = det(cross(b, c)) # 2*A1 tA2 = det(cross(c, a)) # 2*A2 tA3 = det(cross(a, b)) # 2*A3 otA = 1. / (tA1 + tA2 + tA3) # 1/2A S = array([tA1, tA2, tA3]) * otA # Ai/A u = S * un return u
[docs] def Jacob(self): (n0, n1, n2) = self.nodePositions() (nx0, ny0, nz0) = n0 (nx1, ny1, nz1) = n1 (nx2, ny2, nz2) = n2 #J = matrix([n0,n1-n0,n2-n0]) J = array([[nx0, nx1 - nx0, nx2 - nx0], [ny0, ny1 - ny0, ny2 - ny0], [nz0, nz1 - nz0, nz2 - nz0], ]) #detJ = J.det() return J
[docs] def getReprDefaults(self): zOffset = set_blank_if_default(self.zOffset, 0.0) TFlag = set_blank_if_default(self.TFlag, 0) thetaMcid = set_blank_if_default(self.thetaMcid, 0.0) T1 = set_blank_if_default(self.T1, 1.0) T2 = set_blank_if_default(self.T2, 1.0) T3 = set_blank_if_default(self.T3, 1.0) return (thetaMcid, zOffset, TFlag, T1, T2, T3)
[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] def raw_fields(self): list_fields = (['CTRIA3', self.eid, self.Pid()] + self.node_ids + [self.thetaMcid, self.zOffset, None] + [None, self.TFlag, self.T1, self.T2, self.T3]) return list_fields
[docs] def repr_fields(self): (thetaMcid, zOffset, TFlag, T1, T2, T3) = self.getReprDefaults() list_fields = (['CTRIA3', self.eid, self.Pid()] + self.node_ids + [thetaMcid, zOffset, None] + [None, TFlag, T1, T2, T3]) return list_fields
[docs] def write_card(self, size=8, is_double=False): zOffset = set_blank_if_default(self.zOffset, 0.0) TFlag = set_blank_if_default(self.TFlag, 0) thetaMcid = set_blank_if_default(self.thetaMcid, 0.0) T1 = set_blank_if_default(self.T1, 1.0) T2 = set_blank_if_default(self.T2, 1.0) T3 = set_blank_if_default(self.T3, 1.0) #return self.write_card(size, double) nodes = self.node_ids row2_data = [thetaMcid, zOffset, TFlag, T1, T2, T3] row2 = [print_field_8(field) for field in row2_data] data = [self.eid, self.Pid()] + nodes + row2 msg = ('CTRIA3 %8i%8i%8i%8i%8i%8s%8s\n' ' %8s%8s%8s%8s\n' % tuple(data)) return self.comment() + msg.rstrip() + '\n'
#def write_card(self, size=8, is_double=False): #card = wipe_empty_fields(self.repr_fields()) #if size == 8 or len(card) == 6: # to last node #msg = self.comment() + print_card_8(card) #else: #msg = self.comment() + print_card_16(card) #msg2 = self.write_card(size) #assert msg == msg2, '\n%s---\n%s\n%r\n%r' % (msg, msg2, msg, msg2) #return msg
[docs]class CTRIA6(TriShell): type = 'CTRIA6' asterType = 'TRIA6' calculixType = 'S6' def __init__(self, card=None, data=None, comment=''): TriShell.__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, 'n1'), integer(card, 4, 'n2'), integer(card, 5, 'n3'), integer_or_blank(card, 6, 'n4', 0), integer_or_blank(card, 7, 'n5', 0), integer_or_blank(card, 8, 'n6', 0)] self.thetaMcid = integer_double_or_blank(card, 9, 'thetaMcid', 0.0) self.zOffset = double_or_blank(card, 10, 'zOffset', 0.0) self.T1 = double_or_blank(card, 11, 'T1', 1.0) self.T2 = double_or_blank(card, 12, 'T2', 1.0) self.T3 = double_or_blank(card, 13, 'T3', 1.0) self.TFlag = integer_or_blank(card, 14, 'TFlag', 0) assert len(card) <= 15, 'len(CTRIA6 card) = %i' % len(card) else: self.eid = data[0] self.pid = data[1] nids = data[2:8] self.thetaMcid = data[8] self.zOffset = data[8] self.T1 = data[9] self.T2 = data[10] self.T3 = data[11] self.TFlag = data[12] self.prepare_node_ids(nids, allow_empty_nodes=True) assert len(nids) == 6, 'error on CTRIA6' #print self.thetaMcid #print card #print "self.xi = ",self.xi #raise
[docs] def cross_reference(self, model): msg = ' which is required by CTRIA6 eid=%s' % 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 isinstance(nid, int), 'nid%i is not an integer; nid=%s' %(i, nid) if xref: assert self.pid.type in ['PSHELL', 'PCOMP', 'PCOMPG', 'PLPLANE'], 'pid=%i self.pid.type=%s' % (pid, self.pid.type) if not self.pid.type in ['PLPLANE']: t = self.Thickness() assert isinstance(t, float), 'thickness=%r' % t mass = self.Mass() assert isinstance(mass, float), 'mass=%r' % mass a, c, n = self.AreaCentroidNormal() assert isinstance(a, float), 'Area=%r' % a for i in range(3): assert isinstance(c[i], float) assert isinstance(n[i], float)
[docs] def Thickness(self): """ Returns the thickness, :math:`t` """ return self.pid.Thickness()
[docs] def AreaCentroidNormal(self): """ Returns area, centroid, normal as it's more efficient to do them together """ (n1, n2, n3, n4, n5, n6) = self.nodePositions() return _triangle_area_centroid_normal([n1, n2, n3])
[docs] def Area(self): r""" Get the area, :math:`A`. .. math:: A = \frac{1}{2} (n_0-n_1) \times (n_0-n_2)""" (n1, n2, n3, n4, n5, n6) = self.nodePositions() a = n1 - n2 b = n1 - n3 area = Area(a, b) return area
[docs] def Normal(self): r""" Get the normal vector, :math:`n`. .. math:: n = \frac{(n_0-n_1) \times (n_0-n_2)}{\lvert (n_0-n_1) \times (n_0-n_2) \lvert} """ (n0, n1, n2) = self.nodePositions()[:3] return _normal(n0 - n1, n0 - n2)
[docs] def Centroid(self): r""" Get the centroid. .. math:: CG = \frac{1}{3} (n_1+n_2+n_3) """ (n1, n2, n3, n4, n5, n6) = self.nodePositions() centroid = centroid_triangle(n1, n2, n3) return centroid
[docs] def flipNormal(self): r""" :: 1 1 ** ** * * * * 4 6 --> 6 4 * * * * 2----5---3 3----5---2 """ (n1, n2, n3, n4, n5, n6) = self.nodes self.nodes = [n1, n3, n2, n6, n5, n4]
[docs] def getReprDefaults(self): zOffset = set_blank_if_default(self.zOffset, 0.0) TFlag = set_blank_if_default(self.TFlag, 0) thetaMcid = set_blank_if_default(self.thetaMcid, 0.0) T1 = set_blank_if_default(self.T1, 1.0) T2 = set_blank_if_default(self.T2, 1.0) T3 = set_blank_if_default(self.T3, 1.0) return (thetaMcid, zOffset, TFlag, T1, T2, T3)
[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] def raw_fields(self): list_fields = (['CTRIA6', self.eid, self.Pid()] + self.node_ids + [self.thetaMcid, self.zOffset, None] + [None, self.TFlag, self.T1, self.T2, self.T3]) return list_fields
[docs] def repr_fields(self): (thetaMcid, zOffset, TFlag, T1, T2, T3) = self.getReprDefaults() list_fields = (['CTRIA6', self.eid, self.Pid()] + self.node_ids + [thetaMcid, zOffset, None] + [None, TFlag, T1, T2, T3]) return list_fields
[docs] def write_card(self, size=8, is_double=False): card = wipe_empty_fields(self.repr_fields()) if size == 8 or len(card) == 8: # to last node msg = self.comment() + print_card_8(card) else: msg = self.comment() + print_card_16(card) #msg2 = self.write_card(size) #assert msg == msg2, '\n%s---\n%s\n%r\n%r' % (msg, msg2, msg, msg2) return msg
[docs]class CTRIAR(TriShell): type = 'CTRIAR' def __init__(self, card=None, data=None, comment=''): TriShell.__init__(self, card, data) if comment: self._comment = comment #: Element ID self.eid = integer(card, 1, 'eid') #: Property ID self.pid = integer(card, 2, 'pid') nids = [integer(card, 3, 'n1'), integer(card, 4, 'n2'), integer(card, 5, 'n3')] self.prepare_node_ids(nids) assert len(self.nodes) == 3 self.thetaMcid = integer_double_or_blank(card, 6, 'thetaMcid', 0.0) self.zOffset = double_or_blank(card, 7, 'zOffset', 0.0) blank(card, 8, 'blank') blank(card, 9, 'blank') blank(card, 10, 'blank') self.TFlag = integer_or_blank(card, 10, 'TFlag', 0) self.T1 = double_or_blank(card, 11, 'T1', 1.0) self.T2 = double_or_blank(card, 12, 'T2', 1.0) self.T3 = double_or_blank(card, 13, 'T3', 1.0) assert len(card) <= 14, 'len(CTRIAR card) = %i' % len(card)
[docs] def cross_reference(self, model): msg = ' which is required by CTRIAR eid=%s' % self.eid self.nodes = model.Nodes(self.nodes, msg=msg) self.pid = model.Property(self.pid, msg=msg)
#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: #assert self.pid.type in ['PSHELL', 'PCOMP'], 'pid=%i self.pid.type=%s' % (pid, self.pid.type) #t = self.Thickness() #a,c,n = self.AreaCentroidNormal() #for i in range(3): #assert isinstance(c[i], float) #assert isinstance(n[i], float)
[docs] def Thickness(self): """ Returns the thickness """ return self.pid.Thickness()
[docs] def flipNormal(self): r""" :: 1 1 * * --> * * * * * * 2-----3 3-----2 """ (n1, n2, n3) = self.nodes self.nodes = [n1, n3, n2]
[docs] def getReprDefaults(self): zOffset = set_blank_if_default(self.zOffset, 0.0) TFlag = set_blank_if_default(self.TFlag, 0) thetaMcid = set_blank_if_default(self.thetaMcid, 0.0) T1 = set_blank_if_default(self.T1, 1.0) T2 = set_blank_if_default(self.T2, 1.0) T3 = set_blank_if_default(self.T3, 1.0) return (thetaMcid, zOffset, TFlag, T1, T2, T3)
[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: # PSHELL/PCOMP assert self.pid.type in ['PSHELL', 'PCOMP', 'PCOMPG'], 'pid=%i self.pid.type=%s' % (pid, self.pid.type) t = self.Thickness() a, c, n = self.AreaCentroidNormal() assert isinstance(t, float), 'thickness=%r' % t assert isinstance(a, float), 'Area=%r' % a for i in range(3): assert isinstance(c[i], float) #assert isinstance(n[i], float) mass = self.Mass() assert isinstance(mass, float), 'mass=%r' % mass
[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] def raw_fields(self): list_fields = (['CTRIAR', self.eid, self.Pid()] + self.node_ids + [self.thetaMcid, self.zOffset, self.TFlag, self.T1, self.T2, self.T3]) return list_fields
[docs] def repr_fields(self): (thetaMcid, zOffset, TFlag, T1, T2, T3) = self.getReprDefaults() list_fields = (['CTRIAR', self.eid, self.Pid()] + self.node_ids + [thetaMcid, zOffset, None, None, TFlag, T1, T2, T3]) return list_fields
[docs] def write_card(self, size=8, is_double=False): card = wipe_empty_fields(self.repr_fields()) if size == 8 or len(card) == 5: # to last node msg = self.comment() + print_card_8(card) else: msg = self.comment() + print_card_16(card) return msg
[docs]class CTRIAX(TriShell): type = 'CTRIAX' calculixType = 'CAX6' def __init__(self, card=None, data=None, comment=''): TriShell.__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_or_blank(card, 3, 'n1'), integer_or_blank(card, 4, 'n2'), integer_or_blank(card, 5, 'n3'), integer_or_blank(card, 6, 'n4'), integer_or_blank(card, 7, 'n5'), integer_or_blank(card, 8, 'n6')] self.thetaMcid = integer_double_or_blank(card, 9, 'theta_mcsid', 0.0) assert len(card) <= 10, 'len(CTRIAX card) = %i' % len(card) else: raise NotImplementedError(data) self.prepare_node_ids(nids, allow_empty_nodes=True) assert len(nids) == 6, 'error on CTRIAX'
[docs] def _verify(self, xref=True): eid = self.Eid() pid = self.Pid() nids = self.node_ids assert isinstance(eid, int) assert isinstance(pid, int) for i, nid in enumerate(nids): if i < 3: assert isinstance(nid, int), 'nid%i is not an integer; nid=%s' %(i, nid) else: assert isinstance(nid, int) or nid is None, 'nid%i is not an integer or None nid=%s' %(i, nid) if xref: assert self.pid.type in ['PLPLANE'], 'pid=%i self.pid.type=%s' % (pid, self.pid.type) if not self.pid.type in ['PLPLANE']: t = self.Thickness() assert isinstance(t, float), 'thickness=%r' % t mass = self.Mass() assert isinstance(mass, float), 'mass=%r' % mass a, c, n = self.AreaCentroidNormal() assert isinstance(a, float), 'Area=%r' % a for i in range(3): assert isinstance(c[i], float) assert isinstance(n[i], float)
[docs] def AreaCentroidNormal(self): """ Returns area, centroid, normal as it's more efficient to do them together """ (n1, n2, n3, n4, n5, n6) = self.nodePositions() return _triangle_area_centroid_normal([n1, n2, n3])
[docs] def Area(self): r""" Get the area, :math:`A`. .. math:: A = \frac{1}{2} \lvert (n_1-n_2) \times (n_1-n_3) \rvert""" (n1, n2, n3, n4, n5, n6) = self.nodePositions() a = n1 - n2 b = n1 - n3 area = Area(a, b) return area
[docs] def cross_reference(self, model): msg = ' which is required by CTRIAX eid=%s' % self.eid self.nodes = model.Nodes(self.nodes, allowEmptyNodes=True, msg=msg) self.pid = model.Property(self.pid, msg=msg)
[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] def raw_fields(self): nodeIDs = self.node_ids list_fields = ['CTRIAX', self.eid, self.Pid()] + nodeIDs + [self.thetaMcid] return list_fields
[docs] def repr_fields(self): thetaMcid = set_blank_if_default(self.thetaMcid, 0.0) nodeIDs = self.node_ids list_fields = ['CTRIAX', self.eid, self.Pid()] + nodeIDs + [thetaMcid] return list_fields
[docs] def write_card(self, size=8, is_double=False): card = wipe_empty_fields(self.repr_fields()) if size == 8 or len(card) == 8: # to last node msg = self.comment() + print_card_8(card) else: msg = self.comment() + print_card_16(card) #msg2 = self.write_card(size) #assert msg == msg2, '\n%s---\n%s\n%r\n%r' % (msg, msg2, msg, msg2) return msg
[docs]class CTRIAX6(TriShell): r""" Nodes defined in a non-standard way:: 5 / \ 6 4 / \ 1----2----3 """ type = 'CTRIAX6' #calculixType = 'CAX6' def __init__(self, card=None, data=None, comment=''): TriShell.__init__(self, card, data) if comment: self._comment = comment if card: #: Element ID self.eid = integer(card, 1, 'eid') #: Material ID self.mid = integer(card, 2, 'mid') nids = [integer(card, 3, 'n1'), integer_or_blank(card, 4, 'n2'), integer(card, 5, 'n3'), integer_or_blank(card, 6, 'n4'), integer(card, 7, 'n5'), integer_or_blank(card, 8, 'n6')] #: theta self.theta = double_or_blank(card, 9, 'theta', 0.0) assert len(card) <= 10, 'len(CTRIAX6 card) = %i' % len(card) else: raise NotImplementedError(data) self.prepare_node_ids(nids, allow_empty_nodes=True) assert len(nids) == 6, 'error on CTRIAX6'
[docs] def cross_reference(self, model): msg = ' which is required by CTRIAX6 eid=%s' % self.eid self.nodes = model.Nodes(self.nodes, allowEmptyNodes=True, msg=msg) self.mid = model.Material(self.mid)
[docs] def _verify(self, xref=True): eid = self.Eid() #pid = self.Pid() nids = self.node_ids assert self.pid == 0, 'pid = %s' % self.pid 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 or blank; nid=%s' %(i, nid) if xref: assert self.mid.type in ['MAT1'], 'self.mid=%s self.mid.type=%s' % (self.mid, self.mid.type) #assert self.pid.type in ['PSHELL', 'PCOMP', 'PCOMPG', 'PLPLANE'], 'pid=%i self.pid.type=%s' % (pid, self.pid.type) #if not self.pid.type in ['PLPLANE']: #t = self.Thickness() #assert isinstance(t, float), 'thickness=%r' % t #mass = self.Mass() #assert isinstance(mass, float), 'mass=%r' % mass a, c, n = self.AreaCentroidNormal() assert isinstance(a, float), 'Area=%r' % a for i in range(3): assert isinstance(c[i], float) assert isinstance(n[i], float)
[docs] def Pid(self): raise AttributeError("CTRIAX6 doesn't have a Property")
[docs] def AreaCentroidNormal(self): """ Returns area, centroid, normal as it's more efficient to do them together """ (n0, n1, n2, n3, n4, n5) = self.nodePositions() return _triangle_area_centroid_normal([n0, n2, n4])
[docs] def Area(self): r""" Get the normal vector. .. math:: A = \frac{1}{2} \lvert (n_1-n_3) \times (n_1-n_5) \rvert""" (n1, n2, n3, n4, n5, n6) = self.nodePositions() a = n1 - n3 b = n1 - n5 area = Area(a, b) return area
[docs] def Thickness(self): """ CTRIAX doesn't have a thickness because ??? """ raise AttributeError('CTRIAX6 does not have a thickness')
[docs] def Nsm(self): raise AttributeError('CTRIAX6 does not have a non-structural mass')
[docs] def MassPerArea(self): raise AttributeError('CTRIAX6 does not have a MassPerArea')
[docs] def Mass(self): raise NotImplementedError('CTRIAX6 does not have a Mass method yet')
[docs] def Mid(self): if isinstance(self.mid, int): return self.mid return self.mid.mid
[docs] def flipNormal(self): r""" :: 5 5 / \ / \ 6 4 --> 6 4 / \ / \ 1----2----3 1----2----3 """ (n1, n2, n3, n4, n5, n6) = self.nodes self.nodes = [n1, n6, n5, n4, n3, n2]
[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] def raw_fields(self): list_fields = (['CTRIAX6', self.eid, self.Mid(), self.Pid()] + self.node_ids + [self.theta]) return list_fields
[docs] def repr_fields(self): theta = set_default_if_blank(self.theta, 0.0) list_fields = ['CTRIAX6', self.eid, self.Mid()] + self.node_ids + [theta] return list_fields
[docs] def write_card(self, size=8, is_double=False): card = wipe_empty_fields(self.repr_fields()) if size == 8 or len(card) == 8: # to last node msg = self.comment() + print_card_8(card) else: msg = self.comment() + print_card_16(card) #msg2 = self.write_card(size) #assert msg == msg2, '\n%s---\n%s\n%r\n%r' % (msg, msg2, msg, msg2) return msg
[docs]class QuadShell(ShellElement): def __init__(self, card, data): ShellElement.__init__(self, card, data)
[docs] def get_edges(self): """ Returns the edges """ return [ (self.nodes[0], self.nodes[1]), (self.nodes[1], self.nodes[2]), (self.nodes[2], self.nodes[3]), (self.nodes[3], self.nodes[0]), ]
[docs] def Thickness(self): """ Returns the thickness """ return self.pid.Thickness()
[docs] def Normal(self): (n1, n2, n3, n4) = self.nodePositions() try: n = _normal(n1 - n3, n2 - n4) except: msg = 'ERROR computing normal vector for eid=%i.\n' % self.eid msg += ' nid1=%i n1=%s\n' % (self.nodes[0].nid, n1) msg += ' nid2=%i n2=%s\n' % (self.nodes[1].nid, n2) msg += ' nid3=%i n3=%s\n' % (self.nodes[2].nid, n3) msg += ' nid4=%i n4=%s\n' % (self.nodes[3].nid, n4) raise RuntimeError(msg) return n
[docs] def AreaCentroidNormal(self): (area, centroid) = self.AreaCentroid() normal = self.Normal() return (area, centroid, normal)
[docs] def AreaCentroid(self): r""" :: 1-----2 | /| | A1/ | | / | |/ A2 | 4-----3 .. math: c = \frac{\sum(c_i A_i){\sum{A_i}} c = sum(ci*Ai)/sum(A) where: c=centroid A=area """ (n1, n2, n3, n4) = self.nodePositions() area = 0.5 * norm(cross(n3-n1, n4-n2)) centroid = (n1 + n2 + n3 + n4) / 4. return(area, centroid)
[docs] def Centroid(self): (n1, n2, n3, n4) = self.nodePositions() centroid = (n1 + n2 + n3 + n4) / 4. return centroid
[docs] def Area(self): """ .. math:: A = \frac{1}{2} \lvert (n_1-n_3) \times (n_2-n_4) \rvert where a and b are the quad's cross node point vectors""" (n1, n2, n3, n4) = self.nodePositions() area = 0.5 * norm(cross(n3-n1, n4-n2)) return area
[docs] def MassMatrix(self, isLumped=True, gauss=1): """ 6x6 mass matrix triangle http://www.colorado.edu/engineering/cas/courses.d/IFEM.d/IFEM.Ch32.d/IFEM.Ch32.pdf """ mass = self.Mass() # rho*A*t if isLumped: # lumped mass matrix Mass = mass / 3 * eye(6) else: # consistent mass if gauss == 1: M = eye(8) * 1. # 1x1 Gauss Rule M[2, 0] = M[3, 1] = M[4, 2] = M[5, 3] = M[6, 4] = M[7, 5] = 1. M[4, 0] = M[5, 1] = M[6, 2] = M[7, 3] = 1. M[6, 0] = M[7, 1] = 1. M[0, 2] = M[1, 3] = M[2, 4] = M[3, 5] = M[4, 6] = M[5, 7] = 1. M[0, 4] = M[1, 5] = M[2, 6] = M[3, 7] = 1. M[0, 6] = M[1, 7] = 1. Mass = mass / 32 * M if gauss == 2: M = eye(8) * 4. # 2x2 Gauss Rule M[2, 0] = M[3, 1] = M[4, 2] = M[5, 3] = M[6, 4] = M[7, 5] = 2. M[4, 0] = M[5, 1] = M[6, 2] = M[7, 3] = 1. M[6, 0] = M[7, 1] = 2. M[0, 2] = M[1, 3] = M[2, 4] = M[3, 5] = M[4, 6] = M[5, 7] = 2. M[0, 4] = M[1, 5] = M[2, 6] = M[3, 7] = 1. M[0, 6] = M[1, 7] = 2. Mass = mass / 72 * M return Mass
[docs] def flipNormal(self): r""" :: 1---2 1---4 | | --> | | | | | | 4---3 2---3 """ (n1, n2, n3, n4) = self.nodes self.nodes = [n1, n4, n3, n2]
[docs] def getReprDefaults(self): zOffset = set_blank_if_default(self.zOffset, 0.0) TFlag = set_blank_if_default(self.TFlag, 0) thetaMcid = set_blank_if_default(self.thetaMcid, 0.0) T1 = set_blank_if_default(self.T1, 1.0) T2 = set_blank_if_default(self.T2, 1.0) T3 = set_blank_if_default(self.T3, 1.0) T4 = set_blank_if_default(self.T4, 1.0) #if 0: #print("eid = %s" % self.eid) #print("nodes = %s" % self.nodes) #print("self.zOffset = %s" % self.zOffset) #print("self.TFlag = %s" % self.TFlag) #print("self.thetaMcid = %s" % self.thetaMcid) #print("zOffset = %s" % zOffset) #print("TFlag = %s" % TFlag) #print("thetaMcid = %s" % thetaMcid) #print("T1 = %s" % T1) #print("T2 = %s" % T2) #print("T3 = %s" % T3) #print("T4 = %s\n" % T4) return (thetaMcid, zOffset, TFlag, T1, T2, T3, T4)
[docs]class CSHEAR(QuadShell): type = 'CSHEAR' calculixType = 'S4' def __init__(self, card=None, data=None, comment=''): QuadShell.__init__(self, card, data) if comment: self._comment = comment if card: #: Element ID self.eid = integer(card, 1, 'eid') #: Property ID self.pid = integer_or_blank(card, 2, 'pid', self.eid) nids = [integer_or_blank(card, 3, 'n1'), integer_or_blank(card, 4, 'n2'), integer_or_blank(card, 5, 'n3'), integer_or_blank(card, 6, 'n4')] assert len(card) <= 7, 'len(CSHEAR card) = %i' % len(card) else: self.eid = data[0] self.pid = data[1] nids = data[2:] self.prepare_node_ids(nids) assert len(self.nodes) == 4
[docs] def cross_reference(self, model): msg = ' which is required by CSHEAR eid=%s' % self.eid self.nodes = model.Nodes(self.nodes, allowEmptyNodes=True, msg=msg) self.pid = model.Property(self.pid, msg=msg)
[docs] def Normal(self): (n1, n2, n3, n4) = self.nodePositions() return _normal(n1 - n3, n2 - n4)
[docs] def AreaCentroidNormal(self): (area, centroid) = self.AreaCentroid() normal = self.Normal() return (area, centroid, normal)
[docs] def AreaCentroid(self): r""" :: 1-----2 | /| | A1/ | | / | |/ A2 | 4-----3 .. math: c = \frac{\sum(c_i A_i){\sum{A_i}} c = sum(ci*Ai)/sum(A) where: c=centroid A=area """ (n1, n2, n3, n4) = self.nodePositions() a = n1 - n2 b = n2 - n4 area1 = Area(a, b) c1 = centroid_triangle(n1, n2, n4) a = n2 - n4 b = n2 - n3 area2 = Area(a, b) c2 = centroid_triangle(n2, n3, n4) area = area1 + area2 centroid = (c1 * area1 + c2 * area2) / area return(area, centroid)
[docs] def Centroid(self): (area, centroid) = self.AreaCentroid() return centroid
[docs] def _verify(self, xref=True): 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: assert self.pid.type in ['PSHEAR'], 'pid=%i self.pid.type=%s' % (pid, self.pid.type) if self.pid.type in ['PSHEAR']: t = self.Thickness() assert isinstance(t, float), 'thickness=%r' % t mass = self.Mass() assert isinstance(mass, float), 'mass=%r' % mass a, c, n = self.AreaCentroidNormal() assert isinstance(a, float), 'Area=%r' % a for i in range(3): assert isinstance(c[i], float) assert isinstance(n[i], float)
[docs] def Area(self): r""" .. math:: A = \frac{1}{2} \lvert (n_1-n_3) \times (n_2-n_4) \rvert where a and b are the quad's cross node point vectors""" (n1, n2, n3, n4) = self.nodePositions() a = n1 - n3 b = n2 - n4 area = Area(a, b) return area
[docs] def flipNormal(self): r""" :: 1---2 1---4 | | --> | | | | | | 4---3 2---3 """ (n1, n2, n3, n4) = self.nodes self.nodes = [n1, n4, n3, n2]
[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] def raw_fields(self): list_fields = ['CSHEAR', self.eid, self.Pid()] + self.node_ids return list_fields
[docs] def repr_fields(self): return self.raw_fields()
[docs] def write_card(self, size=8, is_double=False): card = self.repr_fields() msg = self.comment() + print_card_8(card) #msg2 = self.write_card(size) #assert msg == msg2, '\n%s---\n%s\n%r\n%r' % (msg, msg2, msg, msg2) return msg
[docs] def G(self): return self.pid.mid.G()
[docs] def Thickness(self): return self.pid.t
[docs]class CQUAD4(QuadShell): type = 'CQUAD4' asterType = 'QUAD4 # CQUAD4' calculixType = 'S4' _field_map = {1: 'eid', 2:'pid', 7:'thetaMcid', 8:'zOffset', 10:'TFlag', 11:'T1', 12:'T2', 13:'T3'}
[docs] def _update_field_helper(self, n, value): if n == 3: self.nodes[0] = value elif n == 4: self.nodes[1] = value elif n == 5: self.nodes[2] = value elif n == 6: self.nodes[3] = value else: raise KeyError('Field %r=%r is an invalid %s entry.' % (n, value, self.type))
def __init__(self, card=None, data=None, comment=''): QuadShell.__init__(self, card, data) if comment: self._comment = comment if card: #: Element ID self.eid = integer(card, 1, 'eid') #: Property ID self.pid = integer_or_blank(card, 2, 'pid', self.eid) nids = [integer(card, 3, 'n1'), integer(card, 4, 'n2'), integer(card, 5, 'n3'), integer(card, 6, 'n4')] self.thetaMcid = integer_double_or_blank(card, 7, 'thetaMcid', 0.0) self.zOffset = double_or_blank(card, 8, 'zOffset', 0.0) blank(card, 9, 'blank') self.TFlag = integer_or_blank(card, 10, 'TFlag', 0) self.T1 = double_or_blank(card, 11, 'T1', 1.0) self.T2 = double_or_blank(card, 12, 'T2', 1.0) self.T3 = double_or_blank(card, 13, 'T3', 1.0) self.T4 = double_or_blank(card, 14, 'T4', 1.0) assert len(card) <= 15, 'len(CQUAD4 card) = %i' % len(card) else: self.eid = data[0] self.pid = data[1] nids = data[2:6] self.thetaMcid = data[6] self.zOffset = data[7] self.TFlag = data[8] self.T1 = data[9] self.T2 = data[10] self.T3 = data[11] self.T4 = data[12] if self.T1 == -1.0: self.T1 = 1.0 if self.T2 == -1.0: self.T2 = 1.0 if self.T3 == -1.0: self.T3 = 1.0 if self.T4 == -1.0: self.T4 = 1.0 self.prepare_node_ids(nids) assert len(self.nodes) == 4, 'CQUAD4'
[docs] def cross_reference(self, model): msg = ' which is required by CQUAD4 eid=%s' % self.eid self.nodes = model.Nodes(self.nodes, 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: assert self.pid.type in ['PSHELL', 'PCOMP', 'PCOMPG', 'PLPLANE'], 'pid=%i self.pid.type=%s' % (pid, self.pid.type) if not self.pid.type in ['PLPLANE']: t = self.Thickness() assert isinstance(t, float), 'thickness=%r' % t mass = self.Mass() assert isinstance(mass, float), 'mass=%r' % mass a, c, n = self.AreaCentroidNormal() assert isinstance(a, float), 'Area=%r' % a for i in range(3): assert isinstance(c[i], float) assert isinstance(n[i], float)
[docs] def flipNormal(self): r""" :: 1---2 1---4 | | --> | | | | | | 4---3 2---3 """ (n1, n2, n3, n4) = self.nodes self.nodes = [n1, n4, n3, n2]
[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] def writeAsCTRIA3(self, newID): """ triangle - 012 triangle - 023 """ zOffset = set_blank_if_default(self.zOffset, 0.0) nodes1 = [self.nodes[0], self.nodes[1], self.nodes[2]] nodes2 = [self.nodes[0], self.nodes[2], self.nodes[3]] fields1 = ['CTRIA3', self.eid, self.Pid()] + nodes1 + [ self.thetaMcid, zOffset] fields2 = ['CTRIA3', newID, self.Pid()] + nodes2 + [ self.thetaMcid, zOffset] return self.print_card(fields1) + self.print_card(fields2)
[docs] def raw_fields(self): list_fields = (['CQUAD4', self.eid, self.Pid()] + self.node_ids + [self.thetaMcid, self.zOffset, self.TFlag, self.T1, self.T2, self.T3, self.T4]) return list_fields
[docs] def repr_fields(self): (thetaMcid, zOffset, TFlag, T1, T2, T3, T4) = self.getReprDefaults() list_fields = (['CQUAD4', self.eid, self.Pid()] + self.node_ids + [thetaMcid, zOffset, None, TFlag, T1, T2, T3, T4]) return list_fields
[docs] def write_card(self, size=8, is_double=False): zOffset = set_blank_if_default(self.zOffset, 0.0) TFlag = set_blank_if_default(self.TFlag, 0) thetaMcid = set_blank_if_default(self.thetaMcid, 0.0) T1 = set_blank_if_default(self.T1, 1.0) T2 = set_blank_if_default(self.T2, 1.0) T3 = set_blank_if_default(self.T3, 1.0) T4 = set_blank_if_default(self.T3, 1.0) nodes = self.node_ids row2_data = [thetaMcid, zOffset, TFlag, T1, T2, T3, T4] row2 = [print_field_8(field) for field in row2_data] data = [self.eid, self.Pid()] + nodes + row2 msg = ('CQUAD4 %8i%8i%8i%8i%8i%8i%8s%8s\n' ' %8s%8s%8s%8s%8s\n' % tuple(data)) return self.comment() + msg.rstrip() + '\n'
#def write_card(self, size=8, is_double=False): #card = wipe_empty_fields(self.repr_fields()) #if size == 8 or len(card) == 7: # to last node #msg = self.comment() + print_card_8(card) #else: #msg = self.comment() + print_card_16(card) #msg2 = self.write_card(size) #assert msg == msg2, '\n%s---\n%s\n%r\n%r' % (msg, msg2, msg, msg2) #return msg
[docs]class CQUADR(QuadShell): type = 'CQUADR' #calculixType = 'CAX8' def __init__(self, card=None, data=None, comment=''): QuadShell.__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_or_blank(card, 3, 'n1'), integer_or_blank(card, 4, 'n2'), integer_or_blank(card, 5, 'n3'), integer_or_blank(card, 6, 'n4')] self.thetaMcid = integer_double_or_blank(card, 7, 'thetaMcid', 0.0) self.zOffset = double_or_blank(card, 8, 'zOffset', 0.0) self.TFlag = integer_or_blank(card, 10, 'TFlag', 0) self.T1 = double_or_blank(card, 11, 'T1', 1.0) self.T2 = double_or_blank(card, 12, 'T2', 1.0) self.T3 = double_or_blank(card, 13, 'T3', 1.0) self.T4 = double_or_blank(card, 14, 'T4', 1.0) assert len(card) <= 15, 'len(CQUADR card) = %i' % len(card) else: self.eid = data[0] self.pid = data[1] nids = data[2:6] self.thetaMcid = data[6] self.zOffset = data[7] self.TFlag = data[8] self.T1 = data[9] self.T2 = data[10] self.T3 = data[11] self.T4 = data[12] if self.T1 == -1.0: self.T1 = 1.0 if self.T2 == -1.0: self.T2 = 1.0 if self.T3 == -1.0: self.T3 = 1.0 if self.T4 == -1.0: self.T4 = 1.0 self.prepare_node_ids(nids) assert len(self.nodes) == 4, 'CQUADR'
[docs] def cross_reference(self, model): msg = ' which is required by CQUADR eid=%s' % 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 isinstance(nid, int), 'nid%i is not an integer; nid=%s' %(i, nid) if xref: assert self.pid.type in ['PSHELL', 'PCOMP', 'PCOMPG'], 'pid=%i self.pid.type=%s' % (pid, self.pid.type) t = self.Thickness() a, c, n = self.AreaCentroidNormal() assert isinstance(t, float), 'thickness=%r' % t assert isinstance(a, float), 'Area=%r' % a for i in range(3): assert isinstance(c[i], float) #assert isinstance(n[i], float) mass = self.Mass() assert isinstance(mass, float), 'mass=%r' % mass
[docs] def Thickness(self): """ Returns the thickness """ return self.pid.Thickness()
[docs] def flipNormal(self): r""" :: 1---2 1---4 | | --> | | | | | | 4---3 2---3 """ (n1, n2, n3, n4) = self.nodes self.nodes = [n1, n4, n3, n2]
[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] def raw_fields(self): list_fields = (['CQUADR', self.eid, self.Pid()] + self.node_ids + [self.thetaMcid, self.zOffset, None, self.TFlag, self.T1, self.T2, self.T3, self.T4]) return list_fields
[docs] def repr_fields(self): (thetaMcid, zOffset, TFlag, T1, T2, T3, T4) = self.getReprDefaults() list_fields = (['CQUADR', self.eid, self.Pid()] + self.node_ids + [thetaMcid, zOffset, None, TFlag, T1, T2, T3, T4]) return list_fields
[docs] def write_card(self, size=8, is_double=False): card = self.repr_fields() if size == 8 or len(card) == 7: # to last node msg = self.comment() + print_card_8(card) else: msg = self.comment() + print_card_16(card) #msg2 = self.write_card(size) #assert msg == msg2, '\n%s---\n%s\n%r\n%r' % (msg, msg2, msg, msg2) return msg
[docs]class CQUAD(QuadShell): type = 'CQUAD' def __init__(self, card=None, data=None, comment=''): QuadShell.__init__(self, card, data) if comment: self._comment = comment #: Element ID self.eid = integer(card, 1, 'eid') #: Property ID self.pid = integer(card, 2, 'pid') nids = [integer(card, 3, 'n1'), integer(card, 4, 'n2'), integer_or_blank(card, 5, 'n3'), integer_or_blank(card, 6, 'n4'), integer_or_blank(card, 7, 'n5'), integer_or_blank(card, 8, 'n6'), integer_or_blank(card, 9, 'n7'), integer_or_blank(card, 10, 'n8'), integer_or_blank(card, 11, 'n9')] assert len(card) <= 12, 'len(CQUAD card) = %i' % len(card) self.prepare_node_ids(nids, allow_empty_nodes=True) assert len(self.nodes) == 9
[docs] def cross_reference(self, model): msg = ' which is required by CQUAD eid=%s' % self.eid self.nodes = model.Nodes(self.nodes, allowEmptyNodes=True, msg=msg) self.pid = model.Property(self.pid, msg=msg)
[docs] def Thickness(self): """ Returns the thickness """ return self.pid.Thickness()
[docs] def flipNormal(self): r""" :: 1--5--2 1--8--4 | | --> | | 8 9 6 5 9 7 | | | | 4--7--3 2--6--3 """ (n1, n2, n3, n4, n5, n6, n7, n8, n9) = self.nodes self.nodes = [n1, n4, n3, n2, n8, n7, n6, n5, n9] assert len(self.nodes) == 9
[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] def raw_fields(self): list_fields = ['CQUAD', self.eid, self.Pid()] + self.node_ids return list_fields
[docs] def repr_fields(self): list_fields = ['CQUAD', self.eid, self.Pid()] + self.node_ids return list_fields
[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 = ('CQUAD %8i%8i%8i%8i%8i%8i%8s%8s\n' # 6 nodes ' %8s%8s%8s\n' % tuple(data)) return self.comment() + msg.rstrip() + '\n'
#def write_card(self, size=8, is_double=False): #card = self.repr_fields() #msg = self.comment() + print_card_8(card) #msg2 = self.write_card(size) #assert msg == msg2, '\n%s---\n%s\n%r\n%r' % (msg, msg2, msg, msg2) #return msg
[docs]class CQUAD8(QuadShell): type = 'CQUAD8' asterType = 'QUAD8' def __init__(self, card=None, data=None, comment=''): QuadShell.__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, 'n1'), integer(card, 4, 'n2'), integer(card, 5, 'n3'), integer(card, 6, 'n4'), integer_or_blank(card, 7, 'n5', 0), integer_or_blank(card, 8, 'n6', 0), integer_or_blank(card, 9, 'n7', 0), integer_or_blank(card, 10, 'n8', 0)] self.T1 = double_or_blank(card, 11, 'T1', 1.0) self.T2 = double_or_blank(card, 12, 'T2', 1.0) self.T3 = double_or_blank(card, 13, 'T3', 1.0) self.T4 = double_or_blank(card, 14, 'T4', 1.0) self.thetaMcid = integer_double_or_blank(card, 15, 'thetaMcid', 0.0) self.zOffset = double_or_blank(card, 16, 'zOffset', 0.0) self.TFlag = integer_or_blank(card, 17, 'TFlag', 0) assert len(card) <= 18, 'len(CQUAD4 card) = %i' % len(card) else: #print "CQUAD8 = ",data #(6401, #6400, #6401, 6402, 6405, 6403, 0, 0, 6404, 0, #-1.0, -1.0, -1.0, -1.0, #0.0, 0) self.eid = data[0] self.pid = data[1] nids = data[2:10] self.T1 = data[10] self.T2 = data[11] self.T3 = data[12] self.T4 = data[13] self.thetaMcid = data[14] self.zOffset = data[14] self.TFlag = data[15] self.prepare_node_ids(nids, allow_empty_nodes=True) assert len(self.nodes) == 8
[docs] def cross_reference(self, model): msg = ' which is required by CQUAD8 eid=%s' % 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 isinstance(nid, int), 'nid%i is not an integer; nid=%s' %(i, nid) if xref: assert self.pid.type in ['PSHELL', 'PCOMP', 'PCOMPG'], 'pid=%i self.pid.type=%s' % (pid, self.pid.type) t = self.Thickness() a, c, n = self.AreaCentroidNormal() assert isinstance(t, float), 'thickness=%r' % t assert isinstance(a, float), 'Area=%r' % a for i in range(3): assert isinstance(c[i], float) #assert isinstance(n[i], float) mass = self.Mass() assert isinstance(mass, float), 'mass=%r' % mass
[docs] def Thickness(self): """ Returns the thickness """ return self.pid.Thickness()
[docs] def flipNormal(self): r""" :: 1--5--2 1--8--4 | | --> | | 8 6 5 7 | | | | 4--7--3 2--6--3 """ (n1, n2, n3, n4, n5, n6, n7, n8) = self.nodes self.nodes = [n1, n4, n3, n2, n8, n7, n6, n5]
[docs] def Normal(self): (n1, n2, n3, n4) = self.nodePositions()[:4] return _normal(n1 - n3, n2 - n4)
[docs] def AreaCentroid(self): """ :: 1-----2 | /| | A1/ | | / | |/ A2 | 4-----3 centroid c = sum(ci*Ai)/sum(A) where: c=centroid A=area """ (n1, n2, n3, n4, n5, n6, n7, n8) = self.nodePositions() a = n1 - n2 b = n2 - n4 area1 = Area(a, b) c1 = centroid_triangle(n1, n2, n4) a = n2 - n4 b = n2 - n3 area2 = Area(a, b) c2 = centroid_triangle(n2, n3, n4) area = area1 + area2 centroid = (c1 * area1 + c2 * area2) / area return(area, centroid)
[docs] def Area(self): r""" .. math:: A = \frac{1}{2} \lvert (n_1-n_3) \times (n_2-n_4) \rvert where a and b are the quad's cross node point vectors""" (n1, n2, n3, n4, n5, n6, n7, n8) = self.nodePositions() a = n1 - n3 b = n2 - n4 area = Area(a, b) return area
[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] def raw_fields(self): list_fields = ['CQUAD8', self.eid, self.Pid()] + self.node_ids + [ self.T1, self.T2, self.T3, self.T4, self.thetaMcid, self.zOffset, self.TFlag] return list_fields
[docs] def repr_fields(self): (thetaMcid, zOffset, TFlag, T1, T2, T3, T4) = self.getReprDefaults() list_fields = (['CQUAD8', self.eid, self.Pid()] + self.node_ids + [ T1, T2, T3, T4, thetaMcid, zOffset, TFlag]) return list_fields
[docs] def write_card(self, size=8, is_double=False): card = self.repr_fields() if size == 8 or len(card) == 11: # to last node return self.comment() + print_card_8(card) return self.comment() + print_card_16(card)
[docs]class CQUADX(QuadShell): type = 'CQUADX' calculixType = 'CAX8' def __init__(self, card=None, data=None, comment=''): QuadShell.__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_or_blank(card, 3, 'n1'), integer_or_blank(card, 4, 'n2'), integer_or_blank(card, 5, 'n3'), integer_or_blank(card, 6, 'n4'), integer_or_blank(card, 7, 'n5'), integer_or_blank(card, 8, 'n6'), integer_or_blank(card, 9, 'n7'), integer_or_blank(card, 10, 'n8'), integer_or_blank(card, 11, 'n9')] assert len(card) <= 12, 'len(CQUADX card) = %i' % len(card) else: raise NotImplementedError(data) self.prepare_node_ids(nids, allow_empty_nodes=True) assert len(self.nodes) == 9
[docs] def cross_reference(self, model): msg = ' which is required by CQUADX eid=%s' % self.eid self.nodes = model.Nodes(self.nodes, allowEmptyNodes=True, msg=msg) self.pid = model.Property(self.pid, msg=msg)
[docs] def Thickness(self): """ Returns the thickness """ return self.pid.Thickness()
[docs] def flipNormal(self): r""" :: 1--5--2 1--8--4 | | --> | | 8 9 6 5 9 7 | | | | 4--7--3 2--6--3 """ (n1, n2, n3, n4, n5, n6, n7, n8, n9) = self.nodes self.nodes = [n1, n4, n3, n2, n8, n7, n6, n5, n9]
[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] def raw_fields(self): list_fields = ['CQUADX', self.eid, self.Pid()] + self.node_ids return list_fields
[docs] def repr_fields(self): return self.raw_fields()
[docs] def write_card(self, size=8, is_double=False): nodes = self.node_ids data = [self.eid, self.Pid()] + nodes[:4] row2 = [' ' if node is None else '%8i' % node for node in nodes[4:]] msg = ('CQUADX %8i%8i%8i%8i%8i%8i%8s%8s\n' ' %8s%8s%8s' % tuple(data + row2)) return self.comment() + msg.rstrip() + '\n'