Source code for pyNastran.bdf.cards.thermal.loads

# pylint: disable=R0902,R0904,R0914,C0111
from __future__ import annotations
from typing import TYPE_CHECKING
from pyNastran.utils.numpy_utils import integer_types
from pyNastran.bdf.field_writer_8 import print_card_8
from pyNastran.bdf.field_writer_16 import print_card_16
from pyNastran.bdf.field_writer_double import print_card_double
from pyNastran.bdf.cards.utils import wipe_empty_fields
from pyNastran.bdf.cards.thermal.thermal import ThermalCard
from pyNastran.bdf.field_writer_8 import set_blank_if_default
from pyNastran.bdf.cards.base_card import expand_thru, expand_thru_by, BaseCard
from pyNastran.bdf.cards.collpase_card import collapse_thru_by
from pyNastran.bdf.bdf_interface.assign_type import (
    integer, integer_or_blank, double, double_or_blank, integer_or_string,
    integer_double_or_blank, string, fields)
if TYPE_CHECKING:  # pragma: no cover
    from pyNastran.bdf.bdf import BDF


#class ThermalLoadDefault(ThermalCard):
    #def __init__(self, card, data):
        #ThermalCard.__init__(self)


[docs] class ThermalLoad(ThermalCard): def __init__(self): ThermalCard.__init__(self)
[docs] class QVOL(ThermalLoad): """ Defines a rate of volumetric heat addition in a conduction element. +------+------+------+---------+------+------+------+------+------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +======+======+======+=========+======+======+======+======+======+ | QVOL | SID | QVOL | CNTRLND | EID1 | EID2 | EID3 | EID4 | EID5 | +------+------+------+---------+------+------+------+------+------+ | | EID6 | etc. | | | | | | | +------+------+------+---------+------+------+------+------+------+ """ type = 'QVOL' _properties = ['element_ids']
[docs] @classmethod def _init_from_empty(cls): sid = 1 #flag = 'LINE' qvol = 1.0 control_point = 10 elements = [1, 2] return QVOL(sid, qvol, control_point, elements, comment='')
def __init__(self, sid, qvol, control_point, elements, comment=''): ThermalLoad.__init__(self) if comment: self.comment = comment #: Load set identification number. (Integer > 0) self.sid = sid self.qvol = qvol self.control_point = control_point if isinstance(elements, integer_types): elements = [elements] self.elements = elements self.elements_ref = None
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a QVOL card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ sid = integer(card, 1, 'sid') qvol = double(card, 2, 'qvol') control_point = integer_or_blank(card, 3, 'control_id', default=0) i = 1 eids = [] for ifield in range(4, len(card)): eid = integer_or_string(card, ifield, 'eid_%d' % i) eids.append(eid) i += 1 elements = expand_thru_by(eids) return QVOL(sid, qvol, control_point, elements, comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a QVOL card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ sid, qvol, control_point, eid = data return QVOL(sid, qvol, control_point, eid, comment=comment)
[docs] def get_loads(self): return [self]
[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 QVOL sid=%s' % self.sid self.elements_ref = model.Elements(self.elements, msg=msg)
[docs] def safe_cross_reference(self, model: BDF, xref_errors): try: return self.cross_reference(model) except KeyError: model.log.warning('failed cross-referencing\n%s' % str(self)) raise
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.elements = self.element_ids self.elements_ref = None
@property def element_ids(self): if self.elements_ref is None: return self.elements eids = [] for eid_ref in self.elements_ref: eids.append(eid_ref.eid) return eids
[docs] def Eids(self): return self.element_ids
[docs] def raw_fields(self): list_fields = ['QVOL', self.sid, self.qvol, self.control_point] + self.element_ids return list_fields
[docs] def repr_fields(self): eids = collapse_thru_by(self.element_ids) list_fields = ['QVOL', self.sid, self.qvol, self.control_point] + eids 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) if is_double: return self.comment + print_card_double(card) return self.comment + print_card_16(card)
[docs] class QVECT(ThermalLoad): """ Thermal Vector Flux Load Defines thermal vector flux from a distant source into a face of one or more CHBDYi boundary condition surface elements. +-------+------+------+-------+-----+---------+---------+---------+---------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +=======+======+======+=======+=====+=========+=========+=========+=========+ | QVECT | SID | Q0 | TSOUR | CE | E1/TID1 | E2/TID2 | E3/TID3 | CNTRLND | +-------+------+------+-------+-----+---------+---------+---------+---------+ | | EID1 | EID2 | etc. | | | | | | +-------+------+------+-------+-----+---------+---------+---------+---------+ """ type = 'QVECT' _properties = ['element_ids']
[docs] @classmethod def _init_from_empty(cls): sid = 1 q0 = 1.0 eids = [1, 2] return QVECT(sid, q0, eids, t_source=None, ce=0, vector_tableds=None, control_id=0, comment='')
def __init__(self, sid, q0, eids, t_source=None, ce=0, vector_tableds=None, control_id=0, comment=''): """ Creates a QVECT card Parameters ---------- sid : int Load set identification number. (Integer > 0) q0 : float; default=None Magnitude of thermal flux vector into face t_source : float; default=None Temperature of the radiant source ce : int; default=0 Coordinate system identification number for thermal vector flux vector_tableds : list[int/float, int/float, int/float] vector : float; default=None directional cosines in coordinate system CE) of the thermal vector flux None : [0.0, 0.0, 0.0] tabled : int TABLEDi entry identification numbers defining the components as a function of time control_id : int; default=0 Control point eids : list[int] or THRU Element identification number of a CHBDYE, CHBDYG, or CHBDYP entry comment : str; default='' a comment for the card """ ThermalLoad.__init__(self) if comment: self.comment = comment #: Load set identification number. (Integer > 0) self.sid = sid self.q0 = q0 self.t_source = t_source self.ce = ce self.control_id = control_id if vector_tableds is None: self.vector_tableds = [0., 0., 0.] else: self.vector_tableds = vector_tableds self.eids = eids self.eids_ref = None
[docs] def validate(self): assert isinstance(self.eids, list), 'type(eids)=%s' % type(self.eids)
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a QVECT card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ sid = integer(card, 1, 'sid') q0 = double(card, 2, 'q0') t_source = double_or_blank(card, 3, 't_source') ce = integer_or_blank(card, 4, 'ce', 0) vector_tableds = [ integer_double_or_blank(card, 5, 'e1_tabled1', default=0.0), integer_double_or_blank(card, 6, 'e2_tabled2', default=0.0), integer_double_or_blank(card, 7, 'e3_tabled3', default=0.0), ] control_id = integer_or_blank(card, 8, 'control_id', default=0) i = 1 eids = [] for ifield in range(9, len(card)): eid = integer_or_string(card, ifield, 'eid_%d' % i) eids.append(eid) assert eid != 0, card i += 1 elements = expand_thru_by(eids) return QVECT(sid, q0, elements, t_source=t_source, ce=ce, vector_tableds=vector_tableds, control_id=control_id, comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a QVECT card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ (sid, q0, t_source, ce, flag1, e1, flag2, e2, flag3, e3, cntrlnd, eid) = data vector_tableds = [e1, e2, e3] flags = [flag1, flag2, flag3] es = [e1, e2, e3] # flags = [2, 2, 2] # e = [-1.0, 0., 0.] # QVECT 90 1260.0 0 -1.0 0. 0. 88 # 201 THRU 218 assert flag1 in [0, 2], (sid, flags, es) assert flag2 in [0, 2], (sid, flags, es) assert flag3 in [0, 2], (sid, flags, es) elements = [eid] obj = QVECT(sid, q0, elements, t_source=t_source, ce=ce, vector_tableds=vector_tableds, control_id=cntrlnd, comment='') return obj
[docs] def get_loads(self): return [self]
[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 QVECT sid=%s' % self.sid self.eids_ref = model.Elements(self.eids, msg=msg)
[docs] def safe_cross_reference(self, model: BDF, xref_errors): try: return self.cross_reference(model) except KeyError: model.log.warning('failed cross-referencing\n%s' % str(self))
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.eids = self.element_ids self.eids_ref = None
@property def element_ids(self): if self.eids_ref is None: return self.eids eids = [] for eid_ref in self.eids_ref: eids.append(eid_ref.eid) return eids
[docs] def Eids(self): return self.element_ids
[docs] def raw_fields(self): list_fields = [ 'QVECT', self.sid, self.q0, self.t_source, self.ce ] + self.vector_tableds + [self.control_id] + self.element_ids return list_fields
[docs] def repr_fields(self): eids = collapse_thru_by(self.element_ids) list_fields = [ 'QVECT', self.sid, self.q0, self.t_source, self.ce ] + self.vector_tableds + [self.control_id] + eids 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) if is_double: return self.comment + print_card_double(card) return self.comment + print_card_16(card)
[docs] class QBDY1(ThermalLoad): """ Defines a uniform heat flux into CHBDYj elements. """ type = 'QBDY1' _properties = ['element_ids']
[docs] @classmethod def _init_from_empty(cls): sid = 1 qflux = 1.0 eids = [1, 2] return QBDY1(sid, qflux, eids, comment='')
def __init__(self, sid, qflux, eids, comment=''): ThermalLoad.__init__(self) if comment: self.comment = comment #: Load set identification number. (Integer > 0) self.sid = sid #: Heat flux into element (FLOAT) self.qflux = qflux #: CHBDYj element identification numbers (Integer) #: .. todo:: use expand_thru_by ??? assert len(eids) > 0 self.eids = expand_thru(eids) self.eids_ref = None
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a QBDY1 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ sid = integer(card, 1, 'sid') qflux = double(card, 2, 'qflux') eids = [] j = 1 for i in range(3, len(card)): eid = integer_or_string(card, i, 'eid%i' % j) eids.append(eid) j += 1 return QBDY1(sid, qflux, eids, comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a QBDY1 card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ sid = data[0] qflux = data[1] eids = data[2:] return QBDY1(sid, qflux, eids, comment=comment)
[docs] def get_loads(self): return [self]
[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 QBDY1 sid=%s' % self.sid self.eids_ref = model.Elements(self.eids, msg=msg)
[docs] def safe_cross_reference(self, model: BDF, xref_errors): try: return self.cross_reference(model) except KeyError: model.log.warning('failed cross-referencing\n%s' % str(self))
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.eids = self.element_ids self.eids_ref = None
[docs] def nQFluxTerms(self): return len(self.qflux)
@property def element_ids(self): if self.eids_ref is None: return self.eids eids = [] for eid_ref in self.eids_ref: eids.append(eid_ref.eid) return eids
[docs] def Eids(self): return self.element_ids
[docs] def raw_fields(self): list_fields = ['QBDY1', self.sid, self.qflux] + self.element_ids return list_fields
[docs] def repr_fields(self): eids = collapse_thru_by(self.element_ids) list_fields = ['QBDY1', self.sid, self.qflux] + eids 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) if is_double: return self.comment + print_card_double(card) return self.comment + print_card_16(card)
[docs] class QBDY2(ThermalLoad): # not tested """ Defines a uniform heat flux load for a boundary surface. """ type = 'QBDY2'
[docs] @classmethod def _init_from_empty(cls): sid = 1 eids = [1] qflux = [1.0] return QBDY2(sid, qflux, eids, comment='')
def __init__(self, sid, eid, qfluxs, comment=''): ThermalLoad.__init__(self) if comment: self.comment = comment #: Load set identification number. (Integer > 0) self.sid = sid #: Identification number of an CHBDYj element. (Integer > 0) self.eid = eid #: Heat flux at the i-th grid point on the referenced CHBDYj #: element. (Real or blank) if isinstance(qfluxs, float): qfluxs = [qfluxs] self.qfluxs = qfluxs self.eid_ref = None
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a QBDY2 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ sid = integer(card, 1, 'sid') eid = integer(card, 2, 'eid') qfluxs = [] j = 1 for i in range(3, len(card)): q = double_or_blank(card, i, 'qFlux%d' % j) qfluxs.append(q) j += 1 assert len(qfluxs) > 0, qfluxs qfluxs = wipe_empty_fields(qfluxs) return QBDY2(sid, eid, qfluxs, comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a QBDY2 card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ sid = data[0] eid = data[1] qfluxs = [data[2]] return QBDY2(sid, eid, qfluxs, comment=comment)
[docs] def get_loads(self): return [self]
[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 QBDY2 sid=%s' % self.sid self.eid_ref = model.Element(self.eid, msg=msg)
[docs] def safe_cross_reference(self, model: BDF, xref_errors): try: return self.cross_reference(model) except KeyError: model.log.warning('failed cross-referencing\n%s' % str(self))
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.eid = self.Eid() self.eid_ref = None
[docs] def Eid(self): if self.eid_ref is not None: return self.eid_ref.eid return self.eid
[docs] def nQFluxTerms(self): return len(self.qfluxs)
[docs] def raw_fields(self): list_fields = ['QBDY2', self.sid, self.Eid()] + self.qfluxs 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.repr_fields() if size == 8: return self.comment + print_card_8(card) if is_double: return self.comment + print_card_double(card) return self.comment + print_card_16(card)
[docs] class QBDY3(ThermalLoad): """ Defines a uniform heat flux load for a boundary surface. """ type = 'QBDY3' _properties = ['element_ids']
[docs] @classmethod def _init_from_empty(cls): sid = 1 q0 = 1.0 cntrlnd = 10 eids = [1, 2] return QBDY3(sid, q0, cntrlnd, eids, comment='')
def __init__(self, sid, q0, cntrlnd, eids, comment=''): """ Creates a QBDY3 card Parameters ---------- sid : int Load set identification number. (Integer > 0) q0 : float; default=None Magnitude of thermal flux vector into face control_id : int; default=0 Control point eids : list[int] or THRU Element identification number of a CHBDYE, CHBDYG, or CHBDYP entry comment : str; default='' a comment for the card """ ThermalLoad.__init__(self) if comment: self.comment = comment #: Load set identification number. (Integer > 0) self.sid = sid #: Heat flux into element self.q0 = q0 #: Control point for thermal flux load. (Integer > 0; Default = 0) self.cntrlnd = cntrlnd #: CHBDYj element identification numbers self.eids = expand_thru_by(eids) self.eids_ref = None
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a QBDY3 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ sid = integer(card, 1, 'sid') q0 = double(card, 2, 'q0') cntrlnd = integer_or_blank(card, 3, 'cntrlnd', default=0) nfields = card.nfields eids = fields(integer_or_string, card, 'eid', i=4, j=nfields) return QBDY3(sid, q0, cntrlnd, eids, comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a QBDY3 card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ sid = data[0] q0 = data[1] cntrlnd = data[2] eids = list(data[3:]) return QBDY3(sid, q0, cntrlnd, eids, 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 QBDY3 sid=%s' % self.sid eids = [] for eid in self.eids: eids.append(model.Element(eid, msg=msg)) self.eids_ref = eids
[docs] def safe_cross_reference(self, model: BDF, xref_errors): try: return self.cross_reference(model) except KeyError: model.log.warning('failed cross-referencing\n%s' % str(self))
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.eids = self.element_ids self.eids_ref = None
@property def element_ids(self): if self.eids_ref is None: return self.eids eids = [] for eid_ref in self.eids_ref: eids.append(eid_ref.eid) return eids
[docs] def Eids(self): return self.element_ids
[docs] def raw_fields(self): eids = self.element_ids eids.sort() list_fields = (['QBDY3', self.sid, self.q0, self.cntrlnd] + collapse_thru_by(eids)) return list_fields
[docs] def repr_fields(self): cntrlnd = set_blank_if_default(self.cntrlnd, 0) eids = self.element_ids eids.sort() list_fields = ['QBDY3', self.sid, self.q0, cntrlnd] + collapse_thru_by(eids) return list_fields
[docs] def get_loads(self): return [self]
[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) if is_double: return self.comment + print_card_double(card) return self.comment + print_card_16(card)
[docs] class QHBDY(ThermalLoad): """ Defines a uniform heat flux into a set of grid points. """ type = 'QHBDY' _properties = ['flag_to_nnodes'] flag_to_nnodes = { 'POINT' : (1, 1), 'LINE' : (2, 2), 'REV' : (2, 2), 'AREA3' : (3, 3), 'AREA4' : (4, 4), 'AREA6' : (4, 6), # 4-6 'AREA8' : (5, 8), # 5-8 }
[docs] @classmethod def _init_from_empty(cls): sid = 1 flag = 'LINE' q0 = 1.0 grids = [1, 2] return QHBDY(sid, flag, q0, grids, af=None, comment='')
def __init__(self, sid, flag, q0, grids, af=None, comment=''): """ Creates a QHBDY card Parameters ---------- sid : int load id flag : str valid_flags = {POINT, LINE, REV, AREA3, AREA4, AREA6, AREA8} q0 : float Magnitude of thermal flux into face. Q0 is positive for heat into the surface af : float; default=None Area factor depends on type grids : list[int] Grid point identification of connected grid points comment : str; default='' a comment for the card """ ThermalLoad.__init__(self) if comment: self.comment = comment #: Load set identification number. (Integer > 0) self.sid = sid self.flag = flag #: Magnitude of thermal flux into face. Q0 is positive for heat #: into the surface. (Real) self.q0 = q0 #: Area factor depends on type. (Real > 0.0 or blank) self.af = af #: Grid point identification of connected grid points. #: (Integer > 0 or blank) self.grids = grids assert flag in ['POINT', 'LINE', 'REV', 'AREA3', 'AREA4', 'AREA6', 'AREA8'], str(self)
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a QHBDY card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ sid = integer(card, 1, 'eid') flag = string(card, 2, 'flag') q0 = double(card, 3, 'q0') af = double_or_blank(card, 4, 'af') nnodes_required, nnodes_max = cls.flag_to_nnodes[flag] grids = [] if nnodes_required == nnodes_max: for i in range(nnodes_required): grid = integer(card, 5 + i, 'grid%i' % (i + 1)) grids.append(grid) else: int_node_count = 0 for i in range(nnodes_max): grid = integer_or_blank(card, 5 + i, 'grid%i' % (i + 1)) if grid is not None: int_node_count += 1 grids.append(grid) if int_node_count < nnodes_required: msg = 'int_node_count=%s nnodes_required=%s' % (int_node_count, nnodes_required) raise RuntimeError(msg) return QHBDY(sid, flag, q0, grids, af=af, comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a QHBDY card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ sid = data[0] flag_int = data[1] q0 = data[2] af = data[3] grids = list(data[4:]) if flag_int == 1: flag = 'POINT' nnodes = 1 elif flag_int == 2: flag = 'LINE' nnodes = 2 elif flag_int == 3: flag = 'REV' nnodes = 2 elif flag_int == 5: flag = 'AREA4' nnodes = 4 elif flag_int == 9: flag = 'AREA8' nnodes = 8 else: # pragma: no cover raise NotImplementedError(f'QHBDY sid={sid} flag_int={flag_int} data={data[2:]}') grids2 = grids[:nnodes] #print(sid, flag_int, flag, q0, af, grids, grids2) return QHBDY(sid, flag, q0, grids2, af=af, comment=comment)
[docs] def get_loads(self): return [self]
[docs] def cross_reference(self, model: BDF) -> None: pass
[docs] def safe_cross_reference(self, model: BDF, xref_errors): try: return self.cross_reference(model) except KeyError: model.log.warning('failed cross-referencing\n%s' % str(self))
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" pass
[docs] def raw_fields(self): list_fields = ['QHBDY', self.sid, self.flag, self.q0, self.af] + self.grids 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.repr_fields() if size == 8: return self.comment + print_card_8(card) if is_double: return self.comment + print_card_double(card) return self.comment + print_card_16(card)
[docs] class TEMPRB(ThermalLoad): """ +--------+-----+----+-------+----+-------+----+----+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | +========+=====+====+=======+====+=======+====+====+ | TEMPRB | SID | G1 | T1 | G2 | T2 | G3 | T3 | +--------+-----+----+-------+----+-------+----+----+ +--------+------+------+------+------+------+------+------+------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +========+======+======+======+======+======+======+======+======+ | TEMPRB | SID | EID1 | TA | TB | TP1A | TP1B | TP2A | TP2B | +--------+------+------+------+------+------+------+------+------+ | | TCA | TDA | TEA | TFA | TCB | TDB | TEB | TFB | +--------+------+------+------+------+------+------+------+------+ | | EID2 | EID3 | EID4 | EID5 | EID6 | EID7 | etc. | | +--------+------+------+------+------+------+------+------+------+ | TEMPRB | 200 | 1 | 68.0 | 23.0 | 0.0 | 28.0 | 2.5 | | +--------+------+------+------+------+------+------+------+------+ | | 68.0 | 91.0 | 45.0 | 48.0 | 80.0 | 20.0 | | | +--------+------+------+------+------+------+------+------+------+ | | 9 | 10 | | | | | | | +--------+------+------+------+------+------+------+------+------+ """ type = 'TEMPRB'
[docs] @classmethod def _init_from_empty(cls): sid = 1 eids = [1] ta = 1.0 tb = 1.0 tp1 = [1.0, 1.0] tp2 = [1.0, 1.0] tai = [1.0, 1.0, 1.0, 1.0] tbi = [1.0, 1.0, 1.0, 1.0] return TEMPRB(sid, ta, tb, tp1, tp2, tai, tbi, eids, comment='')
#@classmethod #def export_to_hdf5(cls, h5_file, model, loads): #"""exports the loads in a vectorized way""" ##encoding = model._encoding ##comments = [] #unused_sid = loads[0].sid ##h5_file.create_dataset('sid', data=sid) #for i, load in enumerate(loads): #sub_group = h5_file.create_group(str(i)) ##comments.append(loads.comment) #node = [] #temp = [] #for nid, tempi in load.temperatures.items(): #node.append(nid) #temp.append(tempi) #sub_group.create_dataset('node', data=node) #sub_group.create_dataset('temperature', data=temp) #h5_file.create_dataset('_comment', data=comments) def __init__(self, sid, ta, tb, tp1, tp2, tai, tbi, eids, comment=''): """ Creates a TEMPRB card Parameters ---------- sid : int Load set identification number comment : str; default='' a comment for the card """ ThermalLoad.__init__(self) if comment: self.comment = comment #: Load set identification number. (Integer > 0) self.sid = sid # temperatures at end A/B self.ta = ta self.tb = tb # gradients at A/B self.tp1 = tp1 self.tp2 = tp2 # temperatures at points C/D/E/F at A/B self.tai = tai self.tbi = tbi self.eids = eids
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a TEMPRB card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ sid = integer(card, 1, 'sid') #TEMPRB SID EID1 TA TB TP1A TP1B TP2A TP2B #TCA TDA TEA TFA TCB TDB TEB TFB #EID2 EID3 EID4 EID5 EID6 EID7 -etc.- #TEMPRB 200 1 68.0 23.0 0.0 28.0 2.5 #68.0 91.0 45.0 48.0 80.0 20.0 #9 10 ##+========+======+======+======+======+======+======+======+======+ ##| TEMPRB | SID | EID1 | TA | TB | TP1A | TP1B | TP2A | TP2B | ##| | TCA | TDA | TEA | TFA | TCB | TDB | TEB | TFB | ##| | EID2 | EID3 | EID4 | EID5 | EID6 | EID7 | etc. | | ##+--------+------+------+------+------+------+------+------+------+ eid1 = integer(card, 2, 'EID1') # TODO: the default for MSC is 0.0 ta = double(card, 3, 'T(A)') tb = double(card, 4, 'T(B)') tp1a = double_or_blank(card, 5, 'TP1(A)') tp1b = double_or_blank(card, 6, 'TP1(B)') tp2a = double_or_blank(card, 7, 'TP2(A)') tp2b = double_or_blank(card, 8, 'TP2(B)') tp1 = [tp1a, tp1b] tp2 = [tp2a, tp2b] # TODO: the default for MSC is TA tca = double_or_blank(card, 9, 'TC(A)') tda = double_or_blank(card, 10, 'TD(A)') tea = double_or_blank(card, 11, 'TE(A)') tfa = double_or_blank(card, 12, 'TF(A)') # TODO: the default for MSC is TB tcb = double_or_blank(card, 13, 'TC(B)') tdb = double_or_blank(card, 14, 'TD(B)') teb = double_or_blank(card, 15, 'TE(B)') tfb = double_or_blank(card, 16, 'TF(B)') eids = [eid1] nfields = len(card) #assert nfields <= 16, 'len(card)=%i card=%s' % (len(card), card) for ifield in range(17, nfields): eid = integer(card, ifield, f'eid{ifield-15}') eids.append(eid) tai = [tca, tda, tea, tfa] tbi = [tcb, tdb, teb, tfb] return TEMPRB(sid, ta, tb, tp1, tp2, tai, tbi, eids, comment=comment)
[docs] def cross_reference(self, model: BDF) -> None: pass
[docs] def safe_cross_reference(self, model: BDF, debug=True): pass
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" pass
[docs] def raw_fields(self): """Writes the TEMPRB card""" eid = self.eids[0] list_fields = [ 'TEMPRB', self.sid, eid, self.ta, self.tb, self.tp1[0], self.tp1[1], self.tp2[0], self.tp2[1], ] + self.tai + self.tbi + self.eids[1:] return list_fields
[docs] def repr_fields(self): """Writes the TEMPRB card""" return self.raw_fields()
[docs] def get_loads(self): return [self]
[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) if is_double: return self.comment + print_card_double(card) return self.comment + print_card_16(card)
[docs] class TEMP(ThermalLoad): """ Defines temperature at grid points for determination of thermal loading, temperature-dependent material properties, or stress recovery. +------+-----+----+-------+----+-------+----+----+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | +======+=====+====+=======+====+=======+====+====+ | TEMP | SID | G1 | T1 | G2 | T2 | G3 | T3 | +------+-----+----+-------+----+-------+----+----+ | TEMP | 3 | 94 | 316.2 | 49 | 219.8 | | | +------+-----+----+-------+----+-------+----+----+ """ type = 'TEMP'
[docs] @classmethod def _init_from_empty(cls): sid = 1 temperatures = {1 : 1.0} return TEMP(sid, temperatures, comment='')
[docs] @classmethod def export_to_hdf5(cls, h5_file, model, loads): """exports the loads in a vectorized way""" #encoding = model._encoding #comments = [] unused_sid = loads[0].sid #h5_file.create_dataset('sid', data=sid) for i, load in enumerate(loads): sub_group = h5_file.create_group(str(i)) #comments.append(loads.comment) node = [] temp = [] for nid, tempi in load.temperatures.items(): node.append(nid) temp.append(tempi) sub_group.create_dataset('node', data=node) sub_group.create_dataset('temperature', data=temp)
#h5_file.create_dataset('_comment', data=comments) def __init__(self, sid, temperatures, comment=''): """ Creates a TEMP card Parameters ---------- sid : int Load set identification number temperatures : dict[nid] : temperature nid : int node id temperature : float the nodal temperature comment : str; default='' a comment for the card """ ThermalLoad.__init__(self) if comment: self.comment = comment #: Load set identification number. (Integer > 0) self.sid = sid #: dictionary of temperatures where the key is the grid ID (Gi) #: and the value is the temperature (Ti) self.temperatures = temperatures
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a TEMP card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ sid = integer(card, 1, 'sid') nfields = len(card) assert nfields <= 8, 'len(card)=%i card=%s' % (len(card), card) ntemps = (nfields -2) // 2 assert nfields % 2 == 0, card assert nfields // 2 > 1, card temperatures = {} for i in range(ntemps): n = i * 2 + 2 gi = integer(card, n, 'g' + str(i)) temperaturei = double(card, n + 1, 'T' + str(i)) temperatures[gi] = temperaturei return TEMP(sid, temperatures, comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a TEMP card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ sid = data[0] temperatures = {data[1]: data[2]} return TEMP(sid, temperatures, comment=comment)
[docs] def add(self, temp_obj): assert self.sid == temp_obj.sid for (gid, temp) in temp_obj.temperatures.items(): self.temperatures[gid] = temp
[docs] def cross_reference(self, model: BDF) -> None: pass
[docs] def safe_cross_reference(self, model: BDF, debug=True): pass
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" pass
[docs] def raw_fields(self): """Writes the TEMP card""" list_fields = ['TEMP', self.sid] ntemps = len(self.temperatures) - 1 for i, (gid, temp) in enumerate(sorted(self.temperatures.items())): list_fields += [gid, temp] if i % 3 == 2 and ntemps > i: # start a new TEMP card list_fields += [None, 'TEMP', self.sid] return list_fields
[docs] def repr_fields(self): """Writes the TEMP card""" return self.raw_fields()
[docs] def get_loads(self): return [self]
def __repr__(self) -> str: try: return self.write_card(size=8) except Exception: try: return self.write_card(size=16) except Exception: print('problem printing %s card' % self.type) raise
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: if size == 8: print_card_ = print_card_8 elif is_double: print_card_ = print_card_double else: print_card_ = print_card_16 list_fields = ['TEMP', self.sid] ntemps = len(self.temperatures) - 1 msg = self.comment msgs = [] if msg: msgs.append(msg) for i, (gid, temp) in enumerate(sorted(self.temperatures.items())): list_fields += [gid, temp] if i % 3 == 2 and ntemps > i: # start a new TEMP card msgs.append(print_card_(list_fields)) list_fields = ['TEMP', self.sid] if len(list_fields) > 2: msgs.append(print_card_(list_fields)) out = ''.join(msgs) return out
[docs] class TEMPP1(BaseCard): """ +--------+------+------+------+--------+------+------+------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | +========+======+======+======+========+======+======+======+ | TEMPP1 | SID | EID1 | TBAR | TPRIME | T1 | T2 | | +--------+------+------+------+--------+------+------+------+ | | EID2 | EID3 | EID4 | EID5 | EID6 | EID7 | etc. | +--------+------+------+------+--------+------+------+------+ +--------+------+------+------+--------+------+------+------+ | TEMPP1 | 2 | 24 | 62.0 | 10.0 | 57.0 | 67.0 | | +--------+------+------+------+--------+------+------+------+ | | 26 | 21 | 19 | 30 | | | | +--------+------+------+------+--------+------+------+------+ Alternate Form +--------+------+------+------+--------+------+------+------+ | | EID2 | THRU | EIDi | EIDj | THRU | EIDk | | +--------+------+------+------+--------+------+------+------+ | | 1 | THRU | 10 | 30 | THRU | 61 | | +--------+------+------+------+--------+------+------+------+ """ type = 'TEMPP1'
[docs] @classmethod def _init_from_empty(cls): sid = 1 eid = 1 tbar = 2.0 tprime = 1.0 t_stress = 10. return TEMPP1(sid, eid, tbar, tprime, t_stress, comment='')
def __init__(self, sid, eid, tbar, tprime, t_stress, comment=''): BaseCard.__init__(self) self.comment = comment self.sid = sid self.eid = eid self.tbar = tbar self.tprime = tprime self.t_stress = t_stress @classmethod def add_op2_data(cls, data, comment=''): """ Adds a TEMPP1 card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ sid, eid, t, tprime, ts1, ts2 = data return TEMPP1(sid, eid, t, tprime, [ts1, ts2], comment=comment)
[docs] def raw_fields(self): """Writes the TEMP card""" list_fields = ['TEMPP1', self.sid, self.eid, self.tbar] + self.t_stress return list_fields
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: list_fields = ['TEMPP1', self.sid, self.eid, self.tbar] + self.t_stress return print_card_8(list_fields)
[docs] class TEMPB3(BaseCard): """ +--------+--------+--------+--------+-------+-------+--------+--------+--------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +========+========+========+========+=======+=======+========+========+========+ | TEMPB3 | SID | EID | T(A) | T(B) | T(C) | TPY(A) | TPZ(A) | TPY(B) | +--------+--------+--------+--------+-------+-------+--------+--------+--------+ | | TPZ(B) | TPY(C) | TPZ(C) | TC(A) | TD(A) | TE(A) | TF(A) | TC(B) | +--------+--------+--------+--------+-------+-------+--------+--------+--------+ | | TD(B) | TE(B) | TF(B) | TC(C) | TD(C) | TE(C) | TF(C) | | +--------+--------+--------+--------+-------+-------+--------+--------+--------+ | | Element ID List +--------+--------+--------+--------+-------+-------+--------+--------+--------+ """ type = 'TEMPB3'
[docs] @classmethod def _init_from_empty(cls): sid = 1 eid = 1 t = [0., 0., 0.] tpy = [0., 0., 0.] tpz = [0., 0., 0.] tc = [0., 0., 0.] td = [0., 0., 0.] te = [0., 0., 0.] tf = [0., 0., 0.] eids = [1, 2] return TEMPB3(sid, eid, t, tpy, tpz, tc, td, te, tf, eids, comment='')
def __init__(self, sid, eid, t, tpy, tpz, tc, td, te, tf, eids, comment=''): BaseCard.__init__(self) self.comment = comment self.sid = sid self.eid = eid self.t = t self.tpy = tpy self.tpz = tpz self.tc = tc self.td = td self.te = te self.tf = tf self.eids = eids assert len(eids) > 0, str(self) self.eid_ref = None self.eids_ref = None
[docs] @classmethod def add_card(cls, card, icard=0, comment=''): """ Adds a TEMPD card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object icard : int; default=0 sid to be parsed comment : str; default='' a comment for the card """ sid = integer(card, 1, 'sid') eid = integer(card, 2, 'eid') t = [] ifield = 3 for var in ['A', 'B', 'C']: ti = double_or_blank(card, ifield, 'T(%s)' % var, default=0.0) t.append(ti) ifield += 1 tpy = [] tpz = [] for var in ['A', 'B', 'C']: tpyi = double_or_blank(card, ifield, 'TPY(%s)' % var, default=0.0) tpzi = double_or_blank(card, ifield + 1, 'TPZ(%s)' % var, default=0.0) tpy.append(tpyi) tpz.append(tpzi) ifield += 2 tc = [] td = [] te = [] tf = [] for var in ['A', 'B', 'C']: tci = double_or_blank(card, ifield, 'TC(%s)' % var, default=0.0) tdi = double_or_blank(card, ifield + 1, 'TD(%s)' % var, default=0.0) tei = double_or_blank(card, ifield + 2, 'TE(%s)' % var, default=0.0) tfi = double_or_blank(card, ifield + 3, 'TF(%s)' % var, default=0.0) tc.append(tci) td.append(tdi) te.append(tei) tf.append(tfi) ifield += 4 ifield += 1 # skip the None list_fields = card[ifield:] eids = expand_thru_by(list_fields, set_fields=True, sort_fields=True, require_int=True, allow_blanks=False) return TEMPB3(sid, eid, t, tpy, tpz, tc, td, te, tf, eids, comment=comment)
[docs] def cross_reference(self, model: BDF) -> None: self.eid_ref = model.Element(self.eid) self.eids_ref = model.Elements(self.eids)
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.eid_ref = None self.eids_ref = None
[docs] def get_loads(self): return [self]
[docs] def raw_fields(self): """Writes the TEMP card""" list_fields = ['TEMPB3', self.sid, self.eid, ] + self.t for tpyi, tpzi in zip(self.tpy, self.tpz): list_fields.append(tpyi) list_fields.append(tpzi) for tci, tdi, tei, tfi in zip(self.tc, self.td, self.tf, self.tf): list_fields.append(tci) list_fields.append(tdi) list_fields.append(tei) list_fields.append(tfi) list_fields.append(None) list_fields += self.eids return list_fields
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: list_fields = self.raw_fields() return print_card_8(list_fields)
# Loads #------------------------------------------------------- # Default Loads
[docs] class TEMPD(BaseCard): """ Defines a temperature value for all grid points of the structural model that have not been given a temperature on a TEMP entry +-------+------+----+------+----+------+----+------+----+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +=======+======+====+======+====+======+====+======+====+ | TEMPD | SID1 | T1 | SID2 | T2 | SID3 | T3 | SID4 | T4 | +-------+------+----+------+----+------+----+------+----+ """ type = 'TEMPD'
[docs] @classmethod def _init_from_empty(cls): sid = 1 temperatures = {1 : 1.0} return TEMPD(sid, temperatures, comment='')
def __init__(self, sid, temperature, comment=''): """ Creates a TEMPD card Parameters ---------- sid : int Load set identification number. (Integer > 0) temperature : float default temperature comment : str; default='' a comment for the card """ BaseCard.__init__(self) if comment: self.comment = comment self.sid = sid self.temperature = temperature
[docs] @classmethod def add_card(cls, card, icard=0, comment=''): """ Adds a TEMPD card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object icard : int; default=0 sid to be parsed comment : str; default='' a comment for the card """ nfields = len(card) - 1 assert nfields % 2 == 0, 'card=%s' % card i = 2 * icard sid = integer(card, i + 1, 'sid') temperature = double(card, i + 2, 'temp') return TEMPD(sid, temperature, comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a TEMPD card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ sid = data[0] temperature = data[1] return TEMPD(sid, temperature, comment=comment)
[docs] def add(self, tempd_obj): for (lid, tempd) in tempd_obj.temperature.items(): self.temperature[lid] = tempd
[docs] def cross_reference(self, model: BDF) -> None: pass
[docs] def safe_cross_reference(self, model: BDF, xref_errors): pass
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" pass
[docs] def raw_fields(self): """Writes the TEMPD card""" list_fields = ['TEMPD', self.sid, self.temperature] return list_fields
[docs] def write_card(self, size: int=8, is_double: bool=False) -> str: card = self.raw_fields() if size == 8: return self.comment + print_card_8(card) if is_double: return self.comment + print_card_double(card) return self.comment + print_card_16(card)