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

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

 * CELAS1
 * CELAS2
 * CELAS3
 * CELAS4

All spring elements are SpringElement and Element objects.

"""
from __future__ import annotations
from typing import TYPE_CHECKING
from pyNastran.bdf.field_writer_8 import set_blank_if_default
from pyNastran.bdf.cards.base_card import Element
from pyNastran.bdf.bdf_interface.assign_type import (
    integer, integer_or_blank, double, double_or_blank)
from pyNastran.bdf.field_writer_8 import print_card_8
from pyNastran.bdf.field_writer_16 import print_card_16
if TYPE_CHECKING:  # pragma: no cover
    from pyNastran.bdf.bdf import BDF


[docs] class SpringElement(Element): def __init__(self): Element.__init__(self) self.nodes = [None, None]
[docs] def Mass(self): return 0.0
[docs] def repr_fields(self): return self.raw_fields()
[docs] def write_card_16(self, is_double=False): card = self.repr_fields() return self.comment + print_card_16(card)
[docs] class CELAS1(SpringElement): """ +--------+-----+-----+----+----+----+----+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | +========+=====+=====+====+====+====+====+ | CELAS1 | EID | PID | G1 | C1 | G2 | C2 | +--------+-----+-----+----+----+----+----+ """ type = 'CELAS1' _field_map = { 1: 'eid', 2:'pid', 4:'c1', 6:'c2', } def _update_field_helper(self, n, value): if n == 3: self.nodes[0] = value elif n == 5: self.nodes[1] = value else: raise KeyError('Field %r=%r is an invalid %s entry.' % (n, value, self.type)) def __init__(self, eid, pid, nids, c1=0, c2=0, comment=''): """ Creates a CELAS1 card Parameters ---------- eid : int element id pid : int property id (PELAS) nids : list[int, int] node ids c1 / c2 : int; default=0 DOF for nid1 / nid2 comment : str; default='' a comment for the card """ SpringElement.__init__(self) if comment: self.comment = comment self.eid = eid #: property ID self.pid = pid #: component number self.c1 = c1 self.c2 = c2 self.nodes = self.prepare_node_ids(nids, allow_empty_nodes=True) self.nodes_ref = None self.pid_ref = None
[docs] @classmethod def export_to_hdf5(cls, h5_file, model, eids): """exports the elements in a vectorized way""" #comments = [] pids = [] nodes = [] components = [] for eid in eids: element = model.elements[eid] #comments.append(element.comment) pids.append(element.pid) nodes.append([nid if nid is not None else 0 for nid in element.nodes]) components.append([element.c1, element.c2]) #h5_file.create_dataset('_comment', data=comments) h5_file.create_dataset('eid', data=eids) h5_file.create_dataset('pid', data=pids) h5_file.create_dataset('nodes', data=nodes) h5_file.create_dataset('components', data=components)
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a CELAS1 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ eid = integer(card, 1, 'eid') pid = integer_or_blank(card, 2, 'pid', eid) nids = [integer(card, 3, 'g1'), integer_or_blank(card, 5, 'g2', 0)] #: component number c1 = integer_or_blank(card, 4, 'c1', 0) c2 = integer_or_blank(card, 6, 'c2', 0) assert len(card) <= 7, f'len(CELAS1 card) = {len(card):d}\ncard={card}' return CELAS1(eid, pid, nids, c1, c2, comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a CELAS1 card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ eid = data[0] pid = data[1] nids = [data[2], data[3]] c1 = data[4] c2 = data[5] return CELAS1(eid, pid, nids, c1, c2, comment=comment)
[docs] def validate(self): msg = 'on\n%s\n is invalid validComponents=[0,1,2,3,4,5,6]' % str(self) assert self.c1 in [0, 1, 2, 3, 4, 5, 6], 'c1=%r %s' % (self.c1, msg) assert self.c2 in [0, 1, 2, 3, 4, 5, 6], 'c2=%r %s' % (self.c2, msg) assert len(self.nodes) == 2
@property def node_ids(self): msg = ', which is required by CELAS1 eid=%s' % (self.eid) return self._node_ids(nodes=self.nodes_ref, allow_empty_nodes=True, msg=msg)
[docs] def get_edge_ids(self): return [tuple(sorted(self.node_ids))]
def _verify(self, xref): eid = self.eid node_ids = self.node_ids c1 = self.c1 c2 = self.c2 #ge = self.ge #s = self.s assert isinstance(eid, int), 'eid=%r' % eid assert isinstance(c1, int), 'c1=%r' % c1 assert isinstance(c2, int), 'c2=%r' % c2 #assert isinstance(ge, float), 'ge=%r' % ge #assert isinstance(s, float), 'ge=%r' % s if xref: k = self.K() assert self.pid_ref.type in ['PELAS'], self.pid_ref assert isinstance(k, float), 'k=%r' % k assert len(node_ids) == len(self.nodes) #for nodeID, node in zip(node_ids, self.nodes): #assert node.node.nid
[docs] def K(self): return self.pid_ref.k
[docs] def cross_reference(self, model: BDF) -> None: """ Cross links the card so referenced cards can be extracted directly Parameters ---------- model : BDF() the BDF object """ msg = ', which is required by CELAS1 eid=%s' % (self.eid) self.nodes_ref = model.EmptyNodes(self.node_ids, msg=msg) self.pid_ref = model.Property(self.Pid(), msg=msg)
[docs] def safe_cross_reference(self, model: BDF, xref_errors): """ Cross links the card so referenced cards can be extracted directly Parameters ---------- model : BDF() the BDF object """ msg = ', which is required by CELAS1 eid=%s' % self.eid self.nodes_ref = model.EmptyNodes(self.node_ids, msg=msg) self.pid_ref = model.safe_property(self.pid, self.eid, xref_errors, msg=msg)
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.nodes = self.node_ids self.pid = self.Pid() self.nodes_ref = None self.pid_ref = None
[docs] def raw_fields(self): nodes = self.node_ids list_fields = ['CELAS1', self.eid, self.Pid(), nodes[0], self.c1, nodes[1], self.c2] return list_fields
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: card = self.repr_fields() return self.comment + print_card_8(card)
[docs] class CELAS2(SpringElement): """ +--------+-----+-----+----+----+----+----+----+----+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +========+=====+=====+====+====+====+====+====+====+ | CELAS2 | EID | K | G1 | C1 | G2 | C2 | GE | S | +--------+-----+-----+----+----+----+----+----+----+ """ type = 'CELAS2' _field_map = { 1: 'eid', 2:'k', 4:'c1', 6:'c2', } cp_name_map = {'K' : 'k', 'GE' : 'ge', 'S' : 's'} def _update_field_helper(self, n, value): if n == 3: self.nodes[0] = value elif n == 5: self.nodes[1] = value else: raise KeyError('Field %r=%r is an invalid %s entry.' % (n, value, self.type)) def __init__(self, eid, k, nids, c1=0, c2=0, ge=0., s=0., comment=''): """ Creates a CELAS2 card Parameters ---------- eid : int element id k : float spring stiffness nids : list[int, int] SPOINT ids node ids c1 / c2 : int; default=0 DOF for nid1 / nid2 ge : int; default=0.0 damping coefficient s : float; default=0.0 stress coefficient comment : str; default='' a comment for the card """ SpringElement.__init__(self) if comment: self.comment = comment self.eid = eid #: stiffness of the scalar spring self.k = k #: component number self.c1 = c1 self.c2 = c2 #: damping coefficient self.ge = ge #: stress coefficient self.s = s self.nodes = self.prepare_node_ids(nids, allow_empty_nodes=True) self.nodes_ref = None self.pid_ref = None
[docs] @classmethod def export_to_hdf5(cls, h5_file, model, eids): """exports the elements in a vectorized way""" #comments = [] k = [] ge = [] s = [] nodes = [] components = [] for eid in eids: element = model.elements[eid] #comments.append(element.comment) k.append(element.k) ge.append(element.ge) s.append(element.s) nodes.append([nid if nid is not None else 0 for nid in element.nodes]) components.append([element.c1, element.c2]) #h5_file.create_dataset('_comment', data=comments) h5_file.create_dataset('eid', data=eids) h5_file.create_dataset('K', data=k) h5_file.create_dataset('ge', data=ge) h5_file.create_dataset('s', data=s) h5_file.create_dataset('nodes', data=nodes) h5_file.create_dataset('components', data=components)
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a CELAS2 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ eid = integer(card, 1, 'eid') k = double(card, 2, 'k') nids = [integer_or_blank(card, 3, 'g1', default=0), integer_or_blank(card, 5, 'g2', default=0)] c1 = integer_or_blank(card, 4, 'c1', default=0) c2 = integer_or_blank(card, 6, 'c2', default=0) ge = double_or_blank(card, 7, 'ge', default=0.) s = double_or_blank(card, 8, 's', default=0.) assert len(card) <= 9, f'len(CELAS2 card) = {len(card):d}\ncard={card}' return CELAS2(eid, k, nids, c1, c2, ge, s, comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a CELAS2 card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ eid = data[0] k = data[1] nids = [data[2], data[3]] c1 = data[4] c2 = data[5] ge = data[6] s = data[7] return CELAS2(eid, k, nids, c1, c2, ge, s, comment=comment)
[docs] def validate(self): msg = 'on\n%s\n is invalid validComponents=[0,1,2,3,4,5,6]' % str(self) assert self.c1 in [0, 1, 2, 3, 4, 5, 6], 'c1=%r %s' % (self.c1, msg) assert self.c2 in [0, 1, 2, 3, 4, 5, 6], 'c2=%r %s' % (self.c2, msg) if self.nodes[0] == self.nodes[1] and self.c1 == self.c2: msg = ( 'Thee nodes=%s must be unique or dofs=[%s, %s] must not be ' 'the same; CELAS2 eid=%s' % (self.nodes, self.c1, self.c2, self.eid)) raise AssertionError(msg)
@property def node_ids(self): msg = ', which is required by CELAS2 eid=%s' % (self.eid) return self._node_ids(nodes=self.nodes_ref, allow_empty_nodes=True, msg=msg)
[docs] def get_edge_ids(self): return [tuple(sorted(self.node_ids))]
[docs] def cross_reference(self, model: BDF) -> None: """ Cross links the card so referenced cards can be extracted directly Parameters ---------- model : BDF() the BDF object """ msg = ', which is required by CELAS2 eid=%s' % (self.eid) self.nodes_ref = model.EmptyNodes(self.node_ids, msg=msg)
[docs] def safe_cross_reference(self, model: BDF, xref_errors): """ Cross links the card so referenced cards can be extracted directly Parameters ---------- model : BDF() the BDF object """ msg = ', which is required by CELAS2 eid=%s' % self.eid self.nodes_ref = model.EmptyNodes(self.node_ids, msg=msg)
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.nodes = self.node_ids self.nodes_ref = None
def _verify(self, xref=True): eid = self.eid k = self.K() node_ids = self.node_ids c1 = self.c2 c2 = self.c1 ge = self.ge s = self.s assert isinstance(eid, int), 'eid=%r' % eid assert isinstance(c1, int), 'c1=%r' % c1 assert isinstance(c2, int), 'c2=%r' % c2 assert isinstance(k, float), 'k=%r' % k assert isinstance(ge, float), 'ge=%r' % ge assert isinstance(s, float), 'ge=%r' % s if xref: assert len(node_ids) == len(self.nodes) #for node_id, node in zip(node_id, self.nodes): #assert node.node.nid
[docs] def K(self): return self.k
[docs] def raw_fields(self): nodes = self.node_ids list_fields = ['CELAS2', self.eid, self.k, nodes[0], self.c1, nodes[1], self.c2, self.ge, self.s] return list_fields
[docs] def repr_fields(self): nodes = self.node_ids ge = set_blank_if_default(self.ge, 0.) s = set_blank_if_default(self.s, 0.) list_fields = ['CELAS2', self.eid, self.k, nodes[0], self.c1, nodes[1], self.c2, ge, s] return list_fields
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: card = self.repr_fields() return self.comment + print_card_8(card)
[docs] class CELAS3(SpringElement): """ +--------+-----+-----+----+----+ | 1 | 2 | 3 | 4 | 5 | +========+=====+=====+====+====+ | CELAS3 | EID | PID | S1 | S2 | +--------+-----+-----+----+----+ """ type = 'CELAS3' _field_map = { 1: 'eid', 2:'pid', #4:'s1', 6:'s2', } def __init__(self, eid, pid, nodes, comment=''): """ Creates a CELAS3 card Parameters ---------- eid : int element id pid : int property id (PELAS) nids : list[int, int] SPOINT ids comment : str; default='' a comment for the card """ SpringElement.__init__(self) if comment: self.comment = comment self.eid = eid #: property ID self.pid = pid #: Scalar point identification numbers self.nodes = nodes self.nodes_ref = None self.pid_ref = None
[docs] @classmethod def export_to_hdf5(cls, h5_file, model, eids): """exports the elements in a vectorized way""" #comments = [] pids = [] nodes = [] for eid in eids: element = model.elements[eid] #comments.append(element.comment) pids.append(element.pid) nodes.append(element.nodes) #h5_file.create_dataset('_comment', data=comments) h5_file.create_dataset('eid', data=eids) h5_file.create_dataset('pid', data=pids) h5_file.create_dataset('nodes', data=nodes)
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a CELAS3 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ eid = integer(card, 1, 'eid') pid = integer_or_blank(card, 2, 'pid', default=eid) s1 = integer_or_blank(card, 3, 's1', default=0) s2 = integer_or_blank(card, 4, 's2', default=0) assert len(card) <= 5, f'len(CELAS3 card) = {len(card):d}\ncard={card}' return CELAS3(eid, pid, [s1, s2], comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a CELAS3 card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ eid = data[0] pid = data[1] s1 = data[2] s2 = data[3] return CELAS3(eid, pid, [s1, s2], comment=comment)
[docs] def K(self): return self.pid_ref.k
[docs] def cross_reference(self, model: BDF) -> None: """ Cross links the card so referenced cards can be extracted directly Parameters ---------- model : BDF() the BDF object """ msg = ', which is required by CELAS3 eid=%s' % (self.eid) self.nodes_ref = model.EmptyNodes(self.nodes, msg=msg) self.pid_ref = model.Property(self.Pid(), msg=msg)
[docs] def safe_cross_reference(self, model: BDF, xref_errors): """ Cross links the card so referenced cards can be extracted directly Parameters ---------- model : BDF() the BDF object """ msg = ', which is required by CELAS3 eid=%s' % (self.eid) #self.nodes_ref = model.safe_empty_nodes(self.node_ids, msg=msg) self.nodes_ref = model.EmptyNodes(self.node_ids, msg=msg) self.pid_ref = model.safe_property(self.pid, self.eid, xref_errors, msg=msg)
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.nodes = self.node_ids self.pid = self.Pid() self.nodes_ref = None self.pid_ref = None
@property def node_ids(self): msg = ', which is required by CELAS3 eid=%s' % (self.eid) return self._node_ids(nodes=self.nodes_ref, allow_empty_nodes=True, msg=msg)
[docs] def get_edge_ids(self): return []
def _verify(self, xref): eid = self.eid node_ids = self.node_ids s1 = self.nodes[0] s2 = self.nodes[1] #ge = self.ge #s = self.s assert isinstance(eid, int), 'eid=%r' % eid assert isinstance(s1, int), 's1=%r' % s1 assert isinstance(s2, int), 's2=%r' % s2 #assert isinstance(ge, float), 'ge=%r' % ge #assert isinstance(s, float), 'ge=%r' % s if xref: k = self.K() assert self.pid_ref.type in ['PELAS'], self.pid_ref assert isinstance(k, float), 'k=%r' % k assert len(node_ids) == len(self.nodes) #for nid, node in zip(node_ids, self.nodes): #assert node.node.nid
[docs] def raw_fields(self): list_fields = ['CELAS3', self.eid, self.Pid()] + self.node_ids return list_fields
#def repr_fields(self): #s1 = set_blank_if_default(self.s1,0) #s2 = set_blank_if_default(self.s2,0) #list_fields = ['CELAS3', self.eid, self.Pid(), s1, s2] #return list_fields
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: card = self.repr_fields() return self.comment + print_card_8(card)
[docs] class CELAS4(SpringElement): """ +--------+-----+-----+----+----+ | 1 | 2 | 3 | 4 | 5 | +========+=====+=====+====+====+ | CELAS4 | EID | K | S1 | S2 | +--------+-----+-----+----+----+ """ type = 'CELAS4' _field_map = { 1: 'eid', 2:'k', #4:'s1', 6:'s2', } cp_name_map = {'K': 'k',} def __init__(self, eid, k, nodes, comment=''): """ Creates a CELAS4 card Parameters ---------- eid : int element id k : float spring stiffness nids : list[int, int] SPOINT ids comment : str; default='' a comment for the card """ SpringElement.__init__(self) if comment: self.comment = comment self.eid = eid #: stiffness of the scalar spring self.k = k #: Scalar point identification numbers #self.nodes = nodes self.nodes = self.prepare_node_ids(nodes, allow_empty_nodes=True) self.nodes_ref = None
[docs] @classmethod def export_to_hdf5(cls, h5_file, model, eids): """exports the elements in a vectorized way""" #comments = [] k = [] nodes = [] for eid in eids: element = model.elements[eid] #comments.append(element.comment) k.append(element.k) nodes.append([nid if nid is not None else 0 for nid in element.nodes]) #h5_file.create_dataset('_comment', data=comments) h5_file.create_dataset('eid', data=eids) h5_file.create_dataset('K', data=k) h5_file.create_dataset('nodes', data=nodes)
[docs] def validate(self): if self.nodes[0] is not None and self.nodes[1] is not None: assert self.nodes[0] > 0 or self.nodes[1] > 0, 's1=%s s2=%s' % (self.nodes[0], self.nodes[1])
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a CELAS4 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ eid = integer(card, 1, 'eid') k = double(card, 2, 'k') s1 = integer_or_blank(card, 3, 's1', 0) s2 = integer_or_blank(card, 4, 's2', 0) assert len(card) <= 5, f'len(CELAS4 card) = {len(card):d}\ncard={card}' return CELAS4(eid, k, [s1, s2], comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a CELAS4 card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ eid = data[0] k = data[1] s1 = data[2] s2 = data[3] return CELAS4(eid, k, [s1, s2], comment=comment)
[docs] def K(self): return self.k
@property def node_ids(self): if self.nodes_ref is None: return self.nodes msg = ', which is required by CELAS4 eid=%s' % (self.eid) return self._node_ids(nodes=self.nodes_ref, allow_empty_nodes=True, msg=msg)
[docs] def get_edge_ids(self): return []
[docs] def cross_reference(self, model: BDF) -> None: """ Cross links the card so referenced cards can be extracted directly Parameters ---------- model : BDF() the BDF object """ msg = ', which is required by CELAS4 eid=%s' % (self.eid) self.nodes_ref = model.EmptyNodes(self.nodes, msg=msg)
[docs] def safe_cross_reference(self, model: BDF, xref_errors): """ Cross links the card so referenced cards can be extracted directly Parameters ---------- model : BDF() the BDF object """ msg = ', which is required by CELAS4 eid=%s' % self.eid self.nodes_ref = model.EmptyNodes(self.node_ids, msg=msg)
#self.nodes_ref = model.safe_empty_nodes(self.node_ids, msg=msg)
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.nodes = self.node_ids self.nodes_ref = None
[docs] def raw_fields(self): list_fields = ['CELAS4', self.eid, self.k] + self.node_ids return list_fields
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: card = self.repr_fields() return self.comment + print_card_8(card)