Source code for pyNastran.bdf.cards.optimization

"""
All optimization cards are defined in this file.  This includes:

* dconstrs - DCONSTR
* dconadds - DCONADD
* ddvals - DDVAL
* dlinks - DLINK
* dresps - DRESP1, DRESP2, DRESP3
* dscreen - DSCREEN
* dvgrids - DVGRID
* desvars - DESVAR
* dvcrels - DVCREL1, DVCREL2
* dvmrels - DVMREL1, DVMREL2
* dvprels - DVPREL1, DVPREL2
* doptprm - DOPTPRM

some missing optimization flags
http://mscnastrannovice.blogspot.com/2014/06/msc-nastran-design-optimization-quick.html"""
# pylint: disable=C0103,R0902,R0904,R0914
from __future__ import annotations
from typing import Any, TYPE_CHECKING
from itertools import cycle, count
import numpy as np

from pyNastran.utils.numpy_utils import integer_types, float_types
from pyNastran.bdf.field_writer_8 import set_blank_if_default
from pyNastran.bdf.cards.base_card import (
    BaseCard, expand_thru_by, break_word_by_trailing_integer,
    break_word_by_trailing_parentheses_integer_ab)
from pyNastran.bdf.cards.deqatn import fortran_to_python_short
    #collapse_thru_by_float, condense, build_thru_float)
from pyNastran.bdf.cards.properties.beam import update_pbeam_negative_integer
from pyNastran.bdf.bdf_interface.assign_type import (
    integer, integer_or_blank, integer_or_string, integer_string_or_blank,
    double, double_or_blank, string, string_or_blank,
    integer_double_or_blank, integer_double_string_or_blank,
    double_string_or_blank, interpret_value, check_string, loose_string)
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 build_table_lines
if TYPE_CHECKING:  # pragma: no cover
    from pyNastran.bdf.bdf import BDF
    from pyNastran.bdf.bdf_interface.bdf_card import BDFCard

#TODO: replace this with formula
valid_pcomp_codes = [3, #3-z0
                     #'Z0',
                     # 13-t1, 14-theta1, 17-t2, 18-theta2
                     13, 14, 17, 18,
                     23, 24, 27, 28,
                     33, 34, 37, 38,
                     43, 44, 47, 48,
                     53, 54, 57, 58,
                     63, 64, 67, 68]

