Source code for pyNastran.bdf.cards.axisymmetric.axisymmetric

"""
All axisymmetric shell elements are defined in this file.  This includes:
 * AXIC
 * AXIF
 * CCONEAX
 * PCONEAX
 * POINTAX
 * RINGFL
 * RINGAX

"""
from __future__ import annotations
from typing import TYPE_CHECKING
from pyNastran.bdf.field_writer_8 import (
    set_blank_if_default,
)
from pyNastran.bdf.bdf_interface.assign_type import (
    integer, integer_or_blank, double_or_blank, double, blank,
    string, string_or_blank, integer_or_string, fields,
)
from pyNastran.bdf.cards.base_card import BaseCard, Element

from pyNastran.bdf.cards.base_card import Property
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 AXIC(BaseCard): type = 'AXIC'
[docs] @classmethod def _init_from_empty(cls): nharmonics = 1 return AXIC(nharmonics, comment='')
def __init__(self, nharmonics, comment=''): if comment: self.comment = comment self.nharmonics = nharmonics
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a AXIC card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ nharmonics = integer(card, 1, 'nharmonics') assert len(card) == 2, f'len(AXIC card) = {len(card):d}\ncard={card}' return AXIC(nharmonics, comment=comment)
[docs] def raw_fields(self): list_fields = ['AXIC', self.nharmonics] return list_fields
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: card = self.repr_fields() msg = self.comment + print_card_8(card) return msg
[docs] class AXIF(BaseCard): """ AXIF CID G DRHO DB NOSYM F N1 N2 N3 N4 N5 etc. """ type = 'AXIF'
[docs] @classmethod def _init_from_empty(cls): cid = 1 g = 1. drho = 1. db = 1. no_sym = 'YES' f = 'NONE' n = 1 return AXIF(cid, g, drho, db, no_sym, f, n, comment='')
def __init__(self, cid, g, drho, db, no_sym, f, n, comment=''): """ cid : int Fluid coordinate system identification number. (Integer > 0) G : float Value of gravity for fluid elements in the axial direction. (Real) drho : float Default mass density for fluid elements. (Real > 0.0 or blank) db : float Default bulk modulus for fluid elements. no_sym : str Request for nonsymmetric (sine) terms of series. {YES, NO} F : str; default=None Flag specifying harmonics. (Blank if harmonic is specified, or Character: 'NONE') Ni : list[int] Harmonic numbers for the solution, represented by an increasing sequence of integers. On continuation entries, without the 'THRU' option, blank fields are ignored. 'THRU' implies all numbers including upper and lower harmonics. (0 < Integer < 100, or Character: 'THRU', 'STEP' or blank) """ if comment: self.comment = comment self.cid = cid self.g = g self.drho = drho self.db = db self.no_sym = no_sym self.f = f self.n = n
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a AXIF card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ cid = integer(card, 1, 'cid') g = double(card, 2, 'g') drho = double(card, 3, 'drho') db = double_or_blank(card, 4, 'db') no_sym = string(card, 5, 'no_sym') f = string_or_blank(card, 6, 'f') n = fields(integer_or_string, card, 'n', i=9, j=len(card)) #cid : int #G : float #drho : float #db : float #no_sym : str #F : str #Ni : list[int] assert len(card) >= 7, f'len(AXIF card) = {len(card):d}\ncard={card}' return AXIF(cid, g, drho, db, no_sym, f, n, comment=comment)
[docs] def raw_fields(self): list_fields = ['AXIF', self.cid, self.g, self.drho, self.db, self.no_sym, self.f] + self.n return list_fields
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: card = self.repr_fields() msg = self.comment + print_card_8(card) return msg
[docs] class POINTAX(BaseCard): """ +---------+----+-----+------+ | 1 | 2 | 3 | 4 | +=========+====+=====+======+ | POINTAX | ID | RID | PHI | +---------+----+-----+------+ | POINTAX | 2 | 3 | 30.0 | +---------+----+-----+------+ """ type = 'POINTAX'
[docs] @classmethod def _init_from_empty(cls): nid = 1 ringax = 1 phi = 60. return POINTAX(nid, ringax, phi, comment='')
def __init__(self, nid, ringax, phi, comment=''): """ Creates a POINTAX card Parameters ---------- nid : int Point identification number. ringax : int Identification number of a RINGAX entry. phi : float Azimuthal angle in degrees. comment : str; default='' a comment for the card """ if comment: self.comment = comment self.nid = nid self.ringax = ringax self.phi = phi
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a RINGAX card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ nid = integer(card, 1, 'nid') ringax = integer(card, 2, 'ringax') phi = double(card, 3, 'phi') assert len(card) <= 4, f'len(POINTAX card) = {len(card):d}\ncard={card}' return POINTAX(nid, ringax, phi, comment=comment)
[docs] def raw_fields(self): list_fields = ['POINTAX', self.nid, self.ringax, self.phi] return list_fields
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: card = self.repr_fields() msg = self.comment + print_card_8(card) return msg
[docs] class RINGFL(BaseCard): type = 'RINGFL' #: allows the get_field method and update_field methods to be used #_field_map = {1: 'mid', 3:'R', 4:'z', 7:'ps'}
[docs] @classmethod def _init_from_empty(cls): ringfl = 1 xa = 1. xb = 2. return RINGFL(ringfl, xa, xb, comment='')
def __init__(self, ringfl: int, xa: float, xb: float, comment: str='') -> None: # this card has missing fields """ Creates the RINGFL card """ #Ring.__init__(self) if comment: self.comment = comment self.ringfl = ringfl self.xa = xa self.xb = xb
[docs] @classmethod def add_card(cls, card, icard=0, comment=''): """ Adds a RINGAX card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ ioffset = 2 * icard j = icard + 1 ringfl = integer(card, 1+ioffset, 'ringfl_%i' % j) xa = double(card, 2+ioffset, 'xa_%i' % j) xb = double_or_blank(card, 3+ioffset, 'xa_%i' % j) assert len(card) <= 9, f'len(RINGFL card) = {len(card):d}\ncard={card}' return RINGFL(ringfl, xa, xb, comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a RINGAX card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ nid = data[0] R = data[1] z = data[2] ps = data[3] assert len(data) == 4, data return RINGAX(nid, R, z, ps, comment=comment)
[docs] def raw_fields(self): """ Gets the fields in their unmodified form Returns ------- fields : list[varies] the fields that define the card """ list_fields = ['RINGFL', self.ringfl, self.xa, self.xb] return list_fields
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: """ The writer method used by BDF.write_card() Parameters ----------- size : int; default=8 the size of the card (8/16) """ card = self.repr_fields() if size == 8: return self.comment + print_card_8(card) return self.comment + print_card_16(card)
[docs] class RINGAX(BaseCard): """ Defines a ring for conical shell problems. +-------+-----+-----+-----+----+-----+-----+------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | +=======+=====+=====+=====+====+=====+=====+======+ |RINGAX | MID | | R | Z | | | PS | +-------+-----+-----+-----+----+-----+-----+------+ """ type = 'RINGAX' #: allows the get_field method and update_field methods to be used _field_map = {1: 'mid', 3:'R', 4:'z', 7:'ps'}
[docs] @classmethod def _init_from_empty(cls): nid = 1 R = 1. z = 1. return RINGAX(nid, R, z, ps=None, comment='')
def __init__(self, nid: int, R: float, z: float, ps: Optional[str]=None, comment: str=''): # this card has missing fields """ Creates the RINGAX card """ #Ring.__init__(self) if comment: self.comment = comment #: Node ID self.nid = nid #: Radius self.R = R self.z = z #: local SPC constraint self.ps = ps
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a RINGAX card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ nid = integer(card, 1, 'nid') blank(card, 2, 'blank') R = double(card, 3, 'R') z = double(card, 4, 'z') blank(card, 5, 'blank') blank(card, 6, 'blank') ps = integer_or_blank(card, 7, 'ps') assert len(card) <= 8, f'len(RINGAX card) = {len(card):d}\ncard={card}' return RINGAX(nid, R, z, ps, comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a RINGAX card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ nid = data[0] R = data[1] z = data[2] ps = data[3] assert len(data) == 4, data return RINGAX(nid, R, z, ps, comment=comment)
[docs] def raw_fields(self): """ Gets the fields in their unmodified form Returns ------- fields : list[varies] the fields that define the card """ list_fields = ['RINGAX', self.nid, None, self.R, self.z, None, None, self.ps] return list_fields
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: """ The writer method used by BDF.write_card() Parameters ----------- size : int; default=8 the size of the card (8/16) """ card = self.repr_fields() if size == 8: return self.comment + print_card_8(card) return self.comment + print_card_16(card)
[docs] class CCONEAX(Element): """ +---------+-----+-----+----+----+ | 1 | 2 | 3 | 4 | 5 | +=========+=====+=====+====+====+ | CCONEAX | EID | PID | N1 | N2 | +---------+-----+-----+----+----+ """ type = 'CCONEAX' _field_map = { 1: 'eid', 2:'pid', }
[docs] @classmethod def _init_from_empty(cls): eid = 1 pid = 1 rings = [1, 2] return CCONEAX(eid, pid, rings, comment='')
def _update_field_helper(self, n, value): if n == 3: self.nodes[0] = value elif n == 4: self.nodes[1] = value else: raise KeyError('Field %r=%r is an invalid %s entry.' % (n, value, self.type)) def __init__(self, eid, pid, rings, comment=''): """ Creates a CCONEAX card Parameters ---------- eid : int element id pid : int property id (PCONEAX) nids : list[int, int] node ids comment : str; default='' a comment for the card """ Element.__init__(self) if comment: self.comment = comment self.eid = eid self.pid = pid #self.nodes = self.prepare_node_ids(nids) self.rings = rings assert len(self.rings) == 2, rings self.rings_ref = None self.pid_ref = None self.rings_ref = None
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a CCONEAX 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, 'n1'), integer(card, 4, 'n2')] assert len(card) == 5, 'len(CROD card) = %i\ncard=%s' % (len(card), str(card)) return CCONEAX(eid, pid, nids, comment=comment)
@property def nodes(self): return self.rings @property def node_ids(self): return self.ring_ids @property def ring_ids(self): if self.rings_ref is not None: raise NotImplementedError(self.rings_ref) return self.rings
[docs] def cross_reference(self, model: BDF) -> None: msg = ', which is required by CCONEAX eid=%s' % (self.eid) #self.rings_ref self.pid_ref = model.Property(self.pid, msg=msg)
[docs] def safe_cross_reference(self, model: BDF, xref_errors): msg = ', which is required by CCONEAX eid=%s' % (self.eid) #self.rings_ref 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.pid = self.Pid() self.pid_ref = None self.rings_ref = None
[docs] def raw_fields(self): list_fields = ['CCONEAX', self.eid, self.Pid()] + self.ring_ids return list_fields
[docs] def repr_fields(self): return self.raw_fields()
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: card = self.raw_fields() return self.comment + print_card_8(card)
[docs] class PCONEAX(Property): """ +---------+-------+--------+------+-------+-------+-------+-------+-------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +=========+=======+========+======+=======+=======+=======+=======+=======+ | PCONEAX | ID | MID1 | T1 | MID2 | I | MID3 | T2 | NSM | +---------+-------+--------+------+-------+-------+-------+-------+-------+ | | Z1 | Z2 | PHIl | PHI2 | PHI3 | PHI4 | PHI5 | PHI6 | +---------+-------+--------+------+-------+-------+-------+-------+-------+ | | PHI7 | PHI8 | PHI9 | PHI10 | PHI11 | PHI12 | PHI13 | PHI14 | +---------+-------+--------+------+-------+-------+-------+-------+-------+ | PCONEAX | 2 | 4 | 1.0 | 6 | 16.3 | 8 | 2.1 | 0.5 | +---------+-------+--------+------+-------+-------+-------+-------+-------+ | | 0.001 | -0.002 | 23.6 | 42.9 | | | | | +---------+-------+--------+------+-------+-------+-------+-------+-------+ """ type = 'PCONEAX' _field_map = { 1: 'pid', 2:'mid1', 3:'t1', 4:'mid2', 5:'i', 6:'mid3', 7:'t2', 8: 'nsm', 9:'z1', 10:'z2', }
[docs] @classmethod def _init_from_empty(cls): pid = 1 mid1 = 1 return PCONEAX(pid, mid1, t1=None, mid2=0, i=None, mid3=None, t2=None, nsm=0., z1=None, z2=None, phi=None, comment='')
def _update_field_helper(self, n, value): if n <= 0: msg = 'Field %r=%r is an invalid %s entry.' % (n, value, self.type) raise KeyError(msg) self.phi[n - 10] = value def __init__(self, pid, mid1, t1=None, mid2=0, i=None, mid3=None, t2=None, nsm=0., z1=None, z2=None, phi=None, comment=''): """ Creates a PCONEAX Parameters ---------- pid : int PCONEAX property id for a CCONEAX. mid1 : int Membrane material id mid2 : int bending material id mid3 : int transverse shear material id t1 : float Membrane thickness. (Real > 0.0 if MID1 = 0) t2 : float Transverse shear thickness. (Real > 0.0 if MID3 = 0) I : float Moment of inertia per unit width. nsm : float Nonstructural mass per unit area. z1, z2 : float Fiber distances from the middle surface for stress recovery. phi : list[float] Azimuthal coordinates (in degrees) for stress recovery. comment : str; default='' a comment for the card """ Property.__init__(self) if comment: self.comment = comment if phi is None: phi = [] self.pid = pid self.mid1 = mid1 self.t1 = t1 self.mid2 = mid2 self.i = i self.mid3 = mid3 self.t2 = t2 self.nsm = nsm self.z1 = z1 self.z2 = z2 self.phi = phi self.mid1_ref = None self.mid2_ref = None self.mid3_ref = None
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a PCONEAX card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ #: Property ID pid = integer(card, 1, 'pid') #: Material ID mid1 = integer_or_blank(card, 2, 'mid1', 0) t1 = double_or_blank(card, 3, 't1') mid2 = integer_or_blank(card, 4, 'mid2', 0) if mid2 > 0: i = double(card, 5, 'i') assert i > 0.0 else: i = blank(card, 5, 'i') mid3 = integer_or_blank(card, 6, 'mid3', 0) if mid3 > 0: t2 = double(card, 7, 't3') assert t2 > 0.0 else: t2 = blank(card, 7, 't3') nsm = double_or_blank(card, 8, 'nsm', 0.0) z1 = double_or_blank(card, 9, 'z1', None) z2 = double_or_blank(card, 10, 'z2', None) j = 1 phi = [] for icard in range(11, len(card)): phii = double(card, icard, 'phi%i' % icard) phi.append(phii) j += 1 return PCONEAX(pid, mid1, t1, mid2, i, mid3, t2, nsm, z1, z2, phi, comment=comment)
[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 PCONEAX=%s' %(self.pid) if self.mid1 > 0: self.mid1_ref = model.Material(self.mid1, msg=msg) if self.mid2 > 0: self.mid2_ref = model.Material(self.mid2, msg=msg) if self.mid3 > 0: self.mid3_ref = model.Material(self.mid3, msg=msg)
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.mid1 = self.Mid1() self.mid2 = self.Mid2() self.mid3 = self.Mid3() self.mid1_ref = None self.mid2_ref = None self.mid3_ref = None
@property def mid_ref(self): return self.mid1_ref
[docs] def Mid1(self): if self.mid_ref is not None: return self.mid1_ref.mid return self.mid1
[docs] def Mid2(self): if self.mid2_ref is not None: return self.mid2_ref.mid return self.mid2
[docs] def Mid3(self): if self.mid3_ref is not None: return self.mid3_ref.mid return self.mid3
[docs] def Mids(self): return [self.Mid1(), self.Mid2(), self.Mid3()]
[docs] def raw_fields(self): list_fields = ['PCONEAX', self.pid, self.Mid1(), self.t1, self.Mid2(), self.i, self.Mid3(), self.t2, self.nsm, self.z1, self.z2] + self.phi return list_fields
[docs] def repr_fields(self): #nsm = set_blank_if_default(self.nsm, 0.0) mid1 = set_blank_if_default(self.Mid1(), 0) mid2 = set_blank_if_default(self.Mid2(), 0) mid3 = set_blank_if_default(self.Mid3(), 0) i = set_blank_if_default(self.i, 0.0) t1 = set_blank_if_default(self.t1, 0.0) t2 = set_blank_if_default(self.t2, 0.0) list_fields = ['PCONEAX', self.pid, mid1, t1, mid2, i, mid3, t2, self.nsm, self.z1, self.z2] + self.phi return list_fields
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: card = self.repr_fields() if size == 8: return self.comment + print_card_8(card) return self.comment + print_card_16(card)