[docs] def validate_dvcrel(validate, element_type, cp_name): """ Valdiates the DVCREL1/2 .. note:: words that start with integers (e.g., 12I/T**3) doesn't support strings """ if not validate: return msg = 'DVCRELx: element_type=%r cp_name=%r is invalid' % (element_type, cp_name) if element_type == 'CMASS4': options = ['M'] _check_dvcrel_options(cp_name, element_type, options) elif element_type == 'CELAS4': options = ['K'] _check_dvcrel_options(cp_name, element_type, options) elif element_type in ['CQUAD4']: options = ['T1', 'T2', 'T3', 'T4'] # 'ZOFFS', _check_dvcrel_options(cp_name, element_type, options) elif element_type == 'CTRIA3': options = ['T1', 'T2', 'T3'] _check_dvcrel_options(cp_name, element_type, options) elif element_type == 'CONM2': options = ['M', 'X1', 'X2', 'X3'] _check_dvcrel_options(cp_name, element_type, options) elif element_type == 'CBAR': options = ['X1', 'X2', 'X3', 'W1A', 'W2A', 'W3A', 'W1B', 'W2B', 'W3B'] _check_dvcrel_options(cp_name, element_type, options) elif element_type == 'CBEAM': options = ['X1', 'X2', 'X3'] _check_dvcrel_options(cp_name, element_type, options) elif element_type in ['CELAS1']: options = [] _check_dvcrel_options(cp_name, element_type, options) elif element_type in ['CBUSH']: options = ['X1', 'X2', 'X3', 'S', 'S1', 'S2', 'S3'] _check_dvcrel_options(cp_name, element_type, options) elif element_type == 'CVISC': options = [] _check_dvcrel_options(cp_name, element_type, options) elif element_type == 'CGAP': options = [] _check_dvcrel_options(cp_name, element_type, options) elif element_type == 'CBUSH1D': options = [] _check_dvcrel_options(cp_name, element_type, options) else: raise NotImplementedError(msg)
[docs] def validate_dvmrel(validate, mat_type, mp_name): """ Valdiates the DVMREL1/2 .. note:: words that start with integers (e.g., 12I/T**3) doesn't support strings """ if not validate: return msg = 'DVMRELx: mat_type=%r mp_name=%r is invalid' % (mat_type, mp_name) if mat_type in ['MAT1']: assert mp_name in ['E', 'G', 'NU', 'GE', 'RHO', 'A', 'TREF'], msg elif mat_type == 'MAT2': assert mp_name in ['G11', 'G12', 'G22', 'G33', 'GE', 'RHO', 'A1', 'A2', 'A3', 'TREF'], msg elif mat_type == 'MAT3': assert mp_name in ['EX', 'ETH', 'EZ', 'NUTH', 'NUXTH', 'NUTHZ', 'NUZX', 'RHO'], msg elif mat_type == 'MAT8': assert mp_name in ['E1', 'E2', 'G12', 'G1Z', 'G2Z', 'NU12', 'RHO', 'A1', 'A2'], msg elif mat_type == 'MAT9': assert mp_name in ['G11', 'G22', 'G33', 'G44', 'G55', 'G66', 'RHO'], msg elif mat_type == 'MAT10': assert mp_name in ['BULK', 'RHO'], msg elif mat_type == 'MAT11': assert mp_name in ['E1', 'E2', 'E3', 'G12', 'G13', 'G23', 'RHO'], msg else: raise NotImplementedError(msg)
[docs] def validate_dvprel(prop_type, pname_fid, validate): """ Valdiates the DVPREL1/2 .. note:: words that start with integers (e.g., 12I/T**3) doesn't support strings .. note:: FID > 0 --> references the Property Card .. note:: FID < 0 --> references the EPT card """ if not validate: return pname_fid msg = 'DVPREL1: prop_type=%r pname_fid=%r is invalid' % (prop_type, pname_fid) #if prop_type == 'CELAS2': #assert pname_fid in ['K', 'GE', 'S'], msg #elif prop_type == 'CELAS4': #assert pname_fid in ['K'], msg if prop_type == 'PELAS': if pname_fid in ['K1', 3]: pname_fid = 'K1' elif pname_fid in ['GE1', 4]: pname_fid = 'GE1' elif pname_fid in ['S1', 5]: pname_fid = 'S1' else: raise NotImplementedError('PELAS pname_fid=%r is invalid' % pname_fid) elif prop_type == 'PELAST': if pname_fid in ['TKID', 3]: pname_fid = 'TKID' else: raise NotImplementedError('PELAST pname_fid=%r is invalid' % pname_fid) assert pname_fid in [3, 4, 'TKID'], msg elif prop_type == 'PROD': if pname_fid in ['A', 4]: pname_fid = 'A' elif pname_fid in ['J', 5]: pname_fid = 'J' #elif pname_fid in ['C', 6]: #pname_fid = 'C' elif pname_fid in ['NSM', 7]: pname_fid = 'NSM' else: raise NotImplementedError('PROD pname_fid=%r is invalid' % pname_fid) assert pname_fid in [4, 'A', 5, 'J', 'NSM'], msg elif prop_type == 'PTUBE': if pname_fid == 4: pname_fid = 'OD' elif pname_fid == 5: pname_fid = 'T' #options = [4, 5, 'T'] options = ['T', 'OD'] _check_dvprel_options(pname_fid, prop_type, options) #elif prop_type == 'CBAR': #assert pname_fid in ['X1', 'X2'], msg elif prop_type == 'PBAR': if pname_fid == 4: pname_fid = 'A' # I1 I2 J elif pname_fid == 5: pname_fid = 'I1' elif pname_fid == 6: pname_fid = 'I2' elif pname_fid == 7: pname_fid = 'J' #options = [4, 5, 6, 7, 12, 13, 14, 15, 16, 17, 18, 19, 'A', 'I1', 'J'] options = [12, 13, 14, 15, 16, 17, 18, 19, 'A', 'I1', 'I2', 'I12', 'J'] _check_dvprel_options(pname_fid, prop_type, options) elif prop_type == 'PBARL': if pname_fid in [12, 13, 14, 15, 16, 17, 18, 19]: # field 12 = DIM1 (10 values per line) iline = pname_fid // 10 ifield = pname_fid % 10 if ifield == 0 or ifield > 8: msg = 'iline=%s ifield=%s pname_fid=%s PBARL' % (iline, ifield, pname_fid) raise RuntimeError(msg) pname_fid = ('DIM%i' % (pname_fid - 11)) options = [ 12, 13, 14, 15, 16, 17, 'DIM1', 'DIM2', 'DIM3', 'DIM4', 'DIM5', 'DIM6', 'DIM7', 'DIM8', 'DIM9', 'DIM10'] _check_dvprel_options(pname_fid, prop_type, options) #elif prop_type == 'CBEAM': #assert pname_fid in ['X1', 'X2', 'X3', 'W1A', 'W2A', 'W3A', 'W1B', 'W2B', 'W3B'], msg elif prop_type == 'PBEAM': options_station_a = [ 'I1', 'I2', 'A', 'I12', 'J', 'C1', 'C2', 'D1', 'D2', 'E1', 'E2', 'F1', 'F2', #-8, -9, -10, -14, -15, -16, -17, -18, -19, -20, -21, #-168, -169, -170, -174, -175, -176, -177, -178, -179, #-180, -181, ] options = [ 'I1', 'I2', 'A', 'I12', 'J', 'I1(A)', 'I1(B)', 'I2(B)', 'C1', 'C2', 'D1', 'D2', 'E1', 'E2', 'F1', 'F2', #-8, -9, -10, -14, -15, -16, -17, -18, -19, -20, -21, #-168, -169, -170, -174, -175, -176, -177, -178, -179, #-180, -181, ] if isinstance(pname_fid, integer_types) and pname_fid < 0: pname_fid = update_pbeam_negative_integer(pname_fid) if isinstance(pname_fid, str): if pname_fid in options_station_a: word = pname_fid num = 'A' pname_fid = '%s(%s)' % (pname_fid, num) else: # A(1) word, num = break_word_by_trailing_parentheses_integer_ab( pname_fid) _check_dvprel_options(word, prop_type, options) elif prop_type == 'PBEAML': _dims = ['DIM1', 'DIM2', 'DIM3', 'DIM4', 'DIM5', 'DIM6', 'DIM7', 'DIM8', 'DIM9', 'DIM10',] _dimsa = [dim + '(A)' for dim in _dims] _dimsb = [dim + '(B)' for dim in _dims] options = _dims + _dimsa + _dimsb + [ 'I1(B)', 'I2(B)', 'NSM'] #options = [ #'DIM1', 'DIM2', 'DIM3', 'DIM4', 'DIM5', 'DIM6', 'DIM7', 'DIM8', 'DIM9', 'DIM10', #'DIM1(A)', 'DIM2(A)', 'DIM3(A)', 'DIM5(A)', 'DIM6(A)', 'DIM7(A)', 'DIM8(A)', 'DIM9(A)', 'DIM10(A)', #'DIM1(B)', 'DIM2(B)', ] # 'DIM(B)' _check_dvprel_options(pname_fid, prop_type, options) #elif prop_type == 'CQUAD4': #assert pname_fid in ['T1', 'T2', 'T3', 'T4'], msg elif prop_type == 'PSHELL': if pname_fid in ['T', 4]: pname_fid = 'T' elif pname_fid in [6]: # 12I/T**3 doesn't support strings pass elif pname_fid in [8]: # TS/T doesn't support strings? pass elif pname_fid in ['Z1', 12]: # TODO: is this right? # definitely not MID4... pname_fid = 'Z1' elif pname_fid in ['Z2', 13]: # TODO: is this right? # definitely not MID4... pname_fid = 'Z2' else: allowed = ("['T', 4, \n" "6 # 12I/T^3, \n" "8 # TS/T]\n") msg = 'PSHELL pname_fid=%r is invalid\nmust be in:\n%s' % (pname_fid, str(allowed)) raise NotImplementedError(msg) #if cp_name in '12I/T**3': #cp_name = #assert pname_fid in ['T', 4, 6], msg elif prop_type == 'PCOMP': if isinstance(pname_fid, str): if pname_fid in ['Z0', 'SB', 'TREF', 'GE', 'NSM']: pass else: word, num = break_word_by_trailing_integer(pname_fid) if word not in ['T', 'THETA']: raise RuntimeError('word=%r\n%s' % (word, msg)) int(num) else: if pname_fid == 4: pname_fid = 'NSM' else: #PID Z0 NSM SB FT TREF GE LAM assert pname_fid in valid_pcomp_codes, msg elif prop_type == 'PCOMPG': #if pname_fid in ['T', 4]: #pname_fid = 'T' #elif pname_fid in [6]: # 12I/T**3 doesn't support strings #pass #else: #raise NotImplementedError('PSHELL pname_fid=%r is invalid' % pname_fid) #if cp_name in '12I/T**3': options = ['Z0', 'SB', 14, 24, 34, 44, 15, 25, 75, 85] _check_dvprel_options(pname_fid, prop_type, options) #elif prop_type == 'CBUSH': #assert pname_fid in ['X1', 'X2', 'X3', 'S', 'S1'], msg elif prop_type == 'PBUSH': options = [18, 'K1', 'K2', 'K3', 'K4', 'K5', 'K6', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'M1', 'M2', 'M3', 'M4', 'M5', 'M6', 'GE1', 'GE3', 'GE4', 'GE5', 'GE6', -13] _check_dvprel_options(pname_fid, prop_type, options) elif prop_type == 'PBUSH1D': options = ['K', 'C', 'M'] _check_dvprel_options(pname_fid, prop_type, options) elif prop_type == 'PBUSHT': options = ['TBID1', 'TGEID1', 'TGEID2'] _check_dvprel_options(pname_fid, prop_type, options) # CGAP elif prop_type == 'PGAP': if pname_fid == 5: pname_fid = 'KA' options = ['KA'] #options = [5] _check_dvprel_options(pname_fid, prop_type, options) elif prop_type == 'PVISC': if pname_fid == 3: pname_fid = 'CE1' options = ['CE1'] _check_dvprel_options(pname_fid, prop_type, options) #elif prop_type == 'CDAMP2': #assert pname_fid in ['B'], msg elif prop_type == 'PDAMP': if pname_fid == 3: pname_fid = 'B1' #options = [3, 'B1'] options = ['B1'] _check_dvprel_options(pname_fid, prop_type, options) #elif prop_type == 'CMASS2': #assert pname_fid in ['M'], msg #elif prop_type == 'CMASS4': #assert pname_fid in ['M'], msg elif prop_type == 'PMASS': options = [3] _check_dvprel_options(pname_fid, prop_type, options) #elif prop_type == 'CONM2': #assert pname_fid in ['M', 'X1', 'X2', 'I11', 'I22'], msg elif prop_type == 'PSHEAR': if pname_fid in ['T', 4]: pname_fid = 'T' elif pname_fid in ['NSM', 5]: pname_fid = 'NSM' else: raise NotImplementedError('PSHEAR pname_fid=%r is invalid' % pname_fid) elif prop_type == 'PWELD': options = ['D'] _check_dvprel_options(pname_fid, prop_type, options) elif prop_type == 'PFAST': options = ['KT1', 'KT2', 'KT3', 'KR1', 'KR2', 'KR3', 'MASS'] _check_dvprel_options(pname_fid, prop_type, options) elif prop_type == 'PBRSECT': options = ['T', 'W', 'H'] _check_dvprel_options(pname_fid, prop_type, options) elif prop_type == 'PBMSECT': options = ['T', 'W', 'H', 'T(1)', 'T(2)', 'T(3)', 'T(4)', 'T(5)', 'T(6)', 'T(7)'] _check_dvprel_options(pname_fid, prop_type, options) elif prop_type == 'PBEND': raise RuntimeError('Nastran does not support the PBEND') else: raise NotImplementedError(msg) return pname_fid
[docs] def _check_dvcrel_options(cp_name, element_type, options): if cp_name not in options: soptions = [str(val) for val in options] msg = ( '%r is an invalid option for %s\n' 'valid: [%s]' % (cp_name, element_type, ', '.join(soptions))) raise ValueError(msg)
[docs] def _check_dvmrel_options(mp_name, material_type, options): if mp_name not in options: soptions = [str(val) for val in options] msg = ( '%r is an invalid option for %s\n' 'valid: [%s]' % (mp_name, material_type, ', '.join(soptions))) raise ValueError(msg)
[docs] def _check_dvprel_options(pname_fid, prop_type, options): if pname_fid not in options: soptions = [str(val) for val in options] msg = ( '%r is an invalid option for %s\n' 'valid: [%s]' % (pname_fid, prop_type, ', '.join(soptions))) raise ValueError(msg)
[docs] class OptConstraint(BaseCard): def __init__(self): BaseCard.__init__(self)
[docs] class DVXREL1(BaseCard): def __init__(self, oid, dvids, coeffs, c0, comment): BaseCard.__init__(self) if comment: self.comment = comment if isinstance(dvids, integer_types): dvids = [dvids] if isinstance(coeffs, float): coeffs = [coeffs] # optimization id self.oid = oid # DESVAR ids self.dvids = dvids # scale factors for DESVARs self.coeffs = coeffs # offset coefficient self.c0 = c0 self.dvids_ref = None
[docs] def validate(self): msg = '' assert len(self.dvids) > 0 and len(self.coeffs) > 0, str(self) for i, desvar_id, coeff in zip(count(), self.dvids, self.coeffs): if not isinstance(desvar_id, integer_types): msg += ' desvar_id[%i]=%s is not an integer; type=%s\n' % ( i, desvar_id, type(desvar_id)) if coeff in ['PVAL']: pass elif not isinstance(coeff, float_types): msg += ' coeff[%i]=%s is not a float; type=%s\n' % (i, coeff, type(coeff)) if msg: raise RuntimeError('Invalid %s\n' % self.type + msg + str(self))
@property def desvar_ids(self): if self.dvids_ref is None: return self.dvids return [desvar.desvar_id for desvar in self.dvids_ref]
[docs] class DVXREL2(BaseCard): def __init__(self, oid, dvids, labels, deqation, comment): BaseCard.__init__(self) if comment: self.comment = comment if dvids is None: dvids = [] elif isinstance(dvids, integer_types): dvids = [dvids] if labels is None: labels = [] elif isinstance(labels, str): labels = [labels] #: Unique identification number self.oid = oid # DESVAR ids self.dvids = dvids self.labels = labels #: DEQATN entry identification number. (Integer > 0) self.dequation = deqation self.dvids_ref = None self.dtable_ref = {} self.dequation_ref = None
[docs] def validate(self): msg = '' assert len(self.dvids) > 0, str(self) for i, desvar_id in enumerate(self.dvids): if not isinstance(desvar_id, int): msg += ' desvar_id[%i]=%s is not an integer; type=%s\n' % ( i, desvar_id, type(desvar_id)) if msg: raise RuntimeError('Invalid %s\n' % self.type + msg + str(self)) assert isinstance(self.labels, list), str(self)
@property def desvar_ids(self): if self.dvids_ref is None: return self.dvids return [desvar.desvar_id for desvar in self.dvids_ref]
[docs] def _check_args(self): """checks the number of DEQATN args""" nargs = len(self.dvids) + len(self.labels) if self.dequation_ref.nargs != nargs: msg = (f'nargs_expected={self.dequation_ref.nargs}; actual={nargs}\n' f'desvars={self.dvids}; n={len(self.dvids)}\n' f'labels={self.labels}; n={len(self.labels)}\n{self.dequation_ref}{self}') raise RuntimeError(msg)
[docs] class DCONSTR(OptConstraint): type = 'DCONSTR' """ +---------+------+-----+------------+------------+-------+--------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | +=========+======+=====+============+============+=======+========+ | DCONSTR | DCID | RID | LALLOW/LID | UALLOW/UID | LOWFQ | HIGHFQ | +---------+------+-----+------------+------------+-------+--------+ | DCONSTR | 10 | 4 | 1.25 | | | | +---------+------+-----+------------+------------+-------+--------+ """ def __init__(self, oid, dresp_id, lid=-1.e20, uid=1.e20, lowfq=0., highfq=1.e20, comment=''): """ Creates a DCONSTR card Parameters ---------- oid : int unique optimization id dresp_id : int DRESP1/2 id lid / uid : int/float; default=-1.e20 / 1.e20 int: f(ω) defined by TABLED1-4 float: lower/upper bound lowfq / highfq : float; default=0. / 1.e20 lower/upper end of the frequency range comment : str; default='' a comment for the card """ OptConstraint.__init__(self) if comment: self.comment = comment self.oid = oid # DRESP entry self.dresp_id = dresp_id # lower bound self.lid = lid # upper bound self.uid = uid # low end of frequency range (Hz) self.lowfq = lowfq # high end of frequency range (Hz) self.highfq = highfq self.lid_ref = None self.uid_ref = None self.dresp_id_ref = None
[docs] @classmethod def export_to_hdf5(cls, hdf5_file, dconstrs, encoding): oid = [] dresp_id = [] lid = [] uid = [] lowfq = [] highfq = [] for dconstr in dconstrs: oid.append(dconstr.oid) dresp_id.append(dconstr.dresp_id) lid.append(dconstr.lid) uid.append(dconstr.uid) lowfq.append(dconstr.lowfq) highfq.append(dconstr.highfq) hdf5_file.create_dataset('oid', data=oid) hdf5_file.create_dataset('dresp_id', data=dresp_id) hdf5_file.create_dataset('lid', data=lid) hdf5_file.create_dataset('uid', data=uid) hdf5_file.create_dataset('lowfq', data=lowfq) hdf5_file.create_dataset('highfq', data=highfq)
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a DCONSTR card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ oid = integer(card, 1, 'oid') dresp_id = integer(card, 2, 'dresp_id') lid = integer_double_or_blank(card, 3, 'lid', default=-1e20) uid = integer_double_or_blank(card, 4, 'uid', default=1e20) lowfq = double_or_blank(card, 5, 'lowfq', default=0.0) highfq = double_or_blank(card, 6, 'highfq', default=1e20) assert len(card) <= 7, f'len(DCONSTR card) = {len(card):d}\ncard={card}' return DCONSTR(oid, dresp_id, lid, uid, lowfq, highfq, comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a DCONSTR card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ oid = data[0] rid = data[1] lid = data[2] uid = data[3] lowfq = data[4] highfq = data[5] return DCONSTR(oid, rid, lid, uid, lowfq, highfq, comment=comment)
[docs] def DRespID(self): if self.dresp_id_ref is None: return self.dresp_id return self.dresp_id_ref.dresp_id
[docs] def Rid(self): return self.DRespID()
[docs] def Lid(self): if self.lid_ref is None: return self.lid # int/float return self.lid_ref.tid
[docs] def Uid(self): if self.uid_ref is None: return self.uid # int/float return self.uid_ref.tid
[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 DCONSTR oid=%s' % (self.oid) self.dresp_id_ref = model.DResp(self.dresp_id, msg) if isinstance(self.lid, integer_types): self.lid_ref = model.TableD(self.lid, msg) if isinstance(self.uid, integer_types): self.uid_ref = model.TableD(self.uid, msg)
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.dresp_id = self.DRespID() self.lid = self.Lid() self.uid = self.Uid() self.lid_ref = None self.uid_ref = None self.dresp_id_ref = None
[docs] def raw_fields(self): list_fields = ['DCONSTR', self.oid, self.DRespID(), self.Lid(), self.Uid(), self.lowfq, self.highfq] return list_fields
[docs] def repr_fields(self): lid = set_blank_if_default(self.Lid(), -1e20) uid = set_blank_if_default(self.Uid(), 1e20) lowfq = set_blank_if_default(self.lowfq, 0.0) highfq = set_blank_if_default(self.highfq, 1e20) list_fields = ['DCONSTR', self.oid, self.DRespID(), lid, uid, lowfq, highfq] 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 DESVAR(OptConstraint): type = 'DESVAR' """ +--------+-----+-------+-------+-----+-----+-------+-------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | +========+=====+=======+=======+=====+=====+=======+=======+ | DESVAR | OID | LABEL | XINIT | XLB | XUB | DELXV | DDVAL | +--------+-----+-------+-------+-----+-----+-------+-------+ """ _properties = ['value'] #@classmethod #def _init_from_empty(cls): #desvar_id = 1 #label = 'name' #xinit = 0.5 #return DESVAR(desvar_id, label, xinit, #xlb=-1e20, xub=1e20, delx=None, ddval=None, comment='')
[docs] @classmethod def export_to_hdf5(cls, h5_file, model, desvar_ids): """exports the elements in a vectorized way""" #comments = [] encoding = model.get_encoding() ndesvars = len(desvar_ids) label = [] xinit = [] xlb = [] xub = [] delx = np.full(ndesvars, np.nan) ddval = np.full(ndesvars, np.nan) for i, desvar_id in enumerate(desvar_ids): desvar = model.desvars[desvar_id] #comments.append(element.comment) label.append(desvar.label.encode(encoding)) xinit.append(desvar.xinit) xlb.append(desvar.xlb) xub.append(desvar.xub) delx[i] = desvar.delx ddval[i] = desvar.ddval #h5_file.create_dataset('_comment', data=comments) h5_file.create_dataset('desvar', data=desvar_ids) h5_file.create_dataset('label', data=label) h5_file.create_dataset('xinit', data=xinit) h5_file.create_dataset('xlb', data=xlb) h5_file.create_dataset('xub', data=xub) h5_file.create_dataset('delx', data=delx) h5_file.create_dataset('ddval', data=ddval)
def __init__(self, desvar_id, label, xinit, xlb=-1e20, xub=1e20, delx=None, ddval=None, comment=''): """ Creates a DESVAR card Parameters ---------- desvar_id : int design variable id label : str name of the design variable xinit : float the starting point value for the variable xlb : float; default=-1.e20 the lower bound xub : float; default=1.e20 the lower bound delx : float; default=1.e20 fractional change allowed for design variables during approximate optimization NX if blank : take from DOPTPRM; otherwise 1.0 MSC if blank : take from DOPTPRM; otherwise 0.5 ddval : int; default=None int : DDVAL id allows you to set discrete values None : continuous comment : str; default='' a comment for the card """ OptConstraint.__init__(self) if comment: self.comment = comment self.desvar_id = desvar_id #: user-defined name for printing purposes self.label = label #xinit = np.clip(xinit, xlb, xub) self.xinit = xinit self.xlb = xlb self.xub = xub assert len(label) <= 8, f'desvar_id={desvar_id} label={label!r} must be less than 8 characters; length={len(label):d}' assert xlb <= xub, f'desvar_id={desvar_id:d} xlb={xlb} xub={xub}' assert xinit >= xlb, f'desvar_id={desvar_id:d} xlb={xlb} xub={xub}' assert xinit <= xub, f'desvar_id={desvar_id:d} xlb={xlb} xub={xub}' # controls change for a single optimization cycle # taken from DOPTPRM if None; else default=1. self.delx = delx # DDVAL id if you want discrete values self.ddval = ddval self.ddval_ref = None #assert ' ' not in label.rstrip(), self.get_stats() def _verify(self, xref): pass
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a DESVAR card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ desvar_id = integer(card, 1, 'desvar_id') label = string(card, 2, 'label') xinit = double(card, 3, 'xinit') xlb = double_or_blank(card, 4, 'xlb', default=-1e20) xub = double_or_blank(card, 5, 'xub', default=1e20) delx = double_or_blank(card, 6, 'delx') ddval = integer_or_blank(card, 7, 'ddval') assert len(card) <= 8, f'len(DESVAR card) = {len(card):d}\ncard={card}' return DESVAR(desvar_id, label, xinit, xlb=xlb, xub=xub, delx=delx, ddval=ddval, comment=comment)
@property def value(self): """gets the actual value for the DESVAR""" value = min(max(self.xinit, self.xlb), self.xub) return value
[docs] def raw_fields(self): list_fields = ['DESVAR', self.desvar_id, self.label, self.xinit, self.xlb, self.xub, self.delx, self.ddval] return list_fields
[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 """ if self.ddval: msg = ', which is required by DESVAR desvar_id=%r' % self.desvar_id self.ddval_ref = model.DDVal(self.ddval, msg=msg)
[docs] def safe_cross_reference(self, model): try: self.cross_reference(model) except KeyError: self.log.warning('cant cross reference DESVAR {self.desvar_id} with DDVAL {self.ddval}')
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.ddval = self.DDVal() self.ddval_ref = None
[docs] def DDVal(self): if self.ddval_ref is not None: return self.ddval_ref.oid return self.ddval
[docs] def repr_fields(self): """ Gets the fields in their simplified form Returns ------- fields : list[varies] the fields that define the card """ xlb = set_blank_if_default(self.xlb, -1e20) xub = set_blank_if_default(self.xub, 1e20) label = self.label.strip() if len(label) <= 6: label = ' %6s ' % label list_fields = ['DESVAR', self.desvar_id, label, self.xinit, xlb, xub, self.delx, self.DDVal()] 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)
[docs] class TOPVAR(BaseCard): type = 'TOPVAR' def __init__(self, opt_id, label, prop_type, xinit, pid, xlb=0.001, delxv=0.2, power=3.0, options=None, comment=''): if comment: self.comment = comment if options is None: options = {} self.opt_id = opt_id self.label = label self.prop_type = prop_type self.xinit = xinit self.pid = pid self.xlb = xlb self.delxv = delxv self.power = power self.options = options
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a DESVAR card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ opt_id = integer(card, 1, 'opt_id') label = string(card, 2, 'label') prop_type = string(card, 3, 'prop_type') xinit = double_or_blank(card, 4, 'xinit') xlb = double_or_blank(card, 5, 'xlb', default=0.001) delxv = double_or_blank(card, 6, 'delxv', default=0.2) power = double_or_blank(card, 7, 'power', default=3.0) pid = integer(card, 8, 'pid') options = {} if len(card) > 8: name = string_or_blank(card, 9, 'SYM') if name == 'SYM': # CID MSi MSi MSi CS NCS cid = integer_or_blank(card, 10, 'cid') mirror_symmetry1 = string_or_blank(card, 11, 'mirror_symmetry1') # Character, XY, YZ, or ZX mirror_symmetry2 = string_or_blank(card, 12, 'mirror_symmetry2') mirror_symmetry3 = string_or_blank(card, 13, 'mirror_symmetry3') cyclic_symmetry = string_or_blank(card, 14, 'cyclic_symmetry') # X, Y, Z # Number of cyclic symmetric segments in 360 degrees num_cyclic_symmetries = integer_or_blank(card, 15, 'num_cyclic_symmetries') options[name] = { 'cid' : cid, 'mirror_symmetry1' : mirror_symmetry1, 'mirror_symmetry2' : mirror_symmetry2, 'mirror_symmetry3' : mirror_symmetry3, 'cyclic_symmetry' : cyclic_symmetry, 'num_cyclic_symmetries' : num_cyclic_symmetries, } assert len(card) <= 16, f'len(TOPVAR card) = {len(card):d}\ncard={card}' elif name == 'STRESS': allowable = double(card, 10, 'allowable?') options[name] = {'allowable' : allowable,} assert len(card) <= 11, f'len(TOPVAR card) = {len(card):d}\ncard={card}' else: assert len(card) <= 9, f'len(TOPVAR card) = {len(card):d}\ncard={card}' return TOPVAR(opt_id, label, prop_type, xinit, pid, xlb=xlb, delxv=delxv, power=power, options=options, comment=comment)
[docs] def repr_fields(self): """ Gets the fields in their simplified form Returns ------- fields : list[varies] the fields that define the card """ power = set_blank_if_default(self.power, 3) xlb = set_blank_if_default(self.xlb, 0.001) delxv = set_blank_if_default(self.delxv, 0.2) label = self.label.strip() if len(label) <= 6: label = ' %6s ' % label list_fields = [ 'TOPVAR', self.opt_id, label, self.prop_type, self.xinit, xlb, delxv, power, self.pid] for name, option in sorted(self.options.items()): if name == 'STRESS': list_fields += [name, option['allowable'], None, None, None, None, None, None] elif name == 'SYM': list_fields += [ name, option['cid'], option['mirror_symmetry1'], option['mirror_symmetry2'], option['mirror_symmetry3'], option['cyclic_symmetry'], option['num_cyclic_symmetries'], None, ] else: raise NotImplementedError(name) return list_fields
[docs] def uncross_reference(self): pass
[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)
[docs] class DDVAL(OptConstraint): """ +-------+-----+-------+-------+-------+-------+-------+-------+-------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +=======+=====+=======+=======+=======+=======+=======+=======+=======+ | DDVAL | ID | DVAL1 | DVAL2 | DVAL3 | DVAL4 | DVAL5 | DVAL6 | DVAL7 | +-------+-----+-------+-------+-------+-------+-------+-------+-------+ | DDVAL | ID | DVAL1 | THRU | DVAL2 | BY | INC | | | +-------+-----+-------+-------+-------+-------+-------+-------+-------+ +-------+-----+-------+-------+-------+-------+-------+-------+-------+ | DDVAL | 110 | 0.1 | 0.2 | 0.3 | 0.5 | 0.6 | 0.4 | | +-------+-----+-------+-------+-------+-------+-------+-------+-------+ | | .7 | THRU | 1.0 | BY | 0.05 | | | | +-------+-----+-------+-------+-------+-------+-------+-------+-------+ | | 1.5 | 2.0 | | | | | | | +-------+-----+-------+-------+-------+-------+-------+-------+-------+ """ type = 'DDVAL'
[docs] @classmethod def _init_from_empty(cls): oid = 1 ddvals = [1, 2] return DDVAL(oid, ddvals, comment='')
def __init__(self, oid, ddvals, comment=''): OptConstraint.__init__(self) if comment: self.comment = comment if isinstance(ddvals, float): ddvals = [ddvals] else: ddvals = expand_thru_by(ddvals, require_int=False) ddvals.sort() self.oid = oid self.ddvals = ddvals
[docs] def validate(self): #if not isinstance(self.ddvals, list): #raise TypeError('ddvals=%s must be a list' % self.ddvals) msg = '' for iddval, ddval in enumerate(self.ddvals): if not isinstance(ddval, float): msg += 'ddval[%i]=%s is not a float; type=%s\n' % (iddval, ddval, type(ddval)) if msg: raise TypeError(msg)
[docs] @classmethod def add_card(cls, card: BDFCard, comment: str=''): """ Adds a DDVAL card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ oid = integer(card, 1, 'oid') n = 1 ddvals = [] for i in range(2, len(card)): ddval = double_string_or_blank(card, i, 'DDVAL%s' % n) if ddval is not None: ddvals.append(ddval) return DDVAL(oid, ddvals, comment=comment)
[docs] def raw_fields(self): self.ddvals.sort() list_fields = ['DDVAL', self.oid] + self.ddvals 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)
DOPTPRM_INTS = set([]) DOPTPRM_FLOATS = { 'DABOBJ', 'DOBJ2', 'DX2', } DOPTPRM_INT_FLOATS = set([]) DOPTPRM_STRS = set( ['OPTCOD'] # DOT ) DOPTPRM_DEFAULTS = { 'APRCOD' : 2, 'AUTOSE' : 0, #'CONV1' : 0.001, 'CONV1' : 0.0001, # NX 2019.2 'CONV2' : 1e-20, 'CONVDV' : 0.001, # 0.0001 for topology optimization 'CONVPR' : 0.001, 'CT' : -0.03, 'CTMIN' : 0.003, 'DELB' : 0.0001, 'DELP' : 0.2, 'DELX' : 0.5, # 0.2 for topology optimization 'DLXESL' : 0.5, 'DESMAX' : 5, # 30 for topology optimization 'DELOBJ' : 0.001, 'DOBJ1' : 0.1, 'DOBJ2' : None, 'DX1' : 0.01, 'DX2' : None, 'DISCOD' : 1, 'DISBEG' : 0, 'DPMAX' : 0.5, 'DPMIN' : 0.01, 'DRATIO' : 0.1, 'DSMXESL' : 20, 'DXMAX' : 1.0, 'DXMIN' : 0.05, # 1e-5 for topology optimization 'DPMIN' : 0.01, 'ETA1' : 0.01, 'ETA2' : 0.25, 'ETA3' : 0.7, 'EDVOUT': 0.001, 'FSDALP' : 0.9, 'FSDMAX' : 0, 'GMAX' : 0.005, 'GSCAL' : 0.001, 'IGMAX' : 0, 'IPRINT' : 0, 'IPRNT1': 0, 'IPRNT2': 0, 'ISCAL' : 0, 'ITMAX': 40, 'ITRMOP': 2, 'ITRMST': 2, 'IWRITE': 6, # or system(2) 'JPRINT': 0, 'JTMAX': 20, 'JWRITE': 0, 'MXCRTRSP': 5, #'METHOD' : 0, # ??? 'METHOD' : 1, # NX 2019 'NASPRO' : 0, 'OBJMOD' : 0, #'OPTCOD' : 0, 'P1' : 0, 'P2' : 1, 'P2CALL' : None, #: .. todo:: DEFAULT PRINTS ALL??? 'P2CBL' : None, #: .. todo:: DEFAULT PRINTS ALL??? 'P2CC' : None, #: .. todo:: DEFAULT PRINTS ALL??? 'P2CDDV' : None, #: .. todo:: DEFAULT PRINTS ALL??? 'P2CM' : None, #: .. todo:: DEFAULT PRINTS ALL??? 'P2CP' : None, #: .. todo:: DEFAULT PRINTS ALL??? 'P2CR' : None, #: .. todo:: DEFAULT PRINTS ALL??? 'P2RSET' : 0, # default=0 -> ALL 'PENAL' : 0.0, 'PLVIOL' : 0, 'PTOL' : 1e35, 'STPSCL' : 1.0, 'TCHECK' : -1, 'TDMIN' : None, #: .. todo:: ??? 'TREGION' : 0, 'UPDFAC1' : 2.0, 'UPDFAC2' : 0.5, } for key, value in DOPTPRM_DEFAULTS.items(): if isinstance(value, int): DOPTPRM_INTS.add(key) elif isinstance(value, float): DOPTPRM_FLOATS.add(key) elif value is None: DOPTPRM_INT_FLOATS.add(key) else: raise RuntimeError((key, value))
[docs] class DOPTPRM(OptConstraint): """causes a Nastran core dump if FSDMAX is nonzero and there is no stress case""" type = 'DOPTPRM' defaults = DOPTPRM_DEFAULTS
[docs] @classmethod def _init_from_empty(cls): params = {'TCHECK' : -1} return DOPTPRM(params, comment='')
[docs] def _finalize_hdf5(self, encoding): """hdf5 helper function""" keys, values = self.params self.params = {key : value if not np.isnan(value) else None for key, value in zip(keys, values)}
def __init__(self, params: dict[str, Any], comment: str=''): """ Design Optimization Parameters Overrides default values of parameters used in design optimization +---------+--------+------+--------+------+--------+------+--------+------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +=========+========+======+========+======+========+======+========+======+ | DOPTPRM | PARAM1 | VAL1 | PARAM2 | VAL2 | PARAM3 | VAL3 | PARAM4 | VAL4 | +---------+--------+------+--------+------+--------+------+--------+------+ | | PARAM5 | VAL5 | etc. | | | | | | +---------+--------+------+--------+------+--------+------+--------+------+ """ OptConstraint.__init__(self) if comment: self.comment = comment self.params = params
[docs] @classmethod def add_card(cls, card: BDFCard, comment: str=''): """ Adds a DOPTPRM card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ nfields = len(card) - 1 params = {} for i in range(0, nfields, 2): param = string_or_blank(card, i + 1, 'param') default_value = None if param is None: continue if param in cls.defaults: default_value = cls.defaults[param] if param in DOPTPRM_INTS: val = integer_or_blank(card, i + 2, '%s_value' % param, default_value) elif param in DOPTPRM_FLOATS: val = double_or_blank(card, i + 2, '%s_value' % param, default_value) elif param in DOPTPRM_STRS: val = string_or_blank(card, i + 2, '%s_value' % param) elif param in DOPTPRM_INT_FLOATS: val = integer_double_string_or_blank(card, i + 2, '%s_value' % param, default_value) else: #raise NotImplementedError(f'param={param} value={card[i+2]}') val = integer_double_string_or_blank(card, i + 2, '%s_value' % param, default_value) params[param] = val return DOPTPRM(params, comment=comment)
[docs] def raw_fields(self) -> list[Union[int, float, str]]: list_fields = ['DOPTPRM'] for param, val in sorted(self.params.items()): list_fields += [param, val] 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] def validate_dresp1(label: str, property_type: str, response_type: str, atta: int, attb: Optional[int], atti: list[int]) -> None: property_types = [ 'ELEM', #'PELAS', 'PROD', # 'PTUBE', 'PBAR', 'PBARL', 'PBEAM', #'PBEAML', #'PSHEAR', 'PSHELL', 'PCOMP', #'PSOLID', #'PKNL', None, ] #stress_types = ['PBARL'] unused_response_types = [ #'WEIGHT', 'VOLUME', # static #'DISP', 'STRESS', 'COMP', 'SPCFORCE', 'ESE', 'GPFORCP', # aero #'FLUTTER', 'STABDER', 'TRIM', 'DIVERG', # ??? #'CEIG', 'CSTRAT', # modal #'EIGN', 'LAMA', # time #'TDISP', 'TVELO', 'TACCL', 'TFORC', 'TSPCF', # frequency #'FREQ', #'FRDISP', 'FRVELO', 'FRACCL', #'FRSPCF', 'FRMASS', 'FRFORC', 'FRSTRE', # random #'PSDDISP', 'PSDACCL', #'RMSDISP', 'RMSVELO', 'RMSACCL', #'CFAILURE', 'TOTSE', ] msg = 'DRESP1 label=%s ptype=%s rtype=%s atta=%s attb=%s atti=%s' % ( label, property_type, response_type, atta, attb, atti) #print(msg) if property_type not in property_types: if property_type == 'ELEM': if response_type == 'CFAILURE': pass elif response_type in ['STRESS', 'STRAIN']: pass else: raise RuntimeError(msg) #elif property_type is stress_properties: #raise RuntimeError(msg) #else: raise RuntimeError(msg) if response_type == 'FLUTTER': #ATT1 = Identification number of a SET1 entry that specifies a set of modes. #ATT2 = Identification number of an FLFACT entry that specifies a list of densities. #ATT3 = Identification number of an FLFACT entry that specifies a list of Mach numbers. #ATT4 = Identification number of an FLFACT entry that specifies a list of velocities. #If the flutter analysis is type PKNL, it is necessary to put PKNL in the PTYPE #field of this entry. assert property_type in [None, 'PKNL', 'PK'], msg assert atta is None, msg assert attb is None, msg assert len(atti) == 4, msg elif property_type is None: atta, attb, atti = _validate_dresp_property_none( label, property_type, response_type, atta, attb, atti) elif response_type == 'CFAILURE': # attb is the lamina number if attb is None: attb = 1 msg = 'DRESP1 ptype=%s rtype=%s atta=%s attb=%s atti=%s' % ( property_type, response_type, atta, attb, atti) if property_type == 'ELEM': assert atta in [5, 7], msg elif property_type == 'PCOMP': assert atta in [3, 5], msg else: raise RuntimeError(msg) assert isinstance(attb, integer_types), msg assert attb > 0, msg assert len(atti) > 0, msg elif response_type in {'CSTRAIN', 'CSTRESS'}: # attb is the lamina number if attb is None: attb = 1 msg = 'DRESP1 ptype=%s rtype=%s atta=%s attb=%s atti=%s' % ( property_type, response_type, atta, attb, atti) # 11 - max shear stress/strain assert atta in [3, 4, 5, 6, 7, 9, 10, 11], msg # stress code if property_type not in ['PCOMP', 'ELEM']: raise RuntimeError(msg) assert isinstance(attb, integer_types), msg assert attb > 0, msg # lamina id assert len(atti) > 0, msg # pid/eids elif response_type in {'STRESS', 'STRAIN'}: _validate_dresp1_stress_strain(property_type, response_type, atta, attb, atti) elif response_type == 'FORCE': _validate_dresp1_force(property_type, response_type, atta, attb, atti) elif response_type == 'ELEM': assert len(atti) > 0, msg for eid in atti: assert isinstance(eid, int), msg elif response_type in {'PSDDISP', 'PSDACCL'}: #RuntimeError: DRESP1 ptype=91 rtype=PSDDISP atta=3 attb=60.0 atti=[3] assert atta in {3}, msg assert isinstance(attb, float_types), msg assert len(atti) > 0, msg for eid in atti: assert isinstance(eid, int), msg else: msg = 'DRESP1 ptype=%s rtype=%s atta=%s attb=%s atti=%s' % ( property_type, response_type, atta, attb, atti) raise RuntimeError(msg) return atta, attb, atti
[docs] def _blank_or_mode(attb, msg): """if it's blank, it's a static result, otherwise it's a mode id""" assert attb is None or isinstance(attb, integer_types), msg
[docs] def _validate_dresp_property_none(label: str, property_type: str, response_type: str, atta, attb, atti) -> None: """helper for ``validate_dresp``""" msg = 'DRESP1 label=%s ptype=%s rtype=%s atta=%s attb=%s atti=%s' % ( label, property_type, response_type, atta, attb, atti) if response_type == 'WEIGHT': assert atta in [1, 2, 3, 4, 5, 6, 33, None], msg assert attb in [1, 2, 3, 4, 5, 6, None], msg if len(atti) == 0: atti = ['ALL'] for attii in atti: if attii != 'ALL': assert isinstance(attii, integer_types), msg assert attii >= 0, msg elif response_type == 'VOLUME': if len(atti) == 0: atti = ['ALL'] msg = 'DRESP1 ptype=%s rtype=%s atta=%s attb=%s atti=%s' % ( property_type, response_type, atta, attb, atti) #assert atta is None, msg assert attb is None, msg for attii in atti: assert attii in [0, 'ALL'], msg elif response_type == 'DISP': atta = str(atta) msg = 'DRESP1 ptype=%s rtype=%s atta/component=%s attb=%s atti/nid=%s' % ( property_type, response_type, atta, attb, atti) assert atta is not None and attb is None and atti is not None, msg for attai in atta: assert atta in '123456', msg # 8??? _blank_or_mode(attb, msg) #assert len(atti) == 1, msg elif response_type in ['FRDISP', 'FRVELO', 'FRACCL', 'FRSPCF']: # frequency displacement assert atta in [1, 2, 3, 4, 5, 7, 8, 9], msg if attb is None or isinstance(attb, float_types): # blank is all frequencies # float is a specific frequency pass elif attb == 'ALL': attb = None else: assert attb in ['SUM', 'AVG', 'SSQ', 'RSS', 'MAX', 'MIN', 'AVE'], msg # remove AVE? if attb is not None: assert len(atti) >= 1, msg for attii in atti: assert isinstance(attii, integer_types), msg assert attii > 0, msg elif response_type in ['TDISP', 'TVELO', 'TACCL', 'TSPCF']: # time displacement atta = str(atta) msg = 'DRESP1 ptype=%s rtype=%s atta=%s attb=%s atti=%s' % ( property_type, response_type, atta, attb, atti) for attai in atta: assert atta in '123456', msg # 8??? if attb is None or isinstance(attb, float_types): # blank is all times # float is a specific times pass else: assert attb in ['SUM', 'AVG', 'SSQ', 'RSS', 'MAX', 'MIN'], msg assert len(atti) >= 1, msg for attii in atti: assert isinstance(attii, integer_types), msg assert attii > 0, msg elif response_type in ['RMSDISP', 'RMSACCL']: assert atta in [1, 2, 3], msg assert attb in [140, 1000], msg assert len(atti) == 1, msg elif response_type == 'CEIG': if attb is None: attb = 'ALPHA' assert isinstance(atta, integer_types), msg assert atta > 0, msg assert attb in ['ALPHA', 'OMEGA'], msg assert len(atti) == 0, msg elif response_type in {'EIGN', 'LAMA'}: # EIGEN as well? assert isinstance(atta, integer_types), msg assert atta > 0, msg # LAMA: # blank/1 -> direct linerization (default) # 2 -> inverse linearization # EIGN: # blank -> Rayleigh Quotient Approximation (default) # 1 -> direct linerization # 2 -> inverse approximation assert attb in [None, 1, 2], msg assert len(atti) == 0, msg elif response_type == 'FREQ': assert isinstance(atta, integer_types), msg assert atta > 0, msg # EIGN: # blank -> Rayleigh Quotient Approximation (default) # 1 -> direct linerization # 2 -> inverse approximation assert attb in [None, 1, 2], msg assert len(atti) == 0, msg elif response_type == 'STABDER': # atta=517 #attb = None #atti = [4] assert isinstance(atta, integer_types), msg assert atta > 0, msg assert attb is None, msg assert len(atti) == 1, msg elif response_type == 'CMPLNCE': # compliance assert atta is None, msg assert attb is None, msg assert len(atti) == 0, msg elif response_type == 'DWEIGHT': #DRESP1 label=DWEIGHT ptype=None rtype=DWEIGHT atta=None attb=None atti=[] assert atta is None, msg assert attb is None, msg assert len(atti) == 0, msg elif response_type in {'STRESS', 'STRAIN', 'FORCE', 'CFAILURE'}: raise RuntimeError(f'response_type={response_type!r} and property_type must not be None...{msg}') else: raise RuntimeError(msg) return atta, attb, atti
[docs] def _validate_dresp1_stress_strain(property_type: str, response_type: str, atta, attb, atti): """helper for ``validate_dresp``""" msg = 'DRESP1 ptype=%s rtype=%s atta=%s attb=%s atti=%s' % ( property_type, response_type, atta, attb, atti) _blank_or_mode(attb, msg) if property_type == 'ELEM': assert isinstance(atta, integer_types), msg elif property_type == 'PBARL': assert atta in [2, 3, 4, 5, 7, 8], msg elif property_type == 'PBAR': assert atta in [2, 6, 7, 8, 14, 15], msg elif property_type == 'PBEAM': _check_pbeam_pbeaml_allowable_attas(atta, msg) elif property_type == 'PBEAML': _check_pbeam_pbeaml_allowable_attas(atta, msg) elif property_type == 'PROD': assert atta in {2, 3, 7}, msg elif property_type == 'PSHELL': assert atta in {4, 5, 6, 7, 8, 9, 15, 16, 17, 19, 26, 28, 35, 36}, msg elif property_type == 'PCOMP': # this is a SMEAR PCOMP, which is basically a PSHELL assert atta in {9, 11, 17}, msg #elif property_type in stress_types: #if not isinstance(atta, integer_types): #msg = 'DRESP1 ptype=%s rtype=%s atta=%s attb=%s atti=%s; atta should be an integer' % ( #property_type, response_type, atta, attb, atti) #raise TypeError(msg) #assert attb is None, 'DRESP1 ptype=%s rtype=%s atta=%s attb=%s atti=%s' % ( #property_type, response_type, atta, attb, atti) elif property_type == 'PSOLID': assert atta in {13}, msg assert attb in {None}, msg #assert atti in {}, msg else: raise RuntimeError(f'property_type={property_type} is not supported\n' + msg) assert attb is None, '%s; atta should be an integer' % msg assert len(atti) > 0, msg
[docs] def _check_pbeam_pbeaml_allowable_attas(atta: int, msg: str) -> None: """ 6 /16/26...106: point E stress 8 /18/28...108: max principal 9 /19/29...109: min principal 10/20/30...110: margin tension 11/21/31...111: margin compression """ # k = 11 # end b # offset = (k - 1) * 10 # i=0 -> end A # i=10 -> end B attas_ends_1_thru_11 = [] for i in range(11): offset = i * 10 attas_ends_1_thru_11 += [6 + offset, 8 + offset, 9 + offset, 10 + offset, 11 + offset] assert atta in attas_ends_1_thru_11, msg
[docs] def _validate_dresp1_force(property_type, response_type, atta, attb, atti): """helper for ``validate_dresp``""" msg = 'DRESP1 ptype=%s rtype=%s atta=%s attb=%s atti=%s' % ( property_type, response_type, atta, attb, atti) _blank_or_mode(attb, msg) if property_type == 'PROD': assert atta in [2], msg elif response_type in ['FRSTRE']: if property_type == 'PROD': assert atta in [4], msg else: raise RuntimeError(msg) assert len(atti) > 0, msg else: raise RuntimeError(msg) assert len(atti) > 0, msg
DRESP_PROPERTIES = [ 'PSHELL', 'PBAR', 'PROD', 'PCOMP', 'PCOMPG', 'PSOLID', 'PELAS', 'PBARL', 'PBEAM', 'PBEAML', 'PSHEAR', 'PTUBE', 'PBMSECT']
[docs] class DRESP1(OptConstraint): """ +--------+-------+---------+---------+--------+--------+-------+------+-------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +========+=======+=========+=========+========+========+=======+======+=======+ | DRESP1 | OID | LABEL | RTYPE | PTYPE | REGION | ATTA | ATTB | ATTI | +--------+-------+---------+---------+--------+--------+-------+------+-------+ | DRESP1 | 103 | STRESS2 | STRESS | PSHELL | | 9 | | 3 | +--------+-------+---------+---------+--------+--------+-------+------+-------+ | DRESP1 | 1S1 | CSTRAN3 | CSTRAIN | PCOMP | | 1 | 1 | 10000 | +--------+-------+---------+---------+--------+--------+-------+------+-------+ """ type = 'DRESP1' #@classmethod #def _init_from_empty(cls): #dresp_id = 103 #label = 'resp1' #response_type = 'STRESS' #property_type = 'PSHELL' #pid = 3 #atta = 9 # von mises upper surface stress #region = None #attb = None #atti = [pid] #return DRESP1(dresp_id, label, response_type, property_type, #region, atta, attb, atti, comment='', validate=False) def __init__(self, dresp_id, label, response_type, property_type, region, atta, attb, atti, comment='', validate=False): """ Creates a DRESP1 card. A DRESP1 is used to define a "simple" output result that may be optimized on. A simple result is a result like stress, strain, force, displacement, eigenvalue, etc. for a node/element that may be found in a non-optimization case. Parameters ---------- dresp_id : int response id label : str Name of the response response_type : str Response type property_type : str Element flag (PTYPE = 'ELEM'), or property entry name, or panel flag for ERP responses (PTYPE = 'PANEL' - See Remark 34), or RANDPS ID. Blank for grid point responses. 'ELEM' or property name used only with element type responses (stress, strain, force, etc.) to identify the relevant element IDs, or the property type and relevant property IDs. Must be {ELEM, PBAR, PSHELL, PCOMP, PANEL, etc.) PTYPE = RANDPS ID when RTYPE=PSDDISP, PSDVELO, or PSDACCL. region : int Region identifier for constraint screening atta : int / float / str / blank Response attribute attb : int / float / str / blank Response attribute atti : list[int / float / str] the response values to pull from list[int]: list of grid ids list of property ids list[str] 'ALL' comment : str; default='' a comment for the card validate : bool; default=False should the card be validated when it's created Examples -------- **stress/PSHELL** >>> dresp_id = 103 >>> label = 'resp1' >>> response_type = 'STRESS' >>> property_type = 'PSHELL' >>> pid = 3 >>> atta = 9 # von mises upper surface stress >>> region = None >>> attb = None >>> atti = [pid] >>> DRESP1(dresp_id, label, response_type, property_type, region, atta, attb, atti) **stress/PCOMP** >>> dresp_id = 104 >>> label = 'resp2' >>> response_type = 'STRESS' >>> property_type = 'PCOMP' >>> pid = 3 >>> layer = 4 >>> atta = 9 # von mises upper surface stress >>> region = None >>> attb = layer >>> atti = [pid] >>> DRESP1(dresp_id, label, response_type, property_type, region, atta, attb, atti) **stress/PCOMP** >>> dresp_id = 104 >>> label = 'resp2' >>> response_type = 'CSTRESS' >>> property_type = 'ELEM' >>> pid = 3 >>> layer = 4 >>> atta = 3 # ??? >>> region = None >>> attb = layer >>> atti = [eid] >>> DRESP1(dresp_id, label, response_type, property_type, region, atta, attb, atti) **displacement - not done** >>> dresp_id = 105 >>> label = 'resp3' >>> response_type = 'DISP' >>> #atta = ??? >>> #region = ??? >>> #attb = ??? >>> atti = [nid] >>> DRESP1(dresp_id, label, response_type, property_type, region, atta, attb, atti) **not done** >>> dresp_id = 105 >>> label = 'resp3' >>> response_type = 'ELEM' >>> #atta = ??? >>> #region = ??? >>> #attb = ??? >>> atti = [eid???] >>> DRESP1(dresp_id, label, response_type, property_type, region, atta, attb, atti) """ OptConstraint.__init__(self) if comment: self.comment = comment self.dresp_id = dresp_id self.label = label # DISP, VONMISES, 14 response_type_dict = { 'compliance': 'CMPLNCE', } response_type = response_type_dict.get(response_type.lower(), response_type) self.response_type = response_type # PSHELL, PCOMP, PBAR, etc. self.property_type = property_type self.region = region if atti is None: atti = [] elif isinstance(atti, integer_types): atti = [atti] assert isinstance(atti, list), 'atti=%s type=%s' % (atti, type(atti)) if validate: atta, attb, atti = validate_dresp1(label, property_type, response_type, atta, attb, atti) self.atta = atta self.attb = attb self.atti = atti self.atta_ref = None self.atti_ref = None
[docs] @classmethod def export_to_hdf5(cls, h5_file, model, encoding): """exports the dresps in a vectorized way""" _export_dresps_to_hdf5(h5_file, model, encoding)
[docs] def object_attributes(self, mode='public', keys_to_skip=None, filter_properties=False): """.. seealso:: `pyNastran.utils.object_attributes(...)`""" if keys_to_skip is None: keys_to_skip = [] my_keys_to_skip = ['rtype', 'ptype'] return super(DRESP1, self).object_attributes( mode=mode, keys_to_skip=keys_to_skip+my_keys_to_skip, filter_properties=filter_properties)
@property def rtype(self): return self.response_type @rtype.setter def rtype(self, response_type): self.response_type = response_type @property def ptype(self): return self.property_type @ptype.setter def ptype(self, property_type): self.property_type = property_type
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a DRESP1 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ oid = integer(card, 1, 'oid') label = string(card, 2, 'label') #label = loose_string(card, 2, 'label') response_type = string(card, 3, 'rtype') # elem, pbar, pshell, etc. (ELEM flag or Prop Name) property_type = integer_string_or_blank(card, 4, 'ptype') region = integer_or_blank(card, 5, 'region') atta = integer_double_string_or_blank(card, 6, 'atta') attb = integer_double_string_or_blank(card, 7, 'attb') atti = [] for i in range(8, len(card)): attii = integer_double_string_or_blank(card, i, 'atti_%i' % (i + 1)) atti.append(attii) return DRESP1(oid, label, response_type, property_type, region, atta, attb, atti, comment=comment, validate=False)
def _verify(self, model: BDF, xref): if not xref: return node_types = { 'DISP', 'FRDISP', 'PSDDISP', 'RMSDISP', 'TDISP', # 'RFDISP', 'FRVELO', 'RMSVELO', 'PSDVELO', 'TVELO', 'FRACCL', 'RMSACCL', 'PSDACCL', 'TACCL', 'FRSPCF', 'SPCFORCE', 'TSPCF', } no_validate = { 'FRMASS', 'WEIGHT', 'EIGN', 'LAMA', 'VOLUME', 'FREQ', 'ERP', 'FLUTTER', 'CFAILURE', 'CSTRAT', 'CEIG', 'DIVERG', 'STABDER', 'TRIM', 'ESE', 'TOTSE', 'GPFORCE', 'GPFORCP', 'FATIGUE'} not_implemented = no_validate no_validate.update(not_implemented) no_validate.update(node_types) elem_props = {'STRESS', 'TSTRE', 'FRSTRE', 'CSTRESS', 'STRAIN', 'CSTRAIN', 'FORCE', 'TFORC', 'FRFORC', } if self.response_type in no_validate: return elif self.response_type in elem_props: property_type = self.property_type #if property_type is None: #continue if property_type == 'ELEM': _dresp_verify_eids(self, model) else: _dresp_verify_prop(self, model, property_type) else: print(self.get_stats()) raise NotImplementedError(self.response_type)
[docs] def calculate(self, op2_model, subcase_id): rtype = self.rtype property_type = self.property_type if rtype == 'DISP' and property_type is None: msg = 'fields=%s\n' % (self.raw_fields()) msg += 'rtype=%r ptype=%r region=%s A=%r B=%r\n' % ( self.rtype, self.property_type, self.region, self.atta, self.attb) assert isinstance(self.atta, integer_types), self.atta assert self.attb is None, self.attb assert len(self.atti) == 1, self.atti #msg += str(self) #raise NotImplementedError(msg) comp = self.atta assert comp < 7, comp case = op2_model.displacements[subcase_id] nids = case.node_gridtype[:, 0] nidsi = np.array( [node if isinstance(node, integer_types) else node.nid for node in self.atti], dtype='int32') inid = np.searchsorted(nids, nidsi)[0] itime = 0 # TODO: ??? #print('atti = ', self.atti) unused_atti = self.atti[0] out = case.data[itime, inid, comp - 1] #print(' DISP[itime=%s, nid=%s, comp=%i] = %s' % (itime, str(nidsi), comp, out)) elif property_type == 'ELEM' and 0: pass else: msg = 'fields=%s\n' % (self.raw_fields()) msg += 'response_type=%r property_type=%r region=%s\n' % ( self.response_type, self.property_type, self.region) msg += str(self) raise NotImplementedError(msg) return out
[docs] def OptID(self): return self.DRespID()
[docs] def DRespID(self): return self.dresp_id
[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 = f', which is required by DRESP1 dresp_id={self.dresp_id}\n{self}' op2_results = { 'VOLUME', 'LAMA', 'FRSPCF', 'TRIM', 'ESE', 'SPCFORCE', 'FRMASS', 'CFAILURE', 'CSTRAT', 'STRESS', 'DIVERG', 'TOTSE', 'COMP', 'TACCL', 'RMSACCL', 'RMSVELO', 'PSDDISP', 'RMSDISP', 'TFORC', 'FRFORC', 'TSPCF', } if self.property_type == 'ELEM': self.atti_ref = model.Elements(self.atti, msg=msg) elif self.property_type in DRESP_PROPERTIES: self.atti_ref = model.Properties(self.atti, msg=msg) elif self.response_type in ['FRSTRE']: self.atti_ref = model.Properties(self.atti, msg=msg) elif self.response_type in {'WEIGHT', 'STABDER', 'CEIG', 'EIGN', 'FREQ', 'CMPLNCE'}: # nothing pass elif self.response_type == 'FLUTTER': # TODO: SOL-200; add check that FLFACT values exist in the FLFACT card # referenced by the FLUTTER card for the given subcase if self.property_type == 'PKNL': self.atti_ref = [ model.Set(self.atti[0], msg=msg), model.FLFACT(self.atti[1], msg=msg), model.FLFACT(self.atti[2], msg=msg), model.FLFACT(self.atti[3], msg=msg), ] #msgi = 'max density=%s mach=%s velocity=%s' % ( #self.atti[1].max(), self.atti[2].max(), self.atti[3].max()) #print(msgi) elif self.property_type is None: pass else: msg = 'PropertyType=%r is not supported\n' % self.property_type msg += str(self) print(msg) elif self.response_type in {'DISP', 'TDISP', 'TVELO', 'FRDISP', 'FRVELO', 'FRACCL', 'PSDVELO', 'PSDACCL'}: self.atti_ref = model.Nodes(self.atti, msg=msg) elif self.response_type in op2_results: pass elif self.response_type == 'ERP': assert self.property_type == 'PANEL' elif self.response_type == 'GPFORCP': assert len(self.atti) >= 1, 'atti=%r\n%s' % (self.atti, self) self.atta_ref = model.Node(self.atta, msg=msg) self.atti_ref = model.Nodes(self.atti, msg=msg) elif self.response_type == 'GPFORCE': #self.atta = component eids = [eid for eid in self.atti if eid is not None] self.atti_ref = model.Elements(eids, msg=msg) elif self.response_type == 'ABSTRESS': # atta - Arbitrary Beam Stress Item Code self.atti_ref = model.Properties(self.atti, msg=msg) elif self.response_type == 'DWEIGHT': pass else: msg = 'response_type=%r ptype=%r\n' % (self.response_type, self.property_type) msg += str(self) raise NotImplementedError(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 DRESP1 dresp_id=%s' % (self.dresp_id) msg += '\n' + str(self) op2_results = [ 'VOLUME', 'LAMA', 'FRSPCF', 'TRIM', 'ESE', 'SPCFORCE', 'FRMASS', 'CFAILURE', 'CSTRAT', 'STRESS', 'DIVERG', 'TOTSE', 'COMP', 'TACCL', 'RMSACCL', 'RMSVELO', 'PSDDISP', 'RMSDISP', 'TFORC', 'FRFORC', 'TSPCF', ] ref_id = self.dresp_id if self.property_type == 'ELEM': self.atti_ref = model.safe_elements(self.atti, ref_id, xref_errors, msg=msg) elif self.property_type in DRESP_PROPERTIES: self.atti_ref = model.Properties(self.atti, msg=msg) elif self.response_type in ['FRSTRE']: self.atti_ref = model.Properties(self.atti, msg=msg) elif self.response_type in ['WEIGHT', 'STABDER', 'CEIG', 'EIGN', 'FREQ']: pass elif self.response_type == 'FLUTTER': # TODO: SOL-200; add check that FLFACT values exist in the FLFACT card # referenced by the FLUTTER card for the given subcase if self.property_type == 'PKNL': self.atti_ref = [ model.Set(self.atti[0], msg=msg), model.FLFACT(self.atti[1], msg=msg), model.FLFACT(self.atti[2], msg=msg), model.FLFACT(self.atti[3], msg=msg), ] #msgi = 'max density=%s mach=%s velocity=%s' % ( #self.atti[1].max(), self.atti[2].max(), self.atti[3].max()) #print(msgi) elif self.property_type is None: pass else: msg = 'PropertyType=%r is not supported\n' % self.property_type msg += str(self) print(msg) elif self.response_type in ['DISP', 'TDISP', 'TVELO', 'FRDISP', 'FRVELO', 'FRACCL', 'PSDVELO', 'PSDACCL']: self.atti_ref = model.Nodes(self.atti, msg=msg) elif self.response_type in op2_results: pass elif self.response_type == 'ERP': assert self.property_type == 'PANEL' elif self.response_type == 'GPFORCP': assert len(self.atti) >= 1, 'atti=%r\n%s' % (self.atti, self) self.atta_ref = model.Node(self.atta, msg=msg) self.atti_ref = model.Nodes(self.atti, msg=msg) elif self.response_type == 'GPFORCE': #self.atta = component eids = [eid for eid in self.atti if eid is not None] self.atti_ref = model.Elements(eids, msg=msg) elif self.response_type == 'ABSTRESS': # atta - Arbitrary Beam Stress Item Code self.atti_ref = model.Properties(self.atti, msg=msg) elif self.response_type in {'CMPLNCE', 'DWEIGHT'}: pass else: msg = 'response_type=%r ptype=%r\n' % (self.response_type, self.property_type) msg += str(self) raise NotImplementedError(msg)
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.atti = self.atti_values() self.atta = self.Atta() self.atta_ref = None self.atti_ref = None
[docs] def Atta(self): """returns the values of ATTa""" if self.response_type in ['GPFORCE', 'GPFORCP']: atta = self.atta_ref.nid if self.atta_ref is not None else self.atta else: assert self.atta_ref is None, self.get_stats() atta = self.atta return atta
[docs] def atti_values(self): """returns the values of ATTi""" if self.atti_ref is None: return self.atti #return self.atti #if self.response_type in ['ELEM']: #self.atti = model.Elements(self.atti, msg=msg) #pass op2_results = [ 'VOLUME', 'CEIG', 'LAMA', 'FREQ', 'FRSPCF', 'TRIM', 'ESE', 'SPCFORCE', 'FRMASS', 'CFAILURE', 'CSTRAT', 'STRESS', 'DIVERG', 'TOTSE', 'COMP', 'TACCL', 'RMSACCL', 'PSDDISP', 'RMSDISP', 'TVELO', 'RMSVELO', 'TFORC', 'FRFORC', 'TSPCF', ] #print('self.atti_ref =', self.atti_ref) if self.property_type == 'ELEM': data = self._elements() elif self.property_type in DRESP_PROPERTIES: data = self._properties() elif self.response_type == 'FRSTRE': data = self._properties() elif self.response_type in ['WEIGHT', 'STABDER', 'EIGN', 'FREQ']: data = self.atti elif self.response_type == 'FLUTTER': if self.property_type == 'PKNL': data = [atti if isinstance(atti, integer_types) else atti.sid for atti in self.atti_ref] else: data = self.atti #msg = 'PropertyType=%r is not supported\n' % self.property_type #msg += str(self) #print(msg) #raise NotImplementedError(msg) elif self.response_type in ['DISP', 'TDISP', 'TVELO', 'FRDISP', 'FRVELO', 'FRACCL', 'PSDVELO', 'PSDACCL']: data = self._nodes() elif self.response_type in ['FRFORC', 'TFORC', 'STRESS', 'STRAIN', 'ESE', 'CFAILURE', 'CSTRAIN']: data = self._elements() elif self.response_type in op2_results: data = self.atti for value in data: assert not isinstance(value, BaseCard), 'response_type=%s value=%s' % (self.response_type, value) elif self.response_type in ['GPFORCP']: # MSC Nastran specific data = self._nodes() elif self.response_type in ['GPFORCE']: # MSC data = self._elements() elif self.response_type in ['ERP']: msg = 'response_type=%r property_type=%r atta=%r attb=%r atti=%r\n' % ( self.response_type, self.property_type, self.atta, self.attb, self.atti) assert self.property_type == 'PANEL', msg # atta=None attb=3000.0 atti=[555] data = self.atti elif self.response_type == 'ABSTRESS': ## atta - Arbitrary Beam Stress Item Code #ids = [idi for idi in self.atti if idi is not None] data = self._properties() elif self.response_type in {'CMPLANCE'}: asdf else: msg = 'response_type=%r property_type=%r atta=%r attb=%r atti=%r\n' % ( self.response_type, self.property_type, self.atta, self.attb, self.atti) #msg += str(self) raise NotImplementedError(msg) return data
[docs] def _nodes(self): """helper method""" data = [node if isinstance(node, integer_types) else node.nid for node in self.atti_ref] #self.atti = data return data
[docs] def _elements(self): """helper method""" data = [eid if elem is None else elem.eid for (eid, elem) in zip(self.atti, self.atti_ref)] #self.atti = data return data
[docs] def _properties(self): """helper method""" data = [pid if prop is None else prop.pid for (pid, prop) in zip(self.atti, self.atti_ref)] #self.atti = data #self.atti_ref = None return data
[docs] def raw_fields(self): list_fields = ['DRESP1', self.dresp_id, self.label, self.response_type, self.property_type, self.region, self.Atta(), self.attb] + self.atti_values() return list_fields
[docs] def repr_fields(self): """ Gets the fields in their simplified form Returns ------- fields : list[varies] the fields that define the card """ label = self.label.strip() if len(label) <= 6: label = ' %6s ' % label list_fields = ['DRESP1', self.dresp_id, self.label, self.response_type, self.property_type, self.region, self.Atta(), self.attb] + self.atti_values() 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] def _dresp_verify_eids(dresp: DRESP1, model: BDF, property_type: str): #if property_type == 'ELEM': eids2 = dresp.atti valid_etypes = { 'CROD', 'CONROD', 'CELAS', 'CBAR', 'CBEAM', 'CTRIA3', 'CQUAD4', 'CTRIA6', 'CQUAD8', 'CSHEAR', 'CHEXA', 'CTETRA', 'CPENTA', 'CPYRAM', 'CFAST', } for eid in eids2: element = model.elements[eid] assert element.type in valid_etypes, f'valid={valid_etypes}\n{element.get_stats()}'
[docs] def _dresp_verify_prop(dresp: DRESP1, model: BDF, property_type: str) -> None: valid_properties_map = { 'PSOLID' : {'PSOLID'}, 'PSHELL' : {'PSHELL'}, 'PBAR' : {'PBAR', 'PBARL'}, 'PBARL' : {'PBARL'}, 'PBEAM' : {'PBEAM', 'PBEAML'}, 'PBEAML' : {'PBEAML'}, 'PROD' : {'PROD'}, 'PELAS' : {'PELAS'}, #'PDAMP' : {'PDAMP'}, 'PSHEAR' : {'PSHEAR'}, 'PCOMP' : {'PCOMP'}, # 'PCOMPG'}, 'PTUBE' : {'PTUBE'}, 'PBMSECT' : {'PBMSECT'}, 'PBRSECT' : {'PBRSECT'}, } properties = set(valid_properties_map) property_to_etypes_map = { 'PSOLID' : {'CHEXA', 'CTETRA', 'CPENTA', 'CPYRAM'}, 'PSHELL' : {'CTRIA3', 'CQUAD4', 'CTRIA6', 'CQUAD8', 'CQUADR'}, 'PBAR' : {'CBAR'}, 'PBARL' : {'CBAR'}, 'PROD' : {'CROD'}, 'PELAS' : {'CELAS1'}, # no CELAS4 #'PDAMP' : {}, # no CDAMP4 'PSHEAR' : {'CSHEAR'}, 'PCOMP' : {'CTRIA3', 'CQUAD4', 'CTRIA6', 'CQUAD8'}, 'PBEAM': {'CBEAM'}, 'PBEAML': {'CBEAM'}, 'PTUBE': {'CTUBE'}, 'PCOMPG': {}, 'PLPLANE': {}, #'PPPLANE': {}, 'PBRSECT' : {'CBAR'}, 'PBMSECT': {'CBEAM'}, } try: valid_properties = valid_properties_map[property_type] valid_etypes = property_to_etypes_map[property_type] except KeyError: print(dresp.get_stats()) raise if property_type in properties: assert dresp.atti_ref is not None, dresp.get_stats() assert len(dresp.atti_ref) > 0, dresp.get_stats() props = dresp.atti_ref else: print(dresp.get_stats()) raise NotImplementedError(property_type) for prop in props: assert prop.type in valid_properties, f'prop.type={prop.type!r} property_type={property_type!r} valid_properties={valid_properties}\nproperty=\n{prop.get_stats()}' pid = prop.pid eids1 = model.get_element_ids_list_with_pids(pid) eids_dict = model.get_element_ids_dict_with_pids() assert pid in eids_dict, f'pid={pid} actual_properties={list(eids_dict.keys())}' eids2 = eids_dict[pid] eids1.sort() eids2.sort() assert eids1 == eids2 assert len(eids2) > 0, f'Error: no elements; eids2={eids2}\n pid={pid} valid={valid_etypes}\n{dresp}' for eid in eids2: element = model.elements[eid] assert element.type in valid_etypes, f'pid={pid} valid={valid_etypes}\n{element.get_stats()}'
DRESP2_PACK_LENGTH = { 'DESVAR' : (1, 0), 'DTABLE' : (1, 0), 'DFRFNC' : (1, 0), 'DRESP1' : (1, 0), 'DNODE' : (1, 1), # unique entry 'DVPREL1' : (1, 0), 'DVCREL1' : (1, 0), 'DVMREL1' : (1, 0), 'DVPREL2' : (1, 0), 'DVCREL2' : (1, 0), 'DVMREL2' : (1, 0), 'DRESP2' : (1, 0), }
[docs] class DRESP2(OptConstraint): """ Design Sensitivity Equation Response Quantities Defines equation responses that are used in the design, either as constraints or as an objective. +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +========+=========+========+===========+========+========+========+========+========+ | DRESP2 | ID | LABEL | EQID/FUNC | REGION | METHOD | C1 | C2 | C3 | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | DESVAR | DVID1 | DVID2 | DVID3 | DVID4 | DVID5 | DVID6 | DVID7 | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | | DVID8 | etc. | | | | | | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | DTABLE | LABL1 | LABL2 | LABL3 | LABL4 | LABL5 | LABL6 | LABL7 | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | | LABL8 | etc. | | | | | | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | DRESP1 | NR1 | NR2 | NR3 | NR4 | NR5 | NR6 | NR7 | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | | NR8 | etc. | | | | | | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | DNODE | G1 | C1 | G2 | C2 | G3 | C3 | | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | | G4 | C4 | etc. | | | | | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | DVPREL1 | DPIP1 | DPIP2 | DPIP3 | DPIP4 | DPIP5 | DPIP6 | DPIP7 | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | | DPIP8 | DPIP9 | etc. | | | | | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | DVCREL1 | DCIC1 | DCIC2 | DCIC3 | DCIC4 | DCIC5 | DCIC6 | DCIC7 | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | | DCIC8 | DCIC9 | etc. | | | | | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | DVMREL1 | DMIM1 | DMIM2 | DMIM3 | DMIM4 | DMIM5 | DMIM6 | DMIM7 | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | | DMIM8 | DMIM9 | etc. | | | | | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | DVPREL2 | DPI2P1 | DPI2P2 | DPI2P3 | DPI2P4 | DPI2P5 | DPI2P6 | DPI2P7 | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | | DPI2P8 | DPI2P9 | etc. | | | | | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | DVCREL2 | DCI2C1 | DCI2C2 | DCI2C3 | DCI2C4 | DCI2C5 | DCI2C6 | DCI2C7 | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | | DCI2C8 | DCI2C9 | etc. | | | | | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | DVMREL2 | DMI2M1 | DMI2M2 | DMI2M3 | DMI2M4 | DMI2M5 | DMI2M6 | DMI2M7 | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | | DMI2M8 | DMI2M9 | etc. | | | | | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | DRESP2 | NRR1 | NRR2 | NRR3 | NRR4 | NRR5 | NRR6 | NRR7 | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | | NRR8 | etc. | | | | | | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | DVLREL1 | DLIL1 | DLIL2 | DLIL3 | DLIL4 | DLIL5 | DLIL6 | DLIL7 | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ | | | DLIL8 | etc. | | | | | | +--------+---------+--------+-----------+--------+--------+--------+--------+--------+ C1, C2, C3 are MSC specific """ type = 'DRESP2' def __init__(self, dresp_id, label, dequation, region, params, method='MIN', c1=1., c2=0.005, c3=10., comment='', validate=False): """ Creates a DRESP2 card. A DRESP2 is used to define a "complex" output result that may be optimized on. A complex result is a result that uses: - simple (DRESP1) results - complex (DRESP2) results - default values (DTABLE) - DVCRELx values - DVMRELx values - DVPRELx values - DESVAR values - DNODE values Then, an equation (DEQATN) is used to formulate an output response. Parameters ---------- dresp_id : int response id label : str Name of the response dequation : int / str int : DEQATN id str : an equation region : int Region identifier for constraint screening params : dict[(index, card_type)] = values the storage table for the response function index : int a counter card_type : str the type of card to pull from DESVAR, DVPREL1, DRESP2, etc. values : list[int] the values for this response method : str; default=MIN flag used for FUNC=BETA/MATCH FUNC = BETA valid options are {MIN, MAX} FUNC = MATCH valid options are {LS, BETA} c1 / c2 / c3 : float; default=1. / 0.005 / 10.0 constants for FUNC=BETA or FUNC=MATCH comment : str; default='' a comment for the card validate : bool; default=False should the card be validated when it's created params = { (0, 'DRESP1') = [10, 20], (1, 'DESVAR') = [30], (2, 'DRESP1') = [40], } """ OptConstraint.__init__(self) if comment: self.comment = comment self.func = None self.dequation_str = None self.dresp_id = dresp_id self.label = label self.dequation = dequation self.region = region self.method = method # Constants used when FUNC = BETA or FUNC = MATCH in combination with METHOD = BETA # MSC 2016.1 Defaults: C1 = 1.0, C2=0.005, and C3=10.0) self.c1 = c1 self.c2 = c2 self.c3 = c3 self.params = params self.params_ref = None self.dequation_ref = None self.dtable_ref = None if validate: self._validate() #atta, attb, atti = validate_dresp1( #property_type, response_type, atta, attb, atti)
[docs] @classmethod def export_to_hdf5(cls, h5_file, model, encoding): """exports the dresps in a vectorized way""" _export_dresps_to_hdf5(h5_file, model, encoding)
[docs] def _validate(self): assert isinstance(self.params, dict), self.params if len(self.params) == 0: msg = ( 'params should be of the form: params[(index, card_type)] = values\n' 'For example:\n' ' params = {\n' " (0, 'DRESP1'): [1, 2, 3]\n" " (1, 'DTABLE'): ['X', 'X2', 'X3']\n" " (2, 'DRESP1'): [4, 5]\n" '}') raise RuntimeError(msg) ifield = 9 ikey = 0 for key, values in self.params.items(): nvalues = len(values) assert isinstance(key, tuple), f"key={key} should be of the form (0, 'DRESP1'), (1, 'DTABLE'), (2, 'DRESP1'), ..." assert len(key) == 2, f'key={key}' iorder, name = key assert isinstance(iorder, int), f'iorder={iorder} key={key}' assert isinstance(name, str), f'name={name!r} key={key}' if name == 'DNODE': assert len(values) == 2, f'name={name!r} must be a tuple of length 2 (nids, components); values={values}' nids, components = values for nid in nids: assert isinstance(nid, int), f'name={name!r} nid={nid!r} is not an int; values={values}' for comp in components: assert isinstance(comp, int), f'name={name!r} comp={comp!r} is not an int; values={values}' elif name == 'DTABLE': for ival, svalue in enumerate(values): fieldname = f'{key}_i={ival+1}' #assert isinstance(svalue, str), f'name={name!r} val={val!r} is not a string; values={values}' check_string(svalue, ifield, fieldname) else: for val in values: assert isinstance(val, int), f'name={name!r} val={val!r} is not an int; values={values}' remainder = min(1, nvalues % 8) dfields = (nvalues // 8 + remainder) * 8 ifield += dfields ikey += 1
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a DRESP2 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ dresp_id = integer(card, 1, 'dresp_id') label = string(card, 2, 'label') dequation = integer_or_string(card, 3, 'dequation_id') region = integer_or_blank(card, 4, 'region') method = string_or_blank(card, 5, 'method', default='MIN') # MSC 2005 Defaults: C1=100., C2=.005) # MSC 2016.1 Defaults: C1=1., C2=.005, C3=10.) c1 = double_or_blank(card, 6, 'c1', default=1.) c2 = double_or_blank(card, 7, 'c2', default=0.005) c3 = double_or_blank(card, 8, 'c3', default=10.) fields = [interpret_value(field) for field in card[9:]] # DRESP2, dresp_id, # DRESP1, 10, 20 # DESVAR, 30 # DRESP1, 40 # params = { # (0, 'DRESP1') = [10, 20], # (1, 'DESVAR') = [30], # (2, 'DRESP1') = [40], # } params = parse_table_fields('DRESP2', card, fields) #print("--DRESP2 Params--") #for key, value_list in sorted(params.items()): #print(" key=%s value_list=%s" %(key, value_list)) return DRESP2(dresp_id, label, dequation, region, params, method, c1, c2, c3, comment=comment)
[docs] def OptID(self): return self.DRespID()
[docs] def DRespID(self): return self.dresp_id
def _verify(self, model, xref): pass #for (j, name), value_list in sorted(self.params.items()): #print(' DRESP2 verify - key=%s values=%s' % (name, #self._get_values(name, value_list)))
[docs] def calculate(self, op2_model, subcase_id): argsi = [] for key, vals in sorted(self.params_ref.items()): unused_j, name = key if name in ['DRESP1', 'DRESP2']: #print('vals =', vals) for val in vals: arg = val.calculate(op2_model, subcase_id) argsi.append(arg) elif name in ['DVMREL1', 'DVMREL2']: for val in vals: arg = val.calculate(op2_model, subcase_id) argsi.append(arg) elif name in ['DVPREL1', 'DVPREL2']: for val in vals: arg = val.calculate(op2_model, subcase_id) argsi.append(arg) elif name == 'DTABLE': for val in vals: arg = self.dtable_ref[val] argsi.append(arg) else: raise NotImplementedError(' TODO: xref %s' % str(key)) #op2_model.log.info('DRESP2 args = %s' % argsi) out = self.func(*argsi) op2_model.log.info(' deqatn out = %s' % out) return out
[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 """ #if model.dtable is not None: #model.log.debug(model.dtable.rstrip()) msg = f', which is required by DRESP2 ID={self.dresp_id}' default_values = {} params_ref = {} for key, vals in sorted(self.params.items()): try: unused_j, name = key except Exception: raise RuntimeError(str(self)) #print(j, name) if name in ['DRESP1', 'DRESP2']: params_ref[key] = [] for unused_i, val in enumerate(vals): params_ref[key].append(model.DResp(val, msg)) elif name in ['DVCREL1', 'DVCREL2']: params_ref[key] = [] for val in vals: params_ref[key].append(model.DVcrel(val, msg)) elif name in ['DVMREL1', 'DVMREL2']: params_ref[key] = [] for unused_i, val in enumerate(vals): params_ref[key].append(model.DVmrel(val, msg)) elif name in ['DVPREL1', 'DVPREL2']: params_ref[key] = [] for unused_i, val in enumerate(vals): params_ref[key].append(model.DVprel(val, msg)) elif name == 'DESVAR': params_ref[key] = [] for unused_i, val in enumerate(vals): params_ref[key].append(model.Desvar(val, msg)) elif name == 'DTABLE': #model.log.info('bdf_filename = %s' % model.bdf_filename) #model.log.info('\n' + model.dtable.rstrip()) self.dtable_ref = model.dtable #print('dtable =', self.dtable) names = [] for unused_i, val in enumerate(vals): default_values[val] = self.dtable_ref[val] names.append(val) params_ref[key] = names del names, vals elif name == 'DNODE': params_ref[key] = [[], []] node_vals, component_vals = vals for nid in node_vals: params_ref[key][0].append(model.Node(nid, msg)) params_ref[key][1] = component_vals del node_vals, component_vals, vals else: raise NotImplementedError(f' TODO: xref {key}\n{self}') # what does this do??? #for key, value_list in sorted(self.params.items()): #j, name = key #values_list2 = self._get_values(name, value_list) #self.params[key] = values_list2 self.params_ref = params_ref if isinstance(self.DEquation(), integer_types): self.dequation_ref = model.DEQATN(self.dequation, msg=msg) self.func = self.dequation_ref.func elif isinstance(self.dequation, str): self.func = fortran_to_python_short(self.dequation, default_values) else: raise NotImplementedError(self.dequation)
[docs] def safe_cross_reference(self, model: BDF, xref_errors): self.cross_reference(model)
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" if hasattr(self, 'func'): del self.func params = {} for key, value_list in sorted(self.params_ref.items()): unused_j, name = key values_list2 = _get_dresp23_table_values(name, value_list) params[key] = values_list2 self.params = params self.params_ref = None self.dequation = self.DEquation() self.dequation_ref = None
[docs] def DEquation(self): if self.dequation_ref is None: return self.dequation return self.dequation_ref.equation_id
[docs] def _pack_params(self): if self.params_ref is None: # not cross-referenced return self._pack(self.params) # cross-referenced return self._pack(self.params_ref)
[docs] def _pack(self, params: list[Any]): """packs the params/params_ref into a form for output""" # # the amount of padding at the [beginning,end] of the 2nd line list_fields = [] for (j, name), value_list in sorted(params.items()): values_list2 = _get_dresp23_table_values(name, value_list, inline=True) fields2 = [name] + values_list2 #try: (i, j) = DRESP2_PACK_LENGTH[name] #except KeyError: #msg = 'INVALID DRESP2 name=%r fields=%s ID=%s' % (name, value_list, self.oid) #raise KeyError(msg) list_fields += build_table_lines(fields2, nstart=i, nend=j) return list_fields
[docs] def raw_fields(self): list_fields = ['DRESP2', self.dresp_id, self.label, self.DEquation(), self.region, self.method, self.c1, self.c2, self.c3] list_fields += self._pack_params() return list_fields
[docs] def repr_fields(self): method = set_blank_if_default(self.method, 'MIN') c1 = None c2 = None c3 = None if self.method == 'BETA': if 'BETA' in self.func or 'MATCH' in self.func: # MSC 2005 Defaults: C1=100., C2=.005) # MSC 2016.1 Defaults: C1=1., C2=.005, C3=10.) c1 = set_blank_if_default(self.c1, 100.) c2 = set_blank_if_default(self.c2, 0.005) c3 = set_blank_if_default(self.c3, 10.) list_fields = ['DRESP2', self.dresp_id, self.label, self.DEquation(), self.region, method, c1, c2, c3] list_fields += self._pack_params() 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 DRESP3(OptConstraint): """ +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +========+=========+========+========+========+========+========+========+========+ | DRESP3 | ID | LABEL | GROUP | TYPE | REGION | | | | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | DESVAR | DVID1 | DVID2 | DVID3 | DVID4 | DVID5 | DVID6 | DVID7 | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | | DVID8 | etc. | | | | | | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | DTABLE | LABL1 | LABL2 | LABL3 | LABL4 | LABL5 | LABL6 | LABL7 | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | | LABL8 | etc. | | | | | | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | DRESP1 | NR1 | NR2 | NR3 | NR4 | NR5 | NR6 | NR7 | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | | NR8 | etc. | | | | | | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | DNODE | G1 | C1 | G2 | C2 | G3 | C3 | | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | | G4 | C4 | etc. | | | | | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | DVPREL1 | DPIP1 | DPIP2 | DPIP3 | DPIP4 | DPIP5 | DPIP6 | DPIP7 | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | | DPIP8 | DPIP9 | etc. | | | | | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | DVCREL1 | DCIC1 | DCIC2 | DCIC3 | DCIC4 | DCIC5 | DCIC6 | DCIC7 | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | | DCIC8 | DCIC9 | etc. | | | | | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | DVMREL1 | DMIM1 | DMIM2 | DMIM3 | DMIM4 | DMIM5 | DMIM6 | DMIM7 | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | | DMIM8 | DMIM9 | etc. | | | | | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | DVPREL2 | DPI2P1 | DPI2P2 | DPI2P3 | DPI2P4 | DPI2P5 | DPI2P6 | DPI2P7 | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | | DPI2P8 | DPI2P9 | etc. | | | | | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | DVCREL2 | DCI2C1 | DCI2C2 | DCI2C3 | DCI2C4 | DCI2C5 | DCI2C6 | DCI2C7 | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | | DCI2C8 | DCI2C9 | etc. | | | | | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | DVMREL2 | DMI2M1 | DMI2M2 | DMI2M3 | DMI2M4 | DMI2M5 | DMI2M6 | DMI2M7 | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | | DMI2M8 | DMI2M9 | etc. | | | | | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | DRESP2 | NRR1 | NRR2 | NRR3 | NRR4 | NRR5 | NRR6 | NRR7 | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | | NRR8 | etc. | | | | | | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | DVLREL1 | DLIL1 | DLIL2 | DLIL3 | DLIL4 | DLIL5 | DLIL6 | DLIL7 | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | | DLIL8 | etc. | | | | | | +--------+---------+--------+--------+--------+--------+--------+--------+--------+ | | USRDATA | String | +--------+---------+--------------------------------------------------------------+ | | | etc. | +--------+---------+--------------------------------------------------------------+ """ type = 'DRESP3' def __init__(self, dresp_id, label, group, Type, region, params, validate=False, comment=''): """ Creates a DRESP3 card. A DRESP3 is used to define a "complex" output result that may be optimized on. A complex result is a result that uses: - simple (DRESP1) results - complex (DRESP2) results - default values (DTABLE) - DVCRELx values - DVMRELx values - DVPRELx values - DESVAR values - DNODE values - DVLREL1 values - USRDATA Then, an secondary code (USRDATA) is used to formulate an output response. Parameters ---------- dresp_id : int response id label : str Name of the response group : str Selects a specific external response routine Type : str Refers to a specific user-created response calculation type in the external function evaluator region : str Region identifier for constraint screening params : dict[(index, card_type)] = values the storage table for the response function index : int a counter card_type : str the type of card to pull from DESVAR, DVPREL1, DRESP2, etc. values : list[int] the values for this response comment : str; default='' a comment for the card validate : bool; default=False should the card be validated when it's created params = { (0, 'DRESP1') = [10, 20], (1, 'DESVAR') = [30], (2, 'DRESP1') = [40], } """ OptConstraint.__init__(self) if comment: self.comment = comment self.dresp_id = dresp_id self.label = label self.group = group self.Type = Type self.region = region self.params = params if validate: self._validate() self.params_ref = None self.dtable_ref = {}
[docs] @classmethod def export_to_hdf5(cls, h5_file, model, encoding): """exports the dresps in a vectorized way""" _export_dresps_to_hdf5(h5_file, model, encoding)
[docs] def _validate(self): assert isinstance(self.params, dict), self.params assert isinstance(self.group, str), 'group=%r' % self.group assert isinstance(self.Type, str), 'Type=%r' % self.Type for key, values in self.params.items(): assert isinstance(key, tuple), 'key=%s' % str(key) assert len(key) == 2, 'key=%s' % str(key) iorder, name = key assert isinstance(iorder, int), 'iorder=%s key=%s' % (iorder, str(key)) assert isinstance(name, str), 'name=%r key=%s' % (name, str(key)) if name == 'DNODE': assert len(values) == 2, 'name=%r must be a tuple of length 2 (nids, components); values=%s' % (name, values) nids, components = values for nid in nids: assert isinstance(nid, int), 'name=%r nid=%r is not an int; values=%s' % (name, nid, values) for comp in components: assert isinstance(comp, int), 'name=%r comp=%r is not an int; values=%s' % (name, comp, values) else: for val in values: assert isinstance(val, int), 'name=%r val=%r is not an int; values=%s' % (name, val, values)
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a DRESP3 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ dresp_id = integer(card, 1, 'dresp_id') label = string(card, 2, 'label') group = string(card, 3, 'group') Type = string(card, 4, 'Type') region = integer_or_blank(card, 5, 'region') list_fields = [interpret_value(field) for field in card[9:]] # DRESP3, dresp_id, # DRESP1, 10, 20 # DESVAR, 30 # DRESP1, 40 # params = { # (0, 'DRESP1') = [10, 20], # (1, 'DESVAR') = [30], # (2, 'DRESP1') = [40], # } params = parse_table_fields('DRESP3', card, list_fields) return DRESP3(dresp_id, label, group, Type, region, params, comment=comment)
[docs] def _pack_params(self): if self.params_ref is None: return self._pack(self.params) return self._pack(self.params_ref)
[docs] def _pack(self, params): """packs the params/params_ref into a form for output""" # # the amount of padding at the [beginning,end] of the 2nd line pack_length = { 'DESVAR' : [1, 0], 'DTABLE' : [1, 0], 'DFRFNC' : [1, 0], 'DRESP1' : [1, 0], 'DNODE' : [1, 1], # unique entry 'DVPREL1' : [1, 0], 'DVCREL1' : [1, 0], 'DVMREL1' : [1, 0], 'DVPREL2' : [1, 0], 'DVCREL2' : [1, 0], 'DVMREL2' : [1, 0], 'DRESP2' : [1, 0], 'USRDATA' : [1, 0], } #print('------------') list_fields = [] for key, value_list in sorted(params.items()): #print(params[key]) unused_iorder, name = key values_list2 = _get_dresp23_table_values(name, value_list, inline=True) fields2 = [name] + values_list2 try: (i, j) = pack_length[name] except KeyError: msg = 'INVALID DRESP3 key=%r fields=%s ID=%s' % (key, value_list, self.dresp_id) raise KeyError(msg) list_fields += build_table_lines(fields2, nstart=i, nend=j) return list_fields
[docs] def safe_cross_reference(self, model: BDF, xref_errors): self.cross_reference(model)
[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 DRESP3 ID=%s' % (self.dresp_id) default_values = {} params = {} for key, vals in sorted(self.params.items()): unused_iorder, name = key if name in ['DRESP1', 'DRESP2']: params[key] = [] for val in vals: params[key].append(model.DResp(val, msg)) elif name in ['DVCREL1', 'DVCREL2']: params[key] = [] for val in vals: params[key].append(model.DVcrel(val, msg)) elif name in ['DVMREL1', 'DVMREL2']: params[key] = [] for val in vals: params[key].append(model.DVmrel(val, msg)) elif name in ['DVPREL1', 'DVPREL2']: params[key] = [] for val in vals: params[key].append(model.DVprel(val, msg)) elif name == 'DESVAR': params[key] = [] for val in vals: params[key].append(model.Desvar(val, msg)) elif name == 'DTABLE': self.dtable_ref = model.dtable for val in vals: default_values[val] = self.dtable_ref[val] elif name == 'DNODE': params[key] = [[], []] node_vals, component_vals = vals for nid in node_vals: params[key][0].append(model.Node(nid, msg)) params[key][1] = component_vals else: raise NotImplementedError(' TODO: xref key=%s' % str(key)) self.params_ref = params
#if isinstance(self.DEquation(), integer_types): #self.dequation = model.DEQATN(self.dequation, msg=msg) #self.dequation_ref = self.dequation #self.func = self.dequation_ref.func #elif isinstance(self.dequation, str): #self.func = fortran_to_python_short(self.dequation, default_values) #else: #raise NotImplementedError(self.dequation)
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" if hasattr(self, 'func'): del self.func self.dtable_ref = {} params = {} for key, value_list in sorted(self.params_ref.items()): unused_iorder, name = key #print(key) #j, name = key values_list2 = _get_dresp23_table_values(name, value_list) params[key] = values_list2 self.params = params self.params_ref = None
#self.dequation = self.DEquation() #if isinstance(self.dequation, integer_types): #del self.dequation_ref def _verify(self, model, xref): pass
[docs] def raw_fields(self): list_fields = [ 'DRESP3', self.dresp_id, self.label, self.group, self.Type, self.region, None, None, None] list_fields += self._pack_params() return list_fields
[docs] def repr_fields(self): list_fields = [ 'DRESP3', self.dresp_id, self.label, self.group, self.Type, self.region, None, None, None] list_fields += self._pack_params() 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 DCONADD(OptConstraint): """ +---------+------+------+-----+-----+-----+-----+-----+-----+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +=========+======+======+=====+=====+=====+=====+=====+=====+ | DCONADD | DCID | DC1 | DC2 | DC3 | DC4 | DC5 | DC6 | DC7 | +---------+------+------+-----+-----+-----+-----+-----+-----+ | | DC8 | etc. | | | | | | | +---------+------+------+-----+-----+-----+-----+-----+-----+ | DCONADD | 10 | 4 | 12 | | | | | | +---------+------+------+-----+-----+-----+-----+-----+-----+ """ type = 'DCONADD'
[docs] @classmethod def _init_from_empty(cls): oid = 1 dconstrs = [1] return DCONADD(oid, dconstrs, comment='')
def __init__(self, oid, dconstrs, comment=''): OptConstraint.__init__(self) if comment: self.comment = comment self.oid = oid self.dconstrs = dconstrs self.dconstrs_ref = None
[docs] @classmethod def export_to_hdf5(cls, hdf5_file, dconadds, encoding): for i, dconadd in enumerate(dconadds): dconadd_group = hdf5_file.create_group(str(i)) dconadd_group.create_dataset('oid', data=dconadd.oid) dconadd_group.create_dataset('dconstrs', data=dconadd.dconstrs)
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a DCONADD card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ oid = integer(card, 1, 'dcid') dconstrs = [] for i in range(2, len(card)): dconstr = integer(card, i, 'dconstr_%i' % i) dconstrs.append(dconstr) return DCONADD(oid, dconstrs, comment=comment)
@classmethod def add_op2_data(cls, data, comment=''): """ Adds a DCONADD card from the OP2 Parameters ---------- data : list[varies] a list of fields defined in OP2 format comment : str; default='' a comment for the card """ conid = data[0] sets = data[1:].tolist() return DCONADD(conid, sets, 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 = f'which is required by DCONADD={self.oid} and must reference a DCONSTR' try: self.dconstrs_ref = [model.dconstrs[oid] for oid in self.dconstr_ids] except Exception: dconstrs_actual = set(list(model.dconstrs.keys())) dconstrs_missing_set = set(self.dconstr_ids) - dconstrs_actual if len(dconstrs_missing_set): raise KeyError(f'The following DCONSTRs are missing which are required by:\n{self}' f'DCONSTRs={dconstrs_missing_set}') raise
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.dconstrs = self.dconstr_ids self.dconstrs_ref = None
@property def dconstr_ids(self): ids = [] for dconstr in self.dconstrs: if isinstance(dconstr, list): for dconstri in dconstr: if isinstance(dconstri, integer_types): ids.append(dconstri) elif isinstance(dconstri, DCONSTR): ids.append(dconstri.oid) break else: print("type=%s; dconstri=%s\n" % (type(dconstri), dconstri)) raise NotImplementedError(dconstri) elif isinstance(dconstr, integer_types): ids.append(dconstr) #elif isinstance(dconstr, DCONSTR): #ids.append(dconstr.oid) else: print("type=%s; dconstr=%s\n" % (type(dconstr), dconstr)) raise NotImplementedError(dconstr) return ids #return [dconstr if isinstance(dconstr, integer_types) else dconstr.oid #for dconstr in self.dconstrs]
[docs] def raw_fields(self): list_fields = ['DCONADD', self.oid] + self.dconstr_ids 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 DSCREEN(OptConstraint): """ +---------+-------+-------+------+ | 1 | 2 | 3 | 4 | +=========+=======+=======+======+ | DSCREEN | RTYPE | TRS | NSTR | +---------+-------+-------+------+ | DSCREEN | DISP | -0.3 | NSTR | +---------+-------+-------+------+ """ type = 'DSCREEN'
[docs] @classmethod def _init_from_empty(cls): rtype = 'DISP' return DSCREEN(rtype, trs=-0.5, nstr=20, comment='')
def __init__(self, rtype: str, trs: float=-0.5, nstr: int=20, comment: str=''): """ Creates a DSCREEN object Parameters ---------- rtype : str Response type for which the screening criteria apply trs : float; default=-0.5 Truncation threshold nstr : int; default=20 Maximum number of constraints to be retained per region per load case comment : str; default='' a comment for the card """ OptConstraint.__init__(self) if comment: self.comment = comment #: Response type for which the screening criteria apply. (Character) self.rtype = rtype #: Truncation threshold. (Real; Default = -0.5) self.trs = trs #: Maximum number of constraints to be retained per region per load #: case. (Integer > 0; Default = 20) self.nstr = nstr #assert rtype in ['DISP', 'STRESS', 'STRAIN', 'EQUA', 'FORCE', 'CSTRESS', 'CFAILURE', #'TDISP', 'TVELO', 'TACCL', 'TSTRE', 'TFORC', #'FRDISP', 'FRVELO', 'FRACCL', 'FRSTRE', 'FRSPCF', #'CEIG', 'LAMA', 'EIGN', 'VOLUME', 'DRESP3', 'WEIGHT'], str(self)
[docs] @classmethod def add_card(cls, card: BDFCard, comment: str=''): """ Adds a DSCREEN card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ rtype = string(card, 1, 'rtype') trs = double_or_blank(card, 2, 'trs', default=-0.5) nstr = integer_or_blank(card, 3, 'nstr', default=20) assert len(card) <= 4, f'len(DSCREEN card) = {len(card):d}\ncard={card}' return DSCREEN(rtype, trs=trs, nstr=nstr, comment=comment)
[docs] def raw_fields(self): list_fields = ['DSCREEN', self.rtype, self.trs, self.nstr] return list_fields
[docs] def repr_fields(self): trs = set_blank_if_default(self.trs, -0.5) nstr = set_blank_if_default(self.nstr, 20) list_fields = ['DSCREEN', self.rtype, trs, nstr] 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 DVCREL1(DVXREL1): # similar to DVMREL1 type = 'DVCREL1' _properties = ['desvar_ids']
[docs] @classmethod def _init_from_empty(cls): oid = 1 element_type = 'CONM2' eid = 2 cp_name = 'X1' dvids = 42 coeffs = 1.0 return DVCREL1(oid, element_type, eid, cp_name, dvids, coeffs, cp_min=None, cp_max=1e20, c0=0., validate=False, comment='')
def __init__(self, oid, element_type, eid, cp_name, dvids, coeffs, cp_min=None, cp_max=1e20, c0=0., validate=False, comment=''): """ +---------+--------+--------+--------+-----------+-------+--------+-----+---+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +=========+========+========+========+===========+=======+========+=====+===+ | DVCREL1 | ID | TYPE | EID | CPNAME | CPMIN | CPMAX | C0 | | +---------+--------+--------+--------+-----------+-------+--------+-----+---+ | | DVID1 | COEF1 | DVID2 | COEF2 | DVID3 | etc. | | | +---------+--------+--------+--------+-----------+-------+--------+-----+---+ +---------+--------+--------+--------+-------+-----+------+ | DVCREL1 | 200000 | CQUAD4 | 1 | ZOFFS | | 1.0 | +---------+--------+--------+--------+-------+-----+------+ | | 200000 | 1.0 | | | | | +---------+--------+--------+--------+-------+-----+------+ """ DVXREL1.__init__(self, oid, dvids, coeffs, c0, comment) # element type (e.g. CQUAD4) self.element_type = element_type # element id self.eid = eid # the connectivity property (X1, X2, X3, ZOFFS, etc.) self.cp_name = cp_name # min value self.cp_min = cp_min # max value self.cp_max = cp_max validate_dvcrel(validate, element_type, cp_name) self.eid_ref = None if len(self.coeffs) == 0: msg = 'len(coeffs)=%s len(dvids)=%s\n' % (len(self.coeffs), len(self.dvids)) msg += "We've added a coeff=1.0 and desvar_id=1 in order to look at the crashing card\n" self.coeffs = [1.] self.dvids = [1] msg += str(self) raise RuntimeError(msg) assert len(self.coeffs) == len(self.dvids), 'len(coeffs)=%s len(dvids)=%s' % (len(self.coeffs), len(self.dvids))
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a DVCREL1 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ oid = integer(card, 1, 'oid') element_type = string(card, 2, 'Type') eid = integer(card, 3, 'eid') cp_name = integer_or_string(card, 4, 'cp_name') cp_min = double_or_blank(card, 5, 'cp_min', default=None) cp_max = double_or_blank(card, 6, 'cp_max', default=1e20) c0 = double_or_blank(card, 7, 'c0', default=0.0) desvar_ids = [] coeffs = [] end_fields = [interpret_value(field) for field in card[9:]] nfields = len(end_fields) # - 1 #if nfields % 2 == 1: #end_fields.append(None) #nfields += 1 i = 0 for i in range(0, nfields, 2): desvar_id = end_fields[i] coeff = end_fields[i + 1] assert isinstance(desvar_id, integer_types), card assert isinstance(coeff, float_types), card desvar_ids.append(desvar_id) coeffs.append(coeff) if len(desvar_ids) != len(coeffs): # nfields % 2 == 1: print(card) print("desvar_ids = %s" % (desvar_ids)) print("coeffs = %s" % (coeffs)) raise RuntimeError('invalid DVCREL1...') return DVCREL1(oid, element_type, eid, cp_name, desvar_ids, coeffs, c0=c0, cp_min=cp_min, cp_max=cp_max, comment=comment)
def _verify(self, xref): """ Verifies all methods for this object work Parameters ---------- xref : bool has this model been cross referenced """ pass
[docs] def OptID(self): return self.oid
[docs] def object_attributes(self, mode='public', keys_to_skip=None, filter_properties=False): """.. seealso:: `pyNastran.utils.object_attributes(...)`""" if keys_to_skip is None: keys_to_skip = [] my_keys_to_skip = ['Type'] return super(DVCREL1, self).object_attributes( mode=mode, keys_to_skip=keys_to_skip+my_keys_to_skip, filter_properties=filter_properties)
@property def Type(self): return self.element_type @Type.setter def Type(self, element_type): self.element_type = element_type
[docs] def update_model(self, model, desvar_values): """doesn't require cross-referencing""" value = get_dvxrel1_coeffs(self, model, desvar_values) assert isinstance(self.eid, int), type(self.eid) element = self._get_element(model, msg='') try: self._update_by_dvcrel(element, value) except AttributeError: raise
#raise NotImplementedError('mat_type=%r is not supported in ' #'update_model' % self.mat_type)
[docs] def _update_by_dvcrel(self, element, value): if hasattr(element, 'update_by_cp_name'): element.update_by_cp_name(self.cp_name, value) else: try: cp_name_map = element.cp_name_map except AttributeError: raise NotImplementedError('element_type=%r cp_name=%r has not implemented ' 'cp_name_map/update_by_cp_name' % ( self.element_type, self.cp_name)) try: key = cp_name_map[self.cp_name] except KeyError: raise NotImplementedError('connectivity_type=%r has not implemented %r ' 'for in cp_name_map/update_by_cp_name' % ( self.element_type, self.cp_name)) setattr(element, key, value)
[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 DVCREL1 oid=%r' % self.oid self.eid_ref = self._get_element(model, msg=msg) self.dvids_ref = [model.Desvar(dvid, msg) for dvid in self.dvids]
[docs] def _get_element(self, model, msg=''): if self.element_type in ['CQUAD4', 'CTRIA3', 'CBAR', 'CBEAM', 'CELAS1', 'CELAS2', 'CELAS4', 'CDAMP2', 'CGAP', 'CBUSH']: elem = model.Element(self.eid, msg=msg) elif self.element_type in ['CONM1', 'CONM2', 'CMASS2', 'CMASS4']: elem = model.Mass(self.eid, msg=msg) #elif element_type in ['CBUSH']: else: raise NotImplementedError(self.element_type) return elem
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.eid = self.Eid() self.dvids = self.desvar_ids self.eid_ref = None self.dvids_ref = None
[docs] def calculate(self, op2_model, subcase_id): raise NotImplementedError('\n' + str(self))
[docs] def Eid(self): if self.eid_ref is not None: return self.eid_ref.eid return self.eid
[docs] def raw_fields(self): list_fields = ['DVCREL1', self.oid, self.element_type, self.Eid(), self.cp_name, self.cp_min, self.cp_max, self.c0, None] for (dvid, coeff) in zip(self.desvar_ids, self.coeffs): list_fields.append(dvid) list_fields.append(coeff) return list_fields
[docs] def repr_fields(self): cp_max = set_blank_if_default(self.cp_max, 1e20) c0 = set_blank_if_default(self.c0, 0.) list_fields = ['DVCREL1', self.oid, self.element_type, self.Eid(), self.cp_name, self.cp_min, cp_max, c0, None] for (dvid, coeff) in zip(self.desvar_ids, self.coeffs): list_fields.append(dvid) list_fields.append(coeff) 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)
[docs] class DVCREL2(DVXREL2): """ +----------+--------+--------+-------+------------+-------+-------+-------+-------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +==========+========+========+=======+============+=======+=======+=======+=======+ | DVCREL2 | ID | TYPE | EID | CPNAME/FID | CPMIN | CPMAX | EQID | | +----------+--------+--------+-------+------------+-------+-------+-------+-------+ | | DESVAR | DVID1 | DVID2 | DVID3 | DVID4 | DVID5 | DVID6 | DVID7 | +----------+--------+--------+-------+------------+-------+-------+-------+-------+ | | | DVID8 | etc. | | | | | | +----------+--------+--------+-------+------------+-------+-------+-------+-------+ | | DTABLE | LABL1 | LABL2 | LABL3 | LABL4 | LABL5 | LABL6 | LABL7 | +----------+--------+--------+-------+------------+-------+-------+-------+-------+ | | | LABL8 | etc. | | | | | | +----------+--------+--------+-------+------------+-------+-------+-------+-------+ """ type = 'DVCREL2' allowed_elements = [ 'CQUAD4', 'CTRIA3', 'CBAR', 'CBEAM', 'CELAS1', 'CBUSH', 'CDAMP2', ] _properties = ['desvar_ids'] #allowed_masses = ['CONM2', 'CMASS2', 'CMASS4'] #allowed_properties_mass = ['PMASS']
[docs] @classmethod def _init_from_empty(cls): oid = 1 element_type = 'CONM2' eid = 2 cp_name = 'X1' deqation = 42 dvids = [] labels = [] return DVCREL2(oid, element_type, eid, cp_name, deqation, dvids, labels, cp_min=None, cp_max=1e20, validate=False, comment='')
def __init__(self, oid, element_type, eid, cp_name, deqation, dvids, labels, cp_min=None, cp_max=1e20, validate=False, comment=''): DVXREL2.__init__(self, oid, dvids, labels, deqation, comment) #: Name of an element connectivity entry, such as CBAR, CQUAD4, etc. #: (Character) self.element_type = element_type #: Element Identification number. (Integer > 0) self.eid = eid #: Name of connectivity property, such as X1, X2, X3, ZOFFS, etc. #: (Character) self.cp_name = cp_name #: Minimum value allowed for this property. If CPNAME references a connectivity #: property that can only be positive, then the default value of CPMIN is 1.0E-15. #: Otherwise, it is -1.0E35. (Real) #: .. todo:: bad default (see DVCREL2) self.cp_min = cp_min #: Maximum value allowed for this property. (Real; Default = 1.0E20) self.cp_max = cp_max #assert len(coeffs) > 0, 'len(coeffs)=%s' % len(coeffs) #assert len(coeffs) == len(dvids), 'len(coeffs)=%s len(dvids)=%s' % (len(coeffs), len(dvids)) validate_dvcrel(validate, element_type, cp_name) self.eid_ref = None
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a DVCREL2 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ oid = integer(card, 1, 'oid') element_type = string(card, 2, 'Type') pid = integer(card, 3, 'pid') cp_name = integer_or_string(card, 4, 'cpName_FID') cp_min = double_or_blank(card, 5, 'cp_min') cp_max = double_or_blank(card, 6, 'cp_max', 1e20) dequation = integer_or_blank(card, 7, 'dequation') #: .. todo:: or blank? fields = [interpret_value(field) for field in card[9:]] ioffset = 9 iend = len(fields) + ioffset try: idesvar = fields.index('DESVAR') + ioffset except ValueError: idesvar = None try: idtable = fields.index('DTABLE') + ioffset #iDesMax = idtable # the index to start parsing DESVAR ides_stop = idtable # the index to stop parsing DESVAR except ValueError: idtable = None ides_stop = iend dvids = [] if idesvar: n = 1 for i in range(10, ides_stop): dvid_name = 'DVID' + str(n) dvid = integer_or_blank(card, i, dvid_name) #print("%s = %s" % (dvid_name, dvid)) if dvid: assert dvid is not None assert dvid != 'DESVAR' dvids.append(dvid) n += 1 labels = [] if idtable: n = 1 for i in range(idtable + 1, iend): label_name = 'Label' + str(n) label = string(card, i, label_name) #print("%s = %s" % (label_name, label)) if label: assert label != 'DTABLE' labels.append(label) return DVCREL2(oid, element_type, pid, cp_name, dequation, dvids, labels, cp_min, cp_max, comment=comment)
[docs] def object_attributes(self, mode='public', keys_to_skip=None, filter_properties=False): """.. seealso:: `pyNastran.utils.object_attributes(...)`""" if keys_to_skip is None: keys_to_skip = [] my_keys_to_skip = ['Type'] return super(DVCREL2, self).object_attributes( mode=mode, keys_to_skip=keys_to_skip+my_keys_to_skip, filter_properties=filter_properties)
@property def Type(self): return self.element_type @Type.setter def Type(self, element_type): self.element_type = element_type
[docs] def OptID(self): return self.oid
[docs] def Eid(self): if self.eid_ref is None: return self.eid elif self.element_type in self.allowed_elements: eid = self.eid_ref.eid #elif self.element_type in self.allowed_masses: #pid = self.pid_ref.eid #elif self.element_type in self.allowed_properties_mass: #pid = self.pid_ref.pid else: raise NotImplementedError('element_type=%r is not supported' % self.element_type) return eid
[docs] def DEquation(self): if self.dequation_ref is None: return self.dequation return self.dequation_ref.equation_id
[docs] def calculate(self, op2_model, subcase_id): """ this should really make a call the the DEQATN; see the PBEAM for an example of get/set_opt_value """ try: get = self.eid_ref.get_optimization_value(self.cp_name) out = self.eid_ref.set_optimization_value(self.cp_name, get) except Exception: print('DVCREL2 calculate : %s[%r] = ???' % (self.element_type, self.cp_name)) raise argsi = [] if self.dvids_ref: for desvar in self.dvids_ref: # DESVARS arg = desvar.calculate(op2_model, subcase_id) argsi.append(arg) if self.labels: for label in self.labels: # DTABLE arg = self.dtable_ref[label] argsi.append(arg) #op2_model.log.info('DVPREL2; args = %s' % argsi) #op2_model.log.info('dvids =', self.dvids) #op2_model.log.info('labels =', self.labels) #op2_model.log.info('%s[%r] = %s' % (self.element_type, self.cp_name, out)) out = self.func(*argsi) op2_model.log.info(' deqatn out = %s' % out) return out
[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 .. todo:: add support for DEQATN cards to finish DVPREL2 xref """ msg = ', which is required by DVCREL2 oid=%r' % self.oid #if self.element_type in self.allowed_elements: #self.pid = model.Element(self.pid, msg=msg) #elif self.element_type in self.allowed_masses: #self.pid = model.masses[self.pid] #elif self.element_type in self.allowed_properties_mass: #self.pid = model.properties_mass[self.pid] #else: #raise NotImplementedError('element_type=%r is not supported' % self.element_type) self.eid_ref = model.Element(self.eid, msg=msg) #self.dvids = [model.Desvar(dvid, msg) for dvid in self.dvids] self.dvids_ref = [model.Desvar(dvid, msg) for dvid in self.dvids] self.dequation_ref = model.DEQATN(self.dequation, msg=msg) assert self.eid_ref.type in self.allowed_elements, self.eid.type self._check_args() self.dtable_ref = {}
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.eid = self.Eid() self.dvids = self.desvar_ids self.dequation = self.DEquation() self.eid_ref = None self.dequation_ref = None self.dtable_ref = {}
[docs] def _get_element(self, model, eid, msg=''): assert isinstance(self.eid, int), type(self.eid) #if self.element_type in ['MAT1']: eid_ref = model.Element(eid, msg=msg) #else: #raise NotImplementedError(self.element_type) return eid_ref
[docs] def update_model(self, model, desvar_values): """doesn't require cross-referencing""" values = get_deqatn_value(self, model, desvar_values) elem = self._get_element(model, self.eid) try: self._update_by_dvcrel(elem, values) except AttributeError: raise
#raise NotImplementedError('prop_type=%r is not supported in update_model' % self.prop_type)
[docs] def _update_by_dvcrel(self, elem, value): if hasattr(elem, 'update_by_cp_name'): elem.update_by_cp_name(self.cp_name, value) else: try: cp_name_map = elem.cp_name_map except AttributeError: msg = ('element_type=%r name=%r has not implemented ' 'cp_name_map/update_by_cp_name' % ( self.element_type, self.cp_name)) raise NotImplementedError(msg) try: key = cp_name_map[self.cp_name] except KeyError: msg = ('element_type=%r has not implemented %r ' 'for in cp_name_map/update_by_cp_name' % ( self.element_type, self.cp_name)) raise NotImplementedError(msg) setattr(elem, key, value)
[docs] def raw_fields(self): list_fields = ['DVCREL2', self.oid, self.element_type, self.Eid(), self.cp_name, self.cp_min, self.cp_max, self.DEquation(), None] if self.dvids: fields2 = ['DESVAR'] + self.dvids list_fields += build_table_lines(fields2, nstart=1, nend=0) if self.labels: fields2 = ['DTABLE'] + self.labels list_fields += build_table_lines(fields2, nstart=1, nend=0) return list_fields
[docs] def repr_fields(self): """ .. todo:: finish repr_fields for DVCREL2 """ 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) return self.comment + print_card_16(card)
[docs] class DVMREL1(DVXREL1): """ Design Variable to Material Relation Defines the relation between a material property and design variables. +---------+-------+-------+-------+--------+-------+-------+--------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | +=========+=======+=======+=======+========+=======+=======+========+ | DVMREL1 | ID | TYPE | MID | MPNAME | MPMIN | MPMAX | C0 | +---------+-------+-------+-------+--------+-------+-------+--------+ | | DVID1 | COEF1 | DVID2 | COEF2 | DVID3 | COEF3 | etc. | +---------+-------+-------+-------+--------+-------+-------+--------+ """ type = 'DVMREL1' _properties = ['desvar_ids']
[docs] @classmethod def _init_from_empty(cls): oid = 1 mat_type = 'MAT1' mid = 2 mp_name = 'E' dvids = 42 coeffs = 1.0 return DVMREL1(oid, mat_type, mid, mp_name, dvids, coeffs, mp_min=None, mp_max=1e20, c0=0., validate=False, comment='')
def __init__(self, oid: int, mat_type: str, mid: int, mp_name: str, dvids: list[int], coeffs: list[float], mp_min: Optional[float]=None, mp_max: float=1e20, c0: float=0., validate: bool=False, comment: str=''): """ Creates a DVMREL1 card Parameters ---------- oid : int optimization id mat_type : str material card name (e.g., MAT1) mid : int material id mp_name : str optimization parameter as a pname (material name; E) dvids : list[int] DESVAR ids coeffs : list[float] scale factors for DESVAR ids mp_min : float; default=None minimum material property value mp_max : float; default=1e20 maximum material property value c0 : float; default=0. offset factor for the variable validate : bool; default=False should the variable be validated comment : str; default='' a comment for the card """ DVXREL1.__init__(self, oid, dvids, coeffs, c0, comment) self.mat_type = mat_type self.mid = mid self.mp_name = mp_name self.mp_max = mp_max self.mp_min = mp_min validate_dvmrel(validate, mat_type, mp_name) self.mid_ref = None if len(self.coeffs) == 0: msg = 'len(coeffs)=%s len(dvids)=%s\n' % (len(self.coeffs), len(self.dvids)) msg += "We've added a coeff=1.0 and desvar_id=1 in order to look at the crashing card\n" self.coeffs = [1.] self.dvids = [1] msg += str(self) raise RuntimeError(msg) assert len(self.coeffs) == len(self.dvids), 'len(coeffs)=%s len(dvids)=%s' % (len(self.coeffs), len(self.dvids))
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a DVMREL1 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ oid = integer(card, 1, 'oid') mat_type = string(card, 2, 'mat_type') mid = integer(card, 3, 'mid') mp_name = string(card, 4, 'mpName') #if self.mp_name in ['E', 'RHO', 'NU']: positive values #self.mp_min = double_or_blank(card, 5, 'mpMin', 1e-15) #else: # negative #self.mp_min = double_or_blank(card, 5, 'mpMin', -1e-35) mp_min = double_or_blank(card, 5, 'mp_min') #: .. todo:: bad default mp_max = double_or_blank(card, 6, 'mp_max', default=1e20) c0 = double_or_blank(card, 7, 'c0', default=0.0) desvar_ids = [] coeffs = [] end_fields = [interpret_value(field) for field in card[9:]] nfields = len(end_fields) # - 1 #if nfields % 2 == 1: #end_fields.append(None) #nfields += 1 i = 0 for i in range(0, nfields, 2): desvar_id = end_fields[i] coeff = end_fields[i + 1] assert isinstance(desvar_id, integer_types), card assert isinstance(coeff, float_types), card desvar_ids.append(desvar_id) coeffs.append(coeff) if len(desvar_ids) != len(coeffs): # nfields % 2 == 1: print(card) print("desvar_ids = %s" % (desvar_ids)) print("coeffs = %s" % (coeffs)) raise RuntimeError('invalid DVMREL1...') return DVMREL1(oid, mat_type, mid, mp_name, desvar_ids, coeffs, mp_min=mp_min, mp_max=mp_max, c0=c0, comment=comment)
[docs] def object_attributes(self, mode='public', keys_to_skip=None, filter_properties=False): """.. seealso:: `pyNastran.utils.object_attributes(...)`""" if keys_to_skip is None: keys_to_skip = [] my_keys_to_skip = ['Type'] return super(DVMREL1, self).object_attributes( mode=mode, keys_to_skip=keys_to_skip+my_keys_to_skip, filter_properties=filter_properties)
[docs] def update_model(self, model, desvar_values): """doesn't require cross-referencing""" value = get_dvxrel1_coeffs(self, model, desvar_values) assert isinstance(self.mid, int), type(self.mid) mat = model.materials[self.mid] try: self._update_by_dvmrel(mat, value) except AttributeError: raise
#raise NotImplementedError('mat_type=%r is not supported in update_model' % self.mat_type)
[docs] def _update_by_dvmrel(self, mat, value): try: mp_name_map = mat.mp_name_map except AttributeError: raise NotImplementedError('mat_type=%r, mp_name=%r has not implemented mp_name_map' % ( self.mat_type, self.mp_name)) try: key = mp_name_map[self.mp_name] except KeyError: raise NotImplementedError('mat_type=%r has not implemented %r for in mp_name_map' % ( self.mat_type, self.mp_name)) setattr(mat, key, value)
[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 DVMREL1 oid=%r' % (self.oid) self.mid_ref = model.Material(self.mid, msg=msg) self.dvids_ref = [model.Desvar(dvid, msg) for dvid in self.dvids]
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.mid = self.Mid() self.dvids = self.desvar_ids self.mid_ref = None self.dvids_ref = None
def _verify(self, xref): """ Verifies all methods for this object work Parameters ---------- xref : bool has this model been cross referenced """ pass
[docs] def OptID(self): return self.oid
[docs] def Mid(self): if self.mid_ref is not None: return self.mid_ref.mid return self.mid
[docs] def raw_fields(self): list_fields = ['DVMREL1', self.oid, self.mat_type, self.Mid(), self.mp_name, self.mp_min, self.mp_max, self.c0, None] for (dvid, coeff) in zip(self.dvids, self.coeffs): list_fields.append(dvid) list_fields.append(coeff) return list_fields
[docs] def repr_fields(self): mp_max = set_blank_if_default(self.mp_max, 1e20) c0 = set_blank_if_default(self.c0, 0.) list_fields = ['DVMREL1', self.oid, self.mat_type, self.Mid(), self.mp_name, self.mp_min, mp_max, c0, None] for (dvid, coeff) in zip(self.dvids, self.coeffs): list_fields.append(dvid) list_fields.append(coeff) 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 DVMREL2(DVXREL2): """ +---------+--------+--------+-------+---------+-------+-------+-------+-------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +=========+========+========+=======+=========+=======+=======+=======+=======+ | DVMREL2 | ID | TYPE | MID | MPNAME | MPMIN | MPMAX | EQID | | +---------+--------+--------+-------+---------+-------+-------+-------+-------+ | | DESVAR | DVID1 | DVID2 | DVID3 | DVID4 | DVID5 | DVID6 | DVID7 | +---------+--------+--------+-------+---------+-------+-------+-------+-------+ | | DVID8 | etc. | | | | | | | +---------+--------+--------+-------+---------+-------+-------+-------+-------+ | | DTABLE | LABL1 | LABL2 | LABL3 | LABL4 | LABL5 | LABL6 | LABL7 | +---------+--------+--------+-------+---------+-------+-------+-------+-------+ | | LABL8 | etc. | | | | | | | +---------+--------+--------+-------+---------+-------+-------+-------+-------+ """ type = 'DVMREL2' allowed_materials = ['MAT1', 'MAT2', 'MAT8'] _properties = ['desvar_ids']
[docs] @classmethod def _init_from_empty(cls): oid = 1 mat_type = 'MAT1' mid = 2 mp_name = 'E' dvids = [] labels = [] deqation = 42 return DVMREL2(oid, mat_type, mid, mp_name, deqation, dvids, labels, mp_min=None, mp_max=1e20, validate=False, comment='')
def __init__(self, oid, mat_type, mid, mp_name, deqation, dvids, labels, mp_min=None, mp_max=1e20, validate=False, comment=''): """ Creates a DVMREL2 card Parameters ---------- oid : int optimization id mat_type : str material card name (e.g., MAT1) mid : int material id mp_name : str optimization parameter as a pname (material name; E) deqation : int DEQATN id dvids : list[int]; default=None DESVAR ids labels : list[str]; default=None DTABLE names mp_min : float; default=None minimum material property value mp_max : float; default=1e20 maximum material property value validate : bool; default=False should the variable be validated comment : str; default='' a comment for the card .. note:: either dvids or labels is required """ DVXREL2.__init__(self, oid, dvids, labels, deqation, comment) #: Name of a material entry, such as MAT1, MAT2, etc self.mat_type = mat_type #: Property entry identification number self.mid = mid #: Property name, such as 'E', 'RHO' #: (Character) self.mp_name = mp_name #: Minimum value allowed for this property. If MPNAME references a material #: property that can only be positive, then the default value for MPMIN is 1.0E-15. #: Otherwise, it is -1.0E35. (Real) self.mp_min = mp_min #: Maximum value allowed for this property. (Real; Default = 1.0E20) self.mp_max = mp_max validate_dvmrel(validate, mat_type, mp_name) self.mid_ref = None self.dequation_ref = None
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a DVMREL2 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ oid = integer(card, 1, 'oid') mat_type = string(card, 2, 'mat_type') mid = integer(card, 3, 'mid') mp_name = integer_or_string(card, 4, 'mp_name') mp_min = double_or_blank(card, 5, 'mp_min') mp_max = double_or_blank(card, 6, 'mp_max', default=1e20) dequation = integer_or_blank(card, 7, 'dequation') #: .. todo:: or blank? fields = [interpret_value(field) for field in card[9:]] ioffset = 9 iend = len(fields) + ioffset try: idesvar = fields.index('DESVAR') + ioffset except ValueError: idesvar = None try: idtable = fields.index('DTABLE') + ioffset #iDesMax = idtable # the index to start parsing DESVAR ides_stop = idtable # the index to stop parsing DESVAR except ValueError: idtable = None ides_stop = iend dvids = [] if idesvar: n = 1 for i in range(10, ides_stop): dvid_name = 'DVID' + str(n) dvid = integer_or_blank(card, i, dvid_name) #print("%s = %s" % (dvid_name, dvid)) if dvid: assert dvid is not None assert dvid != 'DESVAR' dvids.append(dvid) n += 1 labels = [] if idtable: n = 1 for i in range(idtable + 1, iend): label_name = 'Label' + str(n) label = string(card, i, label_name) #print("%s = %s" % (label_name, label)) if label: assert label != 'DTABLE' labels.append(label) return DVMREL2(oid, mat_type, mid, mp_name, dequation, dvids, labels, mp_min=mp_min, mp_max=mp_max, comment=comment)
[docs] def _get_material(self, model, mid, msg=''): assert isinstance(self.mid, int), type(self.mid) if self.mat_type in self.allowed_materials: mid_ref = model.Material(mid, msg=msg) else: raise NotImplementedError(self.mat_type) return mid_ref
[docs] def update_model(self, model, desvar_values): """doesn't require cross-referencing""" values = get_deqatn_value(self, model, desvar_values) mat = self._get_material(model, self.mid) try: self._update_by_dvmrel(mat, values) except AttributeError: raise
#raise NotImplementedError('prop_type=%r is not supported in update_model' % self.prop_type)
[docs] def _update_by_dvmrel(self, mat, value): if hasattr(mat, 'update_by_mp_name'): mat.update_by_mname(self.mp_name, value) else: try: mp_name_map = mat.mp_name_map except AttributeError: msg = ('mat_type=%r name=%r has not implemented ' 'mp_name_map/update_by_mp_name' % ( self.mat_type, self.mp_name)) raise NotImplementedError(msg) try: key = mp_name_map[self.mp_name] except KeyError: msg = ('mat_type=%r has not implemented %r ' 'for in mp_name_map/update_by_mp_name' % ( self.mat_type, self.mp_name)) raise NotImplementedError(msg) setattr(mat, key, value)
[docs] def OptID(self): return self.oid
[docs] def Mid(self): if self.mid_ref is None: return self.mid #if self.mat_type in self.allowed_properties: #pid = self.pid_ref.pid #elif self.mat_type in self.allowed_elements: #pid = self.pid_ref.eid #elif self.mat_type in self.allowed_masses: #pid = self.pid_ref.eid #elif self.mat_type in self.allowed_properties_mass: #pid = self.pid_ref.pid elif self.mat_type in self.allowed_materials: mid = self.mid_ref.mid else: raise NotImplementedError('mat_type=%r is not supported' % self.mat_type) return mid
[docs] def object_attributes(self, mode='public', keys_to_skip=None, filter_properties=False): """.. seealso:: `pyNastran.utils.object_attributes(...)`""" if keys_to_skip is None: keys_to_skip = [] my_keys_to_skip = ['Type'] return super(DVMREL2, self).object_attributes( mode=mode, keys_to_skip=keys_to_skip+my_keys_to_skip, filter_properties=filter_properties, )
[docs] def DEquation(self): if self.dequation_ref is None: return self.dequation return self.dequation_ref.equation_id
[docs] def calculate(self, op2_model, subcase_id): """ this should really make a call the the DEQATN; see the PBEAM for an example of get/set_opt_value """ try: get = self.mid_ref.get_optimization_value(self.mp_name) out = self.mid_ref.set_optimization_value(self.mp_name, get) except Exception: print('DVMREL2 calculate : %s[%r] = ???' % (self.mat_type, self.mp_name)) raise argsi = [] if self.dvids_ref: for desvar in self.dvids_ref: # DESVARS arg = desvar.calculate(op2_model, subcase_id) argsi.append(arg) if self.labels: for label in self.labels: # DTABLE arg = self.dtable_ref[label] argsi.append(arg) #op2_model.log.info('DVMREL2; args = %s' % argsi) #op2_model.log.info('dvids =', self.dvids) #op2_model.log.info('labels =', self.labels) #op2_model.log.info('%s[%r] = %s' % (self.mat_type, self.cp_name, out)) out = self.func(*argsi) op2_model.log.info(' deqatn out = %s' % out) return out
#raise NotImplementedError('\n' + str(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 .. todo:: add support for DEQATN cards to finish DVMREL2 xref """ msg = ', which is required by DVMREL2 oid=%r' % self.oid if self.mat_type in self.allowed_materials: self.mid_ref = model.Material(self.mid, msg=msg) else: raise NotImplementedError('mat_type=%r is not supported' % self.mat_type) self.dvids_ref = [model.Desvar(dvid, msg) for dvid in self.dvids] self.dequation_ref = model.DEQATN(self.dequation, msg=msg) self._check_args()
#assert self.pid_ref.type not in ['PBEND', 'PBARL', 'PBEAML'], self.pid
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.mid = self.Mid() self.dvids = self.desvar_ids self.dequation = self.DEquation() self.mid_ref = None self.dequation_ref = None
#def OptValue(self): #: .. todo:: not implemented #self.pid_ref.OptValue(self.mp_name)
[docs] def raw_fields(self): list_fields = ['DVMREL2', self.oid, self.mat_type, self.Mid(), self.mp_name, self.mp_min, self.mp_max, self.DEquation(), None] if self.dvids: fields2 = ['DESVAR'] + self.dvids list_fields += build_table_lines(fields2, nstart=1, nend=0) if self.labels: fields2 = ['DTABLE'] + self.labels list_fields += build_table_lines(fields2, nstart=1, nend=0) return list_fields
[docs] def repr_fields(self): """ .. todo:: finish repr_fields for DVMREL2 """ 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) return self.comment + print_card_16(card)
[docs] class DVPREL1(DVXREL1): """ +---------+--------+--------+--------+-----------+-------+--------+-----+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | +=========+========+========+========+===========+=======+========+=====+ | DVPREL1 | ID | TYPE | PID | PNAME/FID | PMIN | PMAX | C0 | +---------+--------+--------+--------+-----------+-------+--------+-----+ | | DVID1 | COEF1 | DVID2 | COEF2 | DVID3 | etc. | | +---------+--------+--------+--------+-----------+-------+--------+-----+ | DVPREL1 | 200000 | PCOMP | 2000 | T2 | | | | +---------+--------+--------+--------+-----------+-------+--------+-----+ | | 200000 | 1.0 | | | | | | +---------+--------+--------+--------+-----------+-------+--------+-----+ """ type = 'DVPREL1' allowed_properties = [ 'PELAS', 'PROD', 'PTUBE', 'PBAR', 'PBARL', 'PBEAM', 'PBEAML', 'PSHEAR', 'PSHELL', 'PCOMP', 'PCOMPG', 'PBUSH', 'PBUSH1D', 'PGAP', 'PVISC', 'PDAMP', 'PWELD', 'PBMSECT', ] allowed_elements = [ 'CELAS2', 'CBAR', 'CBEAM', 'CQUAD4', 'CBUSH', 'CDAMP2', ] allowed_masses = ['CONM2', 'CMASS2', 'CMASS4'] allowed_properties_mass = ['PMASS'] _properties = ['desvar_ids', 'allowed_properties', 'allowed_elements', 'allowed_masses', 'allowed_properties_mass']
[docs] @classmethod def _init_from_empty(cls): oid = 1 prop_type = 'PSHELL' pid = 1 pname_fid = 'T' dvids = [1] coeffs = [1.] return DVPREL1(oid, prop_type, pid, pname_fid, dvids, coeffs, p_min=None, p_max=1e20, c0=0.0, validate=False)
def __init__(self, oid, prop_type, pid, pname_fid, dvids, coeffs, p_min=None, p_max=1e20, c0=0.0, validate=False, comment=''): """ Creates a DVPREL1 card Parameters ---------- oid : int optimization id prop_type : str property card name (e.g., PSHELL) pid : int property id pname_fid : str/int optimization parameter as a pname (property name; T) or field number (fid) dvids : list[int] DESVAR ids coeffs : list[float] scale factors for DESVAR ids p_min : float; default=None minimum property value p_max : float; default=1e20 maximum property value c0 : float; default=0. offset factor for the variable validate : bool; default=False should the variable be validated comment : str; default='' a comment for the card """ DVXREL1.__init__(self, oid, dvids, coeffs, c0, comment) # property type (e.g. PSHELL/PCOMP) self.prop_type = prop_type # property id self.pid = pid # the field type (e.g. 'T' on a PSHELL or the field id) self.pname_fid = pname_fid # min value for 'T' self.p_min = p_min # max value for 'T' self.p_max = p_max self.pid_ref = None if len(self.coeffs) == 0: msg = 'len(coeffs)=%s len(dvids)=%s\n' % (len(self.coeffs), len(self.dvids)) msg += "We've added a coeff=1.0 and desvar_id=1 in order to look at the crashing card\n" self.coeffs = [1.] self.dvids = [1] msg += str(self) raise RuntimeError(msg) assert len(self.coeffs) == len(self.dvids), 'len(coeffs)=%s len(dvids)=%s' % (len(self.coeffs), len(self.dvids)) pname_fid = validate_dvprel(prop_type, pname_fid, validate) self.pname_fid = pname_fid
[docs] def update_model(self, model, desvar_values): """doesn't require cross-referencing""" value = get_dvxrel1_coeffs(self, model, desvar_values, debug=False) assert isinstance(self.pid, int), type(self.pid) prop = self._get_property(model, self.pid) try: self._update_by_dvprel(prop, value) except (AttributeError, NotImplementedError): print(self) print(prop) raise
#raise NotImplementedError('prop_type=%r is not supported in ' #'update_model' % self.prop_type)
[docs] def _update_by_dvprel(self, prop, value): if self.prop_type == 'PCOMP' and prop.type == 'PCOMPG': pass elif self.prop_type != prop.type: raise RuntimeError('prop_type=%s is not the same as the property type (%s)\n%s%s' % ( self.prop_type, prop.type, str(self), str(prop))) if hasattr(prop, 'update_by_pname_fid'): prop.update_by_pname_fid(self.pname_fid, value) else: try: pname_fid_map = prop.pname_fid_map except AttributeError: raise NotImplementedError('prop_type=%r name=%r has not implemented ' 'pname_fid_map/update_by_pname_fid' % ( self.prop_type, self.pname_fid)) try: key = pname_fid_map[self.pname_fid] except KeyError: valid = list(pname_fid_map.keys()) if len(valid) == 0: msg = ('prop_type=%r has not implemented %r for in ' 'pname_fid_map/update_by_pname_fid\n' 'valid: []' % ( self.prop_type, self.pname_fid)) raise NotImplementedError(msg) svalid = [str(val) for val in valid] msg = ('prop_type=%r has not implemented %r for in ' 'pname_fid_map/update_by_pname_fid\n' 'valid: [%s]' % ( self.prop_type, self.pname_fid, ', '.join(svalid))) raise NotImplementedError(msg) setattr(prop, key, value)
[docs] def validate(self): DVXREL1.validate(self) self.pname_fid = validate_dvprel(self.prop_type, self.pname_fid, validate=True) unused_key, msg = get_dvprel_key(self) assert len(msg) == 0, msg
[docs] @classmethod def add_card(cls, card: BDFCard, comment: str=''): """ Adds a DVPREL1 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ oid = integer(card, 1, 'oid') prop_type = string(card, 2, 'prop_type') pid = integer(card, 3, 'pid') pname_fid = integer_or_string(card, 4, 'pName_FID') #: Minimum value allowed for this property. #: .. todo:: bad default (see DVMREL1) p_min = double_or_blank(card, 5, 'p_min', None) p_max = double_or_blank(card, 6, 'p_max', default=1e20) c0 = double_or_blank(card, 7, 'c0', default=0.0) desvar_ids = [] coeffs = [] end_fields = [interpret_value(field) for field in card[9:]] nfields = len(end_fields) # - 1 #if nfields % 2 == 1: #end_fields.append(None) #nfields += 1 i = 0 for i in range(0, nfields, 2): desvar_id = end_fields[i] coeff = end_fields[i + 1] assert isinstance(desvar_id, integer_types), card assert isinstance(coeff, float_types), card desvar_ids.append(desvar_id) coeffs.append(coeff) #dvids.append(end_fields[i]) #coeffs.append(end_fields[i + 1]) if len(desvar_ids) != len(coeffs): # nfields % 2 == 1: print(card) print("desvar_ids = %s" % (desvar_ids)) print("coeffs = %s" % (coeffs)) raise RuntimeError('invalid DVPREL1...') return DVPREL1(oid, prop_type, pid, pname_fid, desvar_ids, coeffs, p_min=p_min, p_max=p_max, c0=c0, comment=comment)
def _verify(self, xref): """ Verifies all methods for this object work Parameters ---------- xref : bool has this model been cross referenced """ pass
[docs] def OptID(self): return self.oid
[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 DVPREL1 oid=%r' % self.oid self.pid_ref = self._get_property(model, self.pid, msg=msg) self.dvids_ref = [model.Desvar(dvid, msg) for dvid in self.dvids]
[docs] def _get_property(self, model, pid, msg=''): assert isinstance(self.pid, int), type(self.pid) if self.prop_type in self.allowed_properties: pid_ref = model.Property(pid, msg=msg) #elif self.prop_type in self.allowed_elements: #pid_ref = model.Element(pid, msg=msg) #elif self.prop_type in self.allowed_masses: #pid_ref = model.masses[pid] elif self.prop_type in self.allowed_properties_mass: pid_ref = model.properties_mass[pid] elif self.prop_type == 'PBUSHT': pid_ref = model.pbusht[pid] elif self.prop_type == 'PELAST': pid_ref = model.pelast[pid] elif self.prop_type in ['PFAST', 'PBRSECT']: pid_ref = model.properties[pid] else: raise NotImplementedError('prop_type=%r is not supported' % self.prop_type) assert pid_ref.type not in ['PBEND'], pid_ref return pid_ref
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.pid = self.Pid() self.pid_ref = None self.dvids = self.desvar_ids self.dvids_ref = None
[docs] def calculate(self, op2_model, subcase_id): raise NotImplementedError('\n' + str(self))
[docs] def Pid(self): if self.pid_ref is None: pid = self.pid elif self.prop_type in self.allowed_properties: pid = self.pid_ref.pid #elif self.prop_type in self.allowed_elements: #pid = self.pid_ref.eid #elif self.prop_type in self.allowed_masses: #pid = self.pid_ref.eid elif self.prop_type in self.allowed_properties_mass: pid = self.pid_ref.pid elif self.prop_type in ['PBUSHT', 'PELAST', 'PFAST', 'PBRSECT']: pid = self.pid_ref.pid else: raise NotImplementedError('prop_type=%r is not supported' % self.prop_type) return pid
[docs] def get_xinit_lower_upper_bound(self, model): """gets the active x value and the lower/upper bounds""" lower_bound = self.p_min upper_bound = None if self.p_max == 1e20 else self.p_max xinit = self.c0 desvars = self.dvids ndesvars = len(desvars) for desvar, coeff in zip(desvars, self.coeffs): assert isinstance(coeff, float_types), f'invalid coefficient={coeff!r}\n{self}' if isinstance(desvar, integer_types): desvar_ref = model.desvars[desvar] else: desvar_ref = desvar.desvar_ref xiniti = desvar_ref.xinit # update the lower/upper bound if we have 1 desvar if desvar_ref.xlb != -1e20: xiniti = max(xiniti, desvar_ref.xlb) if ndesvars == 1: lower_bound = none_max(lower_bound, desvar_ref.xlb) if desvar_ref.xub != 1e20: xiniti = min(xiniti, desvar_ref.xub) if ndesvars == 1: upper_bound = none_min(upper_bound, desvar_ref.xub) # code validation if desvar_ref.delx is not None and desvar_ref.delx != 1e20: pass # TODO: haven't quite decided what to do if desvar_ref.ddval is not None: msg = 'DESVAR id=%s DDVAL is not None\n%s' % (desvar, str(desvar_ref)) #assert desvar_ref.ddval is None, desvar_ref xinit += coeff * xiniti if lower_bound: xinit = max(xinit, lower_bound) else: lower_bound = np.nan if upper_bound: xinit = min(xinit, upper_bound) else: upper_bound = np.nan return xinit, lower_bound, upper_bound
[docs] def raw_fields(self): list_fields = ['DVPREL1', self.oid, self.prop_type, self.Pid(), self.pname_fid, self.p_min, self.p_max, self.c0, None] for (dvid, coeff) in zip(self.desvar_ids, self.coeffs): list_fields.append(dvid) list_fields.append(coeff) return list_fields
[docs] def repr_fields(self): p_max = set_blank_if_default(self.p_max, 1e20) c0 = set_blank_if_default(self.c0, 0.) list_fields = ['DVPREL1', self.oid, self.prop_type, self.Pid(), self.pname_fid, self.p_min, p_max, c0, None] for (dvid, coeff) in zip(self.desvar_ids, self.coeffs): list_fields.append(dvid) list_fields.append(coeff) 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)
[docs] class DVPREL2(DVXREL2): """ +----------+--------+--------+-------+-----------+-------+-------+-------+-------+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +==========+========+========+=======+===========+=======+=======+=======+=======+ | DVPREL2 | ID | TYPE | PID | PNAME/FID | PMIN | PMAX | EQID | | +----------+--------+--------+-------+-----------+-------+-------+-------+-------+ | | DESVAR | DVID1 | DVID2 | DVID3 | DVID4 | DVID5 | DVID6 | DVID7 | +----------+--------+--------+-------+-----------+-------+-------+-------+-------+ | | | DVID8 | etc. | | | | | | +----------+--------+--------+-------+-----------+-------+-------+-------+-------+ | | DTABLE | LABL1 | LABL2 | LABL3 | LABL4 | LABL5 | LABL6 | LABL7 | +----------+--------+--------+-------+-----------+-------+-------+-------+-------+ | | | LABL8 | etc. | | | | | | +----------+--------+--------+-------+-----------+-------+-------+-------+-------+ """ type = 'DVPREL2' allowed_properties = [ 'PELAS', 'PROD', 'PTUBE', 'PBAR', 'PBARL', 'PBEAM', 'PBEAML', 'PSHELL', 'PCOMP', 'PCOMPG', 'PBUSH', 'PBUSH1D', 'PGAP', 'PVISC', 'PDAMP', 'PWELD', ] allowed_elements = [ 'CELAS2', 'CBAR', 'CBEAM', 'CQUAD4', 'CBUSH', 'CDAMP2', ] allowed_masses = ['CONM2', 'CMASS2', 'CMASS4'] allowed_properties_mass = ['PMASS'] _properties = ['desvar_ids']
[docs] @classmethod def _init_from_empty(cls): oid = 1 prop_type = 'PSHELL' pid = 2 pname_fid = 'T' deqation = 42 return DVPREL2(oid, prop_type, pid, pname_fid, deqation, dvids=None, labels=None, p_min=None, p_max=1e20, validate=False, comment='')
def __init__(self, oid, prop_type, pid, pname_fid, deqation, dvids=None, labels=None, p_min=None, p_max=1e20, validate=False, comment=''): """ Creates a DVPREL2 card Parameters ---------- oid : int optimization id prop_type : str property card name (e.g., PSHELL) pid : int property id pname_fid : str/int optimization parameter as a pname (property name; T) or field number (fid) deqation : int DEQATN id dvids : list[int]; default=None DESVAR ids labels : list[str]; default=None DTABLE names #params : dict[(index, card_type)] = values #the storage table for the response function #index : int #a counter #card_type : str #the type of card to pull from #DESVAR, DVPREL1, DRESP2, etc. #values : list[int] #the values for this response p_min : float; default=None minimum property value p_max : float; default=1e20 maximum property value validate : bool; default=False should the variable be validated comment : str; default='' a comment for the card .. note:: either dvids or labels is required """ DVXREL2.__init__(self, oid, dvids, labels, deqation, comment) #: Name of a property entry, such as PBAR, PBEAM, etc self.prop_type = prop_type #: Property entry identification number self.pid = pid #: Property name, such as 'T', 'A', or field position of the property #: entry, or word position in the element property table of the #: analysis model. Property names that begin with an integer such as #: 12I/T**3 may only be referred to by field position. #: (Character or Integer 0) self.pname_fid = pname_fid #: Minimum value allowed for this property. If FID references a stress #: recovery location field, then the default value for PMIN is -1.0+35. #: PMIN must be explicitly set to a negative number for properties that #: may be less than zero (for example, field ZO on the PCOMP entry). #: (Real; Default = 1.E-15) #: .. todo:: bad default (see DVMREL1) self.p_min = p_min #: Maximum value allowed for this property. (Real; Default = 1.0E20) self.p_max = p_max pname_fid = validate_dvprel(prop_type, pname_fid, validate) self.pname_fid = pname_fid self.pid_ref = None assert isinstance(self.labels, list), self.get_stats()
[docs] def validate(self): DVXREL2.validate(self) self.pname_fid = validate_dvprel(self.prop_type, self.pname_fid, validate=True)
[docs] @classmethod def add_card(cls, card, comment=''): """ Adds a DVPREL2 card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ oid = integer(card, 1, 'oid') prop_type = string(card, 2, 'prop_type') pid = integer(card, 3, 'pid') pname_fid = integer_or_string(card, 4, 'pName_FID') p_min = double_or_blank(card, 5, 'p_in', default=None) p_max = double_or_blank(card, 6, 'p_max', default=1e20) dequation = integer_or_blank(card, 7, 'dequation') #: .. todo:: or blank? fields = [interpret_value(field) for field in card[9:]] ioffset = 9 iend = len(fields) + ioffset #F:\work\pyNastran\examples\femap_examples\Support\nast\tpl\d200m20.dat #params = parse_table_fields('DRESP2', card, fields) #print(params) try: idesvar = fields.index('DESVAR') + ioffset except ValueError: idesvar = None try: idtable = fields.index('DTABLE') + ioffset #iDesMax = idtable # the index to start parsing DESVAR ides_stop = idtable # the index to stop parsing DESVAR except ValueError: idtable = None ides_stop = iend dvids = [] if idesvar: n = 1 for i in range(10, ides_stop): dvid_name = 'DVID' + str(n) dvid = integer_or_blank(card, i, dvid_name) #print("%s = %s" % (dvid_name, dvid)) if dvid: assert dvid is not None assert dvid != 'DESVAR' dvids.append(dvid) n += 1 labels = [] if idtable: n = 1 for i in range(idtable + 1, iend): label_name = 'Label' + str(n) label = string(card, i, label_name) #print("%s = %s" % (label_name, label)) if label: assert label != 'DTABLE' labels.append(label) dvprel = DVPREL2(oid, prop_type, pid, pname_fid, dequation, dvids, labels, p_min=p_min, p_max=p_max, comment=comment) if len(dvids) and len(labels) and idtable < idesvar: raise SyntaxError('DESVARs must be defined before DTABLE\n%s' % str(dvprel)) return dvprel
[docs] def OptID(self): return self.oid
[docs] def Pid(self): if self.pid_ref is None: pid = self.pid elif self.prop_type in self.allowed_properties: pid = self.pid_ref.pid elif self.prop_type in self.allowed_elements: pid = self.pid_ref.eid elif self.prop_type in self.allowed_masses: pid = self.pid_ref.eid elif self.prop_type in self.allowed_properties_mass: pid = self.pid_ref.pid else: raise NotImplementedError('prop_type=%r is not supported' % self.prop_type) return pid
[docs] def DEquation(self): if self.dequation_ref is None: return self.dequation return self.dequation_ref.equation_id
[docs] def calculate(self, op2_model, subcase_id): """ this should really make a call the the DEQATN; see the PBEAM for an example of get/set_optimization_value """ try: get = self.pid_ref.get_optimization_value(self.pname_fid) out = self.pid_ref.set_optimization_value(self.pname_fid, get) except Exception: print('DVPREL2 calculate : %s[%r] = ???' % (self.prop_type, self.pname_fid)) raise argsi = [] if self.dvids: for desvar in self.dvids_ref: # DESVARS arg = desvar.calculate(op2_model, subcase_id) argsi.append(arg) if self.labels: for label in self.labels: # DTABLE arg = self.dtable_ref[label] argsi.append(arg) #op2_model.log.info('DVPREL2; args = %s' % argsi) #op2_model.log.info('dvids =', self.dvids) #op2_model.log.info('labels =', self.labels) #op2_model.log.info('%s[%r] = %s' % (self.prop_type, self.pname_fid, out)) out = self.func(*argsi) op2_model.log.info(' deqatn out = %s' % out) return out
[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 .. todo:: add support for DEQATN cards to finish DVPREL2 xref """ msg = ', which is required by DVPREL2 oid=%r' % self.oid self.pid_ref = self._get_property(model, self.pid, msg=msg) self.dvids_ref = [model.Desvar(dvid, msg) for dvid in self.dvids] self.dequation_ref = model.DEQATN(self.dequation, msg=msg) self._check_args()
[docs] def _get_property(self, model, pid, msg=''): assert isinstance(self.pid, int), type(self.pid) if self.prop_type in self.allowed_properties: pid_ref = model.Property(pid, msg=msg) #elif self.prop_type in self.allowed_elements: #pid_ref = model.Element(pid, msg=msg) #elif self.prop_type in self.allowed_masses: #pid_ref = model.masses[pid] elif self.prop_type in self.allowed_properties_mass: pid_ref = model.properties_mass[pid] elif self.prop_type == 'PBUSHT': pid_ref = model.pbusht[pid] elif self.prop_type == 'PELAST': pid_ref = model.pelast[pid] else: raise NotImplementedError('prop_type=%r is not supported' % self.prop_type) assert pid_ref.type not in ['PBEND'], pid_ref return pid_ref
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.pid = self.Pid() self.dvids = self.desvar_ids self.dequation = self.DEquation() self.pid_ref = None self.dequation_ref = None self.dvids_ref = None self.dtable_ref = {}
[docs] def update_model(self, model, desvar_values): """doesn't require cross-referencing""" values = get_deqatn_value(self, model, desvar_values) prop = self._get_property(model, self.pid) try: self._update_by_dvprel(prop, values) except AttributeError: raise
#raise NotImplementedError('prop_type=%r is not supported in update_model' % self.prop_type)
[docs] def _update_by_dvprel(self, prop, value): if hasattr(prop, 'update_by_pname_fid'): prop.update_by_pname_fid(self.pname_fid, value) else: try: pname_fid_map = prop.pname_fid_map except AttributeError: msg = ('prop_type=%r name=%r has not implemented ' 'pname_fid_map/update_by_pname_fid' % ( self.prop_type, self.pname_fid)) raise NotImplementedError(msg) try: key = pname_fid_map[self.pname_fid] except KeyError: msg = ('prop_type=%r has not implemented %r ' 'for in pname_fid_map/update_by_pname_fid' % ( self.prop_type, self.pname_fid)) raise NotImplementedError(msg) setattr(prop, key, value)
def _verify(self, xref): """ Verifies all methods for this object work Parameters ---------- xref : bool has this model been cross referenced """ pass #def OptValue(self): #: .. todo:: not implemented #self.pid_ref.OptValue(self.pname_fid)
[docs] def get_xinit_lower_upper_bound(self, model): """gets the active x value and the lower/upper bounds""" return None, None, None
[docs] def raw_fields(self): list_fields = ['DVPREL2', self.oid, self.prop_type, self.Pid(), self.pname_fid, self.p_min, self.p_max, self.DEquation(), None] if self.dvids: fields2 = ['DESVAR'] + self.desvar_ids list_fields += build_table_lines(fields2, nstart=1, nend=0) if self.labels: fields2 = ['DTABLE'] + self.labels list_fields += build_table_lines(fields2, nstart=1, nend=0) return list_fields
[docs] def repr_fields(self): """ .. todo:: finish repr_fields for DVPREL2 """ 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) return self.comment + print_card_16(card)
[docs] class DVGRID(BaseCard): """ +--------+------+-----+-----+-------+----+----+----+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | +========+======+=====+=====+=======+====+====+====+ | DVGRID | DVID | GID | CID | COEFF | N1 | N2 | N3 | +--------+------+-----+-----+-------+----+----+----+ """ type = 'DVGRID' _properties = ['desvar_id', 'node_id', 'coord_id']
[docs] @classmethod def _init_from_empty(cls): dvid = 1 nid = 2 dxyz = [1., 2., 3.] return DVGRID(dvid, nid, dxyz, cid=0, coeff=1.0, comment='')
def __init__(self, dvid, nid, dxyz, cid=0, coeff=1.0, comment=''): """ Creates a DVGRID card Parameters ---------- dvid : int DESVAR id nid : int GRID/POINT id dxyz : (3, ) float ndarray the amount to move the grid point cid : int; default=0 Coordinate system for dxyz coeff : float; default=1.0 the dxyz scale factor comment : str; default='' a comment for the card """ BaseCard.__init__(self) if comment: self.comment = comment if isinstance(dxyz, list): dxyz = np.asarray(dxyz) elif not isinstance(dxyz, np.ndarray): raise TypeError('DVGRID: dxyz = %r and must be a list' % dxyz) self.dvid = dvid self.nid = nid self.cid = cid self.coeff = coeff self.dxyz = dxyz self.nid_ref = None self.cid_ref = None self.dvid_ref = None
[docs] def validate(self): if np.linalg.norm(self.dxyz) == 0.: msg = 'DVGRID Error; dvid=%s nid=%s norm(dxyz)=0.' % (self.dvid, self.nid) raise ValueError(msg)
[docs] @staticmethod def add_card(card, comment=''): """ Adds a DVGRID card from ``BDF.add_card(...)`` Parameters ---------- card : BDFCard() a BDFCard object comment : str; default='' a comment for the card """ dvid = integer(card, 1, 'dvid') nid = integer(card, 2, 'nid') cid = integer_or_blank(card, 3, 'cid', default=0) coeff = double_or_blank(card, 4, 'coeff', default=1.0) dxyz = [ double_or_blank(card, 5, 'n1', default=0.), double_or_blank(card, 6, 'n2', default=0.), double_or_blank(card, 7, 'n3', default=0.), ] return DVGRID(dvid, nid, dxyz, cid=cid, coeff=coeff, 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 """ self.dvid_ref = model.desvars[self.dvid] self.nid_ref = model.Node(self.nid) self.cid_ref = model.Coord(self.cid)
@property def node_id(self): if self.nid_ref is None: return self.nid return self.nid_ref.nid @property def coord_id(self): if self.cid_ref is None: return self.cid return self.cid_ref.cid @property def desvar_id(self): if self.dvid_ref is None: return self.dvid return self.dvid_ref.dvid
[docs] def uncross_reference(self) -> None: """Removes cross-reference links""" self.nid = self.node_id self.cid = self.coord_id self.dvid = self.desvar_id self.nid_ref = None self.cid_ref = None self.dvid_ref = None
[docs] def raw_fields(self): list_fields = [ 'DVGRID', self.desvar_id, self.node_id, self.coord_id, self.coeff] + list(self.dxyz) 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)
def _verify(self, xref): pass
[docs] def parse_table_fields(card_type: str, card: BDFCard, fields): """ params = { (0, 'DRESP1') = [10, 20], (1, 'DESVAR') = [30], (2, 'DRESP1') = [40], } """ params = {} if not fields: return params j = 0 value_list = [] key = None # dummy key integer_names = [ 'DESVAR', 'DRESP1', 'DRESP2', 'DVCREL1', 'DVCREL2', 'DVMREL1', 'DVMREL2', 'DVPREL1', 'DVPREL2', 'DNODE'] for (i, field) in enumerate(fields): if i % 8 == 0 and field is not None: if i > 0: assert len(value_list) > 0, 'key=%s values=%s' % (key, value_list) params[key] = value_list j += 1 key = (j, field) value_list = [] name = field elif field is not None: if name in integer_names: #print('field=%s value=%r type=%r should be an integer...\ncard=%s' % ( #i+9, field, name, card)) assert isinstance(field, integer_types), 'field=%i value=%r type=%s should be an integer...\ncard=%s' % (i+9, field, name, card) elif name == 'DTABLE': #print('field=%s value=%r type=%r should be an string...\ncard=%s' % ( #i+9, field, name, card)) assert isinstance(field, str), 'field=%i value=%r type=%s should be an string...\ncard=%s' % (i+9, field, name, card) elif name == 'DFRFNC': pass elif name == 'USRDATA' and card_type == 'DRESP3': pass else: raise NotImplementedError('name=%r\n%s' % (name, card)) value_list.append(field) params[key] = value_list assert None not in params, params params2 = {} for (i, name), values in params.items(): if name != 'DNODE': params2[(i, name)] = values continue nids = [] components = [] if len(values) % 2 != 0: msg = 'DNODE nvalues=%s must be even; values=%s' % (len(values), values) raise RuntimeError(msg) for j, value in zip(cycle([0, 1]), values): if j == 0: nids.append(value) else: components.append(value) assert len(nids) == len(components) assert len(nids) > 0 params2[(i, name)] = (nids, components) return params2
[docs] def _get_dresp23_table_values(name, values_list, inline=False): """ Parameters ---------- name : str the name of the response (e.g., DRESP1, DVPREL1) values_list : varies typical : list[int] DNODE : list[list[int], list[int]] inline : bool; default=False used for DNODE """ out = [] if name in ['DRESP1', 'DRESP2']: for val in values_list: if isinstance(val, integer_types): out.append(val) else: out.append(val.OptID()) elif name in ['DVCREL1', 'DVCREL2']: for val in values_list: if isinstance(val, integer_types): out.append(val) else: out.append(val.OptID()) elif name in ['DVMREL1', 'DVMREL2']: for val in values_list: if isinstance(val, integer_types): out.append(val) else: out.append(val.OptID()) elif name in ['DVPREL1', 'DVPREL2']: for val in values_list: if isinstance(val, integer_types): out.append(val) else: out.append(val.OptID()) elif name == 'DESVAR': for val in values_list: if isinstance(val, integer_types): out.append(val) else: out.append(val.desvar_id) elif name == 'DNODE': nids_list, components_list = values_list if inline: for nid, component in zip(nids_list, components_list): if isinstance(nid, integer_types): out.append(nid) else: out.append(nid.nid) out.append(component) else: out1 = [] out2 = [] out = [out1, out2] for nid, component in zip(nids_list, components_list): if isinstance(nid, integer_types): out1.append(nid) else: out1.append(nid.nid) out2.append(component) elif name == 'DTABLE': out = values_list else: raise NotImplementedError(f' TODO: _get_values {str(name)}') #out = values_list return out
[docs] def get_dvxrel1_coeffs(dvxrel, model, desvar_values, debug=False): """ Used by DVPREL1/2, DVMREL1/2, DVCREL1/2, and DVGRID to determine the value for the new property/material/etc. value """ value = dvxrel.c0 if debug: print('value_init=%s' % value) for coeff, desvar_id in zip(dvxrel.coeffs, dvxrel.desvar_ids): #desvar = model.desvars[desvar_id] #valuei = desvar.value valuei = _get_desvar(desvar_values, desvar_id, dvxrel) if debug: print(' desvar_id=%s coeff=%s valuei=%s' % (desvar_id, coeff, valuei)) value += coeff * valuei if debug: print('value_final=%s' % value) return value
[docs] def _get_desvar(desvar_values, desvar_id, dvxrel): try: value = desvar_values[desvar_id] except KeyError: msg = 'Cannot find desvar_id=%r in:\n%s\ndesvar_ids=%s' % ( desvar_id, dvxrel, list(desvar_values.keys()) ) raise KeyError(msg) assert isinstance(value, float), value #print('value = %s' % value) return value
[docs] def _get_dtable_value(dtable, labels, dvxrel): values = [] if not labels: return values if dtable is None: raise KeyError('DTABLE is None and must contain %s\n%s' % ( str(labels), str(dvxrel))) for label in labels: value = dtable[label] values.append(value) return values
[docs] def get_deqatn_args(dvxrel2, model, desvar_values): """gets the arguments for the DEQATN for the DVxREL2""" values = [] for desvar_id in dvxrel2.dvids: valuei = _get_desvar(desvar_values, desvar_id, dvxrel2) values.append(valuei) if dvxrel2.labels: values += _get_dtable_value(model.dtable, dvxrel2.labels, dvxrel2) return values
[docs] def get_deqatn_value(dvxrel2, model, desvar_values): values = get_deqatn_args(dvxrel2, model, desvar_values) deqatn = model.DEQATN(dvxrel2.dequation) #print(deqatn.func_str) #exec(deqatn.func_str) func = deqatn.func if func is None: msg = 'func is None...DEQATN=%s\n%s\n%s' % (dvxrel2.dequation, dvxrel2, deqatn) raise RuntimeError(msg) #print(func) try: value = func(*values) except NameError: print(deqatn) print(deqatn.func_str) raise return value
[docs] def get_dvprel_key(dvprel, prop=None): """helper method for the gui""" msg = '' prop_type = dvprel.prop_type var_to_change = dvprel.pname_fid if prop_type == 'PROD': if var_to_change in ['A', 'J']: pass elif isinstance(var_to_change, integer_types): # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PTUBE': if var_to_change in ['OD', 'T']: pass elif isinstance(var_to_change, integer_types): # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PSHELL': if var_to_change in ['T']: pass elif var_to_change == 6: var_to_change = '12I/t^3' elif var_to_change == 8: var_to_change = 'Ts/T' elif isinstance(var_to_change, integer_types): # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PCOMP': if isinstance(var_to_change, integer_types): if var_to_change in valid_pcomp_codes: pass else: msg = 'prop_type=%r pname/fid=%s int is not supported' % (prop_type, var_to_change) elif var_to_change.startswith('THETA') or var_to_change.startswith('T'): pass elif var_to_change in ['Z0', 'SB', 'TREF', 'GE']: pass else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PCOMPG': if isinstance(var_to_change, integer_types): msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) elif var_to_change.startswith('THETA') or var_to_change.startswith('T'): pass elif var_to_change in ['Z0', 'SB']: pass elif isinstance(var_to_change, integer_types): # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PBAR': pbar_var_map = { # 1-based 4 : 'A', 5 : 'I1', 6 : 'I2', 7 : 'J', 10 : 'C1', 11 : 'C2', 12 : 'D1', 13 : 'D2', 14 : 'E1', 15 : 'E2', 16 : 'F1', 17 : 'F2', 18 : 'K1', 19 : 'K1', 20 : 'I12', } if var_to_change in ['A', 'I1', 'I2', 'J', 'C1', 'C2', 'D1', 'D2', 'E1', 'E2', 'F1', 'F2', 'K1', 'K2', 'I12']: pass elif isinstance(var_to_change, integer_types): # pragma: no cover if var_to_change in pbar_var_map: var_to_change = pbar_var_map[var_to_change] else: msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PBEAM': if isinstance(var_to_change, str): if var_to_change in ['A', 'I1', 'I2', 'I1(B)', 'J', 'I2(B)', 'A(A)',]: pass else: word, num = break_word_by_trailing_parentheses_integer_ab( var_to_change) var_to_change = '%s(%s)' % (word, num) # A(A), A(1), A(10) elif isinstance(var_to_change, integer_types): # pragma: no cover if var_to_change < 0: # shift to divisible by 16 if not (-167 <= var_to_change <= -6): msg = 'A-property_type=%r has not implemented %r in pname_map' % ( prop_type, var_to_change) raise NotImplementedError(msg) ioffset = -var_to_change - 6 istation = ioffset // 16 iterm = ioffset % 16 # 0 1 2 3 4 5 6 7 8 9 #(soi, xxb, a, i1, i2, i12, j, nsm, c1, c2, # #10 11 12 13 14 15 #d1, d2, e1, e2, f1, f2) = pack assert istation == 0, istation pbeam_var_map = { 2 : 'A', 3 : 'I1', 4 : 'I2', 5 : 'I12', 6 : 'J', #7 : 'NSM', 8 : 'C1', 9 : 'C2', 10 : 'D1', 11 : 'D2', 12 : 'E1', 13 : 'E2', 14 : 'F1', 15 : 'F2', } if iterm in pbeam_var_map: var_to_change = pbeam_var_map[iterm] + str(istation + 1) else: msg = 'istation=%s iterm=%s' % (istation, iterm) msg += 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PBARL': if isinstance(var_to_change, integer_types): msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) elif var_to_change.startswith('DIM'): pass else: # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) if prop is None: var_to_change = '??? %s' % (var_to_change) else: var_to_change = '%s %s' % (prop.Type, var_to_change) elif prop_type == 'PBEAML': if isinstance(var_to_change, integer_types): msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) elif var_to_change in ['NSM']: pass elif var_to_change.startswith('DIM'): pass else: # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) if prop is None: var_to_change = '??? %s' % (var_to_change) else: var_to_change = '%s %s' % (prop.Type, var_to_change) elif prop_type == 'PSHEAR': if var_to_change in ['T']: pass elif isinstance(var_to_change, integer_types): # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PELAS': if var_to_change in ['K1', 'GE1']: pass elif isinstance(var_to_change, integer_types): # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PELAST': if var_to_change in ['TKID']: pass elif isinstance(var_to_change, integer_types): # pragma: no cover #if var_to_change == 5: # PID TKID TGEID TKNID #var_to_change = 'TKNID' #else: msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PDAMP': if var_to_change in ['B1']: pass elif isinstance(var_to_change, integer_types): # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PWELD': if var_to_change in ['D']: pass elif isinstance(var_to_change, integer_types): # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PBUSH': pbush_var_map = { -2 : 'K1', -3 : 'K2', -4 : 'K3', -5 : 'K4', -6 : 'K5', -7 : 'K6', -8 : 'B1', -9 : 'B2', -10 : 'B3', -11 : 'B4', -12 : 'B5', -13 : 'B6', -14 : 'GE1', -15 : 'GE2', -16 : 'GE3', -17 : 'GE4', -18 : 'GE5', -19 : 'GE6', -20 : 'SA', -21 : 'ST', -22 : 'EA', -23 : 'ET', } #data_in = (pid, k1, k2, k3, k4, k5, k6, b1, b2, b3, b4, b5, b6, #g1, g2, g3, g4, g5, g6, sa, st, ea, et) if isinstance(var_to_change, int) and var_to_change < 0: # and (var_to_change <= -23 <= var_to_change < 1): var_to_change = pbush_var_map[var_to_change] elif var_to_change in ['K1', 'K2', 'K3', 'K4', 'K5', 'K6', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'M1', 'M2', 'M3', 'M4', 'M5', 'M6', 'GE1', 'GE3', 'GE4', 'GE5', 'GE6',]: pass elif isinstance(var_to_change, integer_types): # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PBUSH1D': if var_to_change in ['K', 'C', 'M']: pass elif isinstance(var_to_change, integer_types): # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PBUSHT': if var_to_change in ['TGEID1', 'TGEID2']: pass elif isinstance(var_to_change, integer_types): # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PGAP': if var_to_change in ['KA',]: pass elif isinstance(var_to_change, integer_types): # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PVISC': if var_to_change in ['CE1']: pass elif isinstance(var_to_change, integer_types): # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PFAST': if var_to_change in ['KT1', 'KT2', 'KT3', 'KR1', 'KR2', 'KR3', 'MASS']: pass elif isinstance(var_to_change, integer_types): # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PMASS': # 3 if var_to_change == 3: var_to_change = 'M1' if var_to_change in ['M1']: pass #elif isinstance(var_to_change, int): # pragma: no cover #msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PBRSECT': # 3 if var_to_change in ['T', 'W', 'H']: pass else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) elif prop_type == 'PBMSECT': # 3 if var_to_change in ['T', 'W', 'H']: pass elif var_to_change.startswith('T(') and var_to_change.endswith(')'): # T(2) pass else: # pragma: no cover msg = 'prop_type=%r pname/fid=%r is not supported' % (prop_type, var_to_change) else: # pragma: no cover msg = 'prop_type=%r pname/fid=%s is not supported' % (prop_type, var_to_change) key = '%s %s' % (prop_type, var_to_change) return key, msg
[docs] def _export_dresps_to_hdf5(h5_file, model, encoding): """exports dresps""" dresp1s = [] dresp2s = [] dresp3s = [] for key, dresp in model.dresps.items(): # key : int if dresp.type == 'DRESP1': dresp1s.append(dresp) elif dresp.type == 'DRESP2': dresp2s.append(dresp) elif dresp.type == 'DRESP3': dresp3s.append(dresp) else: print(key) print(dresp.get_stats()) raise NotImplementedError(dresp.type) ndresp1s = len(dresp1s) if ndresp1s: dresp_group = h5_file.create_group('DRESP1') dresp_id = [] atta = [] attb = [] label = [] region = [] response_type = [] property_type = [] for i, dresp in enumerate(dresp1s): #print(dresp.get_stats()) dresp_id.append(dresp.dresp_id) # super hackish, we'll just write everything as a string if dresp.atta is None: attai = '' elif isinstance(dresp.atta, int): attai = str(dresp.atta) elif isinstance(dresp.atta, float): attai = '%.12e' % dresp.atta elif isinstance(dresp.atta, str): attai = dresp.atta else: raise TypeError(type(dresp.atta)) atta.append(attai.encode(encoding)) # int, float, str, blank # super hackish, we'll just write everything as a string if dresp.attb is None: attbi = '' elif isinstance(dresp.attb, int): attbi = str(dresp.attb) elif isinstance(dresp.attb, float): attbi = '%.12e' % dresp.attb elif isinstance(dresp.attb, str): attbi = dresp.attb else: raise TypeError(type(dresp.attb)) attb.append(attbi.encode(encoding)) # int, float, str, blank label.append(dresp.label.encode(encoding)) response_type.append(dresp.response_type.encode(encoding)) if dresp.region is None: region.append(-1) else: region.append(dresp.region) #region.append(dresp.region.encode(encoding)) #print('property_type', dresp.property_type) if dresp.property_type is None: property_typei = '' elif isinstance(dresp.atta, int): property_typei = str(dresp.property_type) else: property_typei = dresp.property_type property_type.append(property_typei.encode(encoding)) #atta : 1 #attb : None #atti : [2] #dresp_id : 10 #label : 'DISPL' #property_type : None #region : None #response_type : 'DISP' dresp_groupi = dresp_group.create_group(str(i)) if len(dresp.atti) > 0: if isinstance(dresp.atti[0], str): # ALL #model.log.debug('str atti = %s' % dresp.atti) values_bytes = [ attii.encode(encoding) if isinstance(attii, str) else attii for attii in dresp.atti] dresp_groupi.create_dataset('atti', data=values_bytes) # int else: #model.log.debug('atti = %s' % dresp.atti) dresp_groupi.create_dataset('atti', data=dresp.atti) # int dresp_group.create_dataset('dresp_id', data=dresp_id) dresp_group.create_dataset('atta', data=atta) dresp_group.create_dataset('attb', data=attb) dresp_group.create_dataset('label', data=label) dresp_group.create_dataset('region', data=region) dresp_group.create_dataset('response_type', data=response_type) dresp_group.create_dataset('property_type', data=property_type) ndresp2s = len(dresp2s) if ndresp2s: #c1 : 1.0 #c2 : 0.005 #c3 : 10.0 #comment : u'' #dequation : 1 #dequation_str : None #dresp_id : 1 #label : 'VOLUME' #method : u'MIN' #params : {(0, u'DESVAR'): [1, 2, 3]} #region : None c123 = np.full((ndresp2s, 3), np.nan) dresp_id = np.full(ndresp2s, -1, dtype='int32') dequation = np.full(ndresp2s, -1, dtype='int32') func = [] dequation_str = [] label = [] method = [] region = [] dresp_group = h5_file.create_group('DRESP2') for i, dresp in enumerate(dresp2s): #model.log.debug('\n' + dresp.get_stats()) # DRESP2 params: {(0, u'DRESP1'): [1], (0, u'DTABLE'): [u'L1'], (0, u'DESVAR'): [1]} # DRESP2 params: {(0, 'DRESP1'): [10501, 10502, 10503]} param_keys = [None] * len(dresp.params) #print(dresp_group) #model.log.debug(' DRESP2 params %s %s' % (i, dresp.params)) #print('i = %i' % i) dresp_groupi = dresp_group.create_group(str(i)) for (j, param_key), values in dresp.params.items(): try: param_keys[j] = param_key.encode(encoding) except IndexError: print(dresp.get_stats()) print(' DRESP2', (i, j), param_key, values) raise dresp_groupj = dresp_groupi.create_group(str(j)) values2 = [val.encode(encoding) if isinstance(val, str) else val for val in values] dresp_groupj.create_dataset('values', data=values2) dresp_groupi.create_dataset('param_keys', data=param_keys) #print('param_keys =', param_keys) #print('keys', list(dresp_group.keys())) dresp_id[i] = dresp.dresp_id c123[i, :] = [dresp.c1, dresp.c2, dresp.c3] method.append(dresp.method.encode(encoding)) label.append(dresp.label.encode(encoding)) if dresp.region is None: region.append(-1) else: region.append(dresp.region) #region.append(dresp.region.encode(encoding)) if isinstance(dresp.dequation, int): dequation[i] = dresp.dequation func.append(b'') else: func.append(dresp.dequation.encode(encoding)) assert dresp.dequation_str is None, dresp.get_stats() if dresp.dequation_str is None: dequation_str.append(b'') else: dequation_str.append(dresp.dequation_str) #dresp_id[i] = dresp.dresp_id #dresp_id[i] = dresp.dresp_id dresp_group.create_dataset('dresp_id', data=dresp_id) dresp_group.create_dataset('c123', data=c123) dresp_group.create_dataset('dequation', data=dequation) dresp_group.create_dataset('func', data=func) dresp_group.create_dataset('dequation_str', data=dequation_str) dresp_group.create_dataset('label', data=label) dresp_group.create_dataset('method', data=method) dresp_group.create_dataset('region', data=region) ndresp3s = len(dresp3s) if ndresp3s: model.log.warning('skipping DRESP3')
[docs] def none_max(lower_bound, xlb): """helper method for DVPREL1""" if lower_bound is None: return xlb return max(lower_bound, xlb)
[docs] def none_min(upper_bound, xub): """helper method for DVPREL1""" if upper_bound is None: return xub return min(upper_bound, xub)