def run_fem2(bdf_model, out_model, xref, punch,
             sum_load, size, is_double,
             reject, debug=False, log=None):
    """
    Reads/writes the BDF to verify nothing has been lost

    Parameters
    ----------
    bdf_model : str
        the filename to run
    xref : bool
       xrefs
    punch : bool
       punches
    """
    assert os.path.exists(bdf_model), bdf_model
    assert os.path.exists(out_model), out_model
    fem2 = BDF(debug=debug, log=log)
    fem2.log.info('starting fem2')
    sys.stdout.flush()
    try:
        fem2.read_bdf(out_model, xref=xref, punch=punch)
    except:
        print("failed reading %r" % out_model)
        raise

    #fem2.sumForces()
    #fem2.sumMoments()
    out_model2 = bdf_model + '_out2'
    fem2.write_bdf(out_model2, interspersed=True)
    #fem2.writeAsCTRIA3(out_model_2)
    os.remove(out_model2)
    return fem2
Example #2
0
def run_fem2(bdf_model,
             out_model,
             xref,
             punch,
             sum_load,
             size,
             precision,
             reject,
             debug=False,
             log=None):
    assert os.path.exists(bdf_model), bdf_model
    assert os.path.exists(out_model), out_model
    fem2 = BDF(debug=debug, log=log)
    fem2.log.info('starting fem2')
    sys.stdout.flush()
    try:
        fem2.read_bdf(out_model, xref=xref, punch=punch)
    except:
        print("failed reading %r" % out_model)
        raise

    #fem2.sumForces()
    #fem2.sumMoments()
    out_model2 = bdf_model + '_out2'
    fem2.write_bdf(out_model2, interspersed=True)
    #fem2.writeAsCTRIA3(out_model_2)
    os.remove(out_model2)
    return fem2
Example #3
0
    def test_combo_1(self):
        model = BDF(debug=False, log=None)
        bdfname = os.path.join(testpath, 'test_mass.dat')
        model.read_bdf(bdfname, xref=True)

        # these are valid
        eids, mass = model.elements.get_mass_by_element_id([8, 9])
        print('massA = %s' % mass)
        eids, mass = model.elements.get_mass_by_element_id(range(1, 10))
        print('massB = %s' % mass)

        # no analysis - out of range
        elements = model.elements[[100000, 100001]]
        eids, mass = model.elements.get_mass_by_element_id(range(100000, 100005))
        print('elementsC = %s' % eids)
        print('massC = %s' % mass)

        eids, mass = model.elements.get_mass_by_element_id(range(-10, -5))
        print('elementsD = %s' % eids)
        print('massD = %s' % mass)

        print('-------------------------')
        eids, mass = model.elements.get_mass_by_element_id(range(-3, 20))
        print('massE = %s' % mass)
        print('eidsE = %s' % eids)
        print('\neid   mass')
        print('----------')
        for eidi, massi in zip(eids, mass):
            print('%-5s %-5s' % (eidi, massi))
Example #4
0
    def test_bad_01(self):
        model = BDF(debug=False, log=None)
        bdfname = os.path.join(testpath, 'test_mass.dat')
        model.read_bdf(bdfname, xref=True)

        # this passes silently
        print(model.elements[['cat']])

        # this does not
        with self.assertRaises(TypeError):
            print(model.elements[None])

        #print('elements = %r' % model.elements['cat'])
        with self.assertRaises(KeyError):
            model.elements['cat']
Example #5
0
    def test_mass_solid_1(self):  # passes
        model = BDF(debug=False, log=None)
        bdfname = os.path.join(TEST_PATH, 'test_mass.dat')
        model.read_bdf(bdfname, xref=True)

        # hexa - psolid - nsm = 0
        #print(model.elements[7:8])
        #print(model.elements[[7,8]])
        model.elements[7:9]
        model.elements[7:9:2]
        model.elements[1:100]
        #hexa = model.get_elements(7)
        #hexa = model.get_elements(7)
        #print(hexa)
        hexa = model.elements[7]
        print('hexa =', hexa)
        mass = 0.2
        volume = 2.  # l * w * h = 1 * 1 * 2
        rho = 0.1
        E = 1.0
        G = 2.0
        nu = 3.0
        centroid = array([0.5, 0.5, 1.0])
        self.verify_psolid_element(hexa, mass, volume, centroid, rho, E, G, nu)

        # tetra - psolid
        tetra = model.elements[8]
        mass = 1 / 30.
        volume = 1 / 3.  # 1/3 * b * h = 1/3 * 0.5 * 2.0
        rho = 0.1
        E = 1.0
        G = 2.0
        nu = 3.0
        centroid = array([0.5, 0.25, 0.5])
        self.verify_psolid_element(tetra, mass, volume, centroid, rho, E, G,
                                   nu)

        # penta - psolid
        penta = model.elements[9]
        mass = 0.1
        volume = 1.0  # b * h = 0.5 * 2
        rho = 0.1
        E = 1.0
        G = 2.0
        nu = 3.0
        centroid = array([2 / 3., 1 / 3., 1.])
        self.verify_psolid_element(penta, mass, volume, centroid, rho, E, G,
                                   nu)
Example #6
0
def bdf_renumber(bdf_filename,
                 bdf_filename_out,
                 size=8,
                 is_double=False,
                 starting_id_dict=None,
                 round_ids=False,
                 cards_to_skip=None):
    """
    Renumbers a BDF

    Parameters
    ----------
    bdf_filename : str
        a bdf_filename (string; supported) or a BDF model (BDF)
        that has been cross referenced and is fully valid (a equivalenced deck is not valid)
    bdf_filename_out : str
        a bdf_filename to write
    size : int; {8, 16}; default=8
        the bdf write precision
    is_double : bool; default=False
        the field precision to write
    starting_id_dict : dict, None (default=None)
        None : renumber everything starting from 1
        dict : {key : starting_id}
            key : str
                the key (e.g. eid, nid, cid, ...)
            starting_id : int, None
                int : the value to start from
                None : don't renumber this key
    round_ids : bool; default=False
        Should a rounding up be applied for each variable?
        This makes it easier to read a deck and verify that it's been renumbered properly.
        This only really applies when starting_id_dict is None
    cards_to_skip : List[str]; (default=None -> don't skip any cards)
        There are edge cases (e.g. FLUTTER analysis) where things can break due to
        uncross-referenced cards.  You need to disable entire classes of cards in
        that case (e.g. all aero cards).

    .. todo:: bdf_model option for bdf_filename hasn't been tested
    .. todo:: add support for subsets (e.g. renumber only a subset of nodes/elements)
    .. todo:: doesn't support partial renumbering
    .. todo:: doesn't support element material coordinate systems

    ..warning :: spoints might be problematic...check
    ..warning :: still in development, but it usually brutally crashes if it's not supported
    ..warning :: be careful of card unsupported cards (e.g. ones not read in)

    Supports
    ========
     - GRIDs
       - no superelements
     - COORDx

     - elements
        - CELASx/CONROD/CBAR/CBEAM/CQUAD4/CTRIA3/CTETRA/CPENTA/CHEXA
        - RBAR/RBAR1/RBE1/RBE2/RBE3/RSPLINE

     - properties
        - PSHELL/PCOMP/PCOMPG/PSOLID/PSHEAR/PBAR/PBARL
          PROD/PTUBE/PBEAM
     - mass
        - CMASSx/CONMx/PMASS

     - aero
       - FLFACT
       - SPLINEx
       - FLUTTER

     - partial case control
       - METHOD/CMETHOD/FREQENCY
       - LOAD/DLOAD/LSEQ/LOADSET...LOADSET/LSEQ is iffy
       - SET cards
         - nodes
         - elements
       - SPC/MPC/FLUTTER/FLFACT

    - constraints
       - SPC/SPCADD/SPCAX/SPCD
       - MPC/MPCADD
       - SUPORT/SUPORT1

    - solution control/methods
       - TSTEP/TSTEPNL
       - NLPARM
       - EIGB/EIGC/EIGRL/EIGR

    - sets
       - USET

    - other
      - tables
      - materials
      - loads/dloads


    Not Done
    ========
     - SPOINT
     - any cards with SPOINTs
       - DMIG/DMI/DMIJ/DMIJI/DMIK/etc.
       - CELASx
       - CDAMPx
     - superelements
     - aero cards
       - CAEROx
       - PAEROx
     - thermal cards?
     - optimization cards
     - SETx
     - PARAM,GRDPNT,x; where x>0
     - GRID SEID
     - case control
       - STATSUB
       - SUBCASE
       - global SET cards won't be renumbered properly

    Examples
    --------
    # Renumber Everything; Start from 1
    >>> bdf_renumber(bdf_filename, bdf_filename_out, size=8, is_double=False,
                     round_ids=False)

    # Renumber Everything; Start Material IDs from 100
    >>> starting_id_dict = {
        'mid' : 100,
    }
    >>> bdf_renumber(bdf_filename, bdf_filename_out, size=8, is_double=False,
                     starting_ids_dict=starting_ids_dict, round_ids=False)

    # Only Renumber Material IDs
    >>> starting_id_dict = {
        'cid' : None,
        'nid' : None,
        'eid' : None,
        'pid' : None,
        'mid' : 1,
        'spc_id' : None,
        'mpc_id' : None,
        'load_id' : None,
        'dload_id' : None,

        'method_id' : None,
        'cmethod_id' : None,
        'spline_id' : None,
        'table_id' : None,
        'flfact_id' : None,
        'flutter_id' : None,
        'freq_id' : None,
        'tstep_id' : None,
        'tstepnl_id' : None,
        'suport_id' : None,
        'suport1_id' : None,
        'tf_id' : None,
    }
    >>> bdf_renumber(bdf_filename, bdf_filename_out, size=8, is_double=False,
                     starting_ids_dict=starting_ids_dict, round_ids=False)
    """
    starting_id_dict_default = {
        'cid': 1,
        'nid': 1,
        'eid': 1,
        'pid': 1,
        'mid': 1,
        'spc_id': 1,
        'mpc_id': 1,
        'load_id': 1,
        'dload_id': 1,
        'method_id': 1,
        'cmethod_id': 1,
        'spline_id': 1,
        'table_id': 1,
        'flfact_id': 1,
        'flutter_id': 1,
        'freq_id': 1,
        'tstep_id': 1,
        'tstepnl_id': 1,
        'suport_id': 1,
        'suport1_id': 1,
        'tf_id': 1,
    }
    # fill up starting_id_dict
    if starting_id_dict is None:
        starting_id_dict = starting_id_dict_default
    else:
        for key, value in iteritems(starting_id_dict_default):
            if key not in starting_id_dict:
                starting_id_dict[key] = value

    nid = None
    cid = None
    eid = None
    pid = None
    mid = None
    spc_id = None
    mpc_id = None
    load_id = None
    dload_id = None
    method_id = None
    cmethod_id = None
    spline_id = None
    table_id = None
    flfact_id = None
    flutter_id = None
    freq_id = None
    tstep_id = None
    tstepnl_id = None
    suport_id = None
    suport1_id = None
    tf_id = None

    # turn them into variables
    for key, value in sorted(iteritems(starting_id_dict)):
        #assert isinstance(key, string_types), key
        assert key in starting_id_dict_default, 'key=%r is invalid' % (key)
        if value is None:
            pass
        else:
            if not isinstance(value, integer_types):
                msg = 'key=%r value=%r must be an integer; type(value)=%s' % (
                    key, value, type(value))
                raise TypeError(msg)

        if key == 'nid':
            nid = int(value)
        elif key == 'cid':
            if value is None:
                cid = None
            else:
                cid = int(value)
        elif key == 'eid':
            eid = int(value)
        elif key == 'pid':
            if value is None:
                pid = None
            else:
                pid = int(value)
        elif key == 'mid':
            if value is None:
                mid = None
            else:
                mid = int(value)
        elif key == 'spc_id':
            spc_id = int(value)
        elif key == 'mpc_id':
            mpc_id = int(value)

        elif key == 'load_id':
            load_id = int(value)
        elif key == 'dload_id':
            dload_id = int(value)
        elif key == 'method_id':
            method_id = int(value)
        elif key == 'cmethod_id':
            cmethod_id = int(value)
        elif key == 'spline_id':
            spline_id = int(value)
        elif key == 'table_id':
            table_id = int(value)
        elif key == 'flfact_id':
            flfact_id = int(value)
        elif key == 'flutter_id':
            flutter_id = int(value)
        elif key == 'freq_id':
            freq_id = int(value)
        elif key == 'tstep_id':
            tstep_id = int(value)
        elif key == 'tstepnl_id':
            tstepnl_id = int(value)
        elif key == 'suport_id':
            suport_id = int(value)
        elif key == 'suport1_id':
            suport1_id = int(value)
        elif key == 'tf_id':
            tf_id = int(value)
        else:
            raise NotImplementedError('key=%r' % key)

    # build the maps
    #eid_map = {}
    #nid_map = {}
    #reverse_nid_map = {}
    #pid_map = {}
    #mid_map = {}
    #mpc_map = {}
    #spc_map = {}
    dload_map = {}
    load_map = {}

    cmethod_map = {}
    method_map = {}
    #flfact_map = {}
    #flutter_map = {}
    #aefact_map = {}
    #freq_map = {}
    tstep_map = {}
    tstepnl_map = {}
    suport_map = {}
    suport1_map = {}

    if isinstance(bdf_filename, string_types):
        model = BDF(debug=False)
        model.disable_cards(cards_to_skip)
        model.read_bdf(bdf_filename)
    else:
        model = bdf_filename

    elements = [
        model.celas1,
        model.celas2,
        model.celas3,
        model.celas4,
        #model.cdamp1,
        #model.cdamp2,
        #model.cdamp3,
        #model.cdamp4,
        model.conrod,
        model.crod,
        model.ctube,
        model.cbar,
        model.cbeam,
        model.cshear,
        model.cquad4,
        model.ctria3,
        model.cquad8,
        model.ctria6,
        #model.ctriax,
        model.ctriax6,
        model.ctetra4,
        model.ctetra10,
        model.cpenta6,
        model.cpenta15,
        #model.cpyram5, model.cpyram13,
        model.chexa8,
        model.chexa20,
    ]
    props = [
        model.pelas,
        #model.pdamp,
        model.ptube,
        model.ptube,
        model.pbar,
        model.pbarl,
        model.pbeam,
        model.pbeaml,
        model.pshear,
        model.pshell,
        model.pcomp,
        #model.pcompg,
        model.psolid,
        model.plsolid,
    ]
    materials = [
        model.mat1,
        #model.mat2,
        #model.mat3,
        #model.mat4,
        #model.mat5,
        model.mat8,
        #model.mat9,
        #model.mat10,
        #model.mat11,
    ]
    loads = [
        model.force,
        model.force1,
        model.force2,
        model.moment,
        model.moment1,
        model.moment2,
        model.pload,
        model.pload1,
        model.pload2,
        model.pload4,
        #model.rforce,
        #model.dload,
        #model.load,
        #model.sload,
    ]

    nid_map = {}
    #reverse_nid_map = {}
    if 'nid' in starting_id_dict and nid is not None:
        #i = nid
        #nid_map = {}
        ngrids = model.grid.n
        if ngrids:
            nids = model.grid.node_id - 1
            nid_map.update({(nid + nids[i]): (i + 1) for i in range(ngrids)})
            #reverse_nid_map.update(
            #{(i+1) : (nid + nids[i]) for i in range(ngrids)}) # index to nid
        #print(min(nid_map))
        # TODO: SPOINTs
        # TODO: EPOINTs
        #if model.spoints.points:

    cid_map = {}
    if 'cid' in starting_id_dict and cid is not None:
        cids = model.coords.coords.keys()
        #print(cids)
        ncoords = len(cids)
        cids.sort()
        #print('cids =', cids)
        cid_map.update({(cid + cids[i] - 1): (i) for i in range(ncoords)})
        #print('cid_map =', cid_map)

    eid_map = {}
    if 'eid' in starting_id_dict and pid is not None:

        eids = [element.element_id for element in elements if element.n]
        eids.append(model.rigid_elements.keys())
        eids = np.hstack(eids)
        neids = len(eids)
        eids.sort()
        eid_map.update({eids[i]: (i + eid) for i in range(neids)})

    pid_map = {}
    if 'pid' in starting_id_dict and pid is not None:
        pids = np.hstack([prop.property_id for prop in props if prop.n])
        npids = len(pids)
        pids.sort()
        pid_map.update({pids[i]: (i + pid) for i in range(npids)})

    mid_map = {}
    if 'mid' in starting_id_dict and mid is not None:
        mids = np.hstack([mat.material_id for mat in materials])
        nmids = len(mids)
        mids.sort()
        mid_map.update({mids[i]: (mid + i) for i in range(nmids)})

    load_map = {}
    if 'load_id' in starting_id_dict and load_id is not None:
        loadsi = [load.load_id for load in loads if load.n]
        if loadsi:
            #print(loadsi)
            load_ids = np.unique(np.hstack(loadsi))
            del loadsi
            nload_ids = len(load_ids)
            load_ids.sort()
            load_map.update(
                {load_ids[i]: (load_id + i)
                 for i in range(nload_ids)})

    spc_map = {}
    if 'spc_id' in starting_id_dict and spc_map is not None:
        spcs = [model.spc, model.spc1, model.spcadd]
        spcsi = []
        for spc_obj in spcs:
            #print(spc_obj)
            #spc_ids = [spc.spc_id for spc_id, spc in iteritems(spc_obj) if spc.n]
            spc_ids = spc_obj.keys()
            if spc_ids:
                spcsi.append(spc_ids)
        #spcsi = [spc_id for spc_id in spcs]
        #print('spcsi =', spcsi)
        #asdf
        if spcsi:
            #print(loadsi)
            spc_ids = np.unique(np.hstack(spcsi))
            #del spcsi
            nspc_ids = len(spc_ids)
            spc_ids.sort()
            spc_map.update({spc_ids[i]: (spc_id + i) for i in range(nspc_ids)})
            #print('spc_ids =', spc_ids)

    caero_map = {}
    #if model.caeros:
    #caeros = model.caeros.keys()
    #caeros.sort()
    #ncaeros = len(caeros)
    #caero_map = {caeros[i] : (i+1) for i in range(ncaeros)}

    paero_map = {}
    if model.paeros:
        paeros = model.paeros.keys()
        paeros.sort()
        npaeros = len(paeros)
        paero_map = {paeros[i]: (i + 1) for i in range(npaeros)}

    aefact_map = {}
    if model.aefacts:
        aefacts = model.aefacts.keys()
        aefacts.sort()
        naefacts = len(aefacts)
        aefact_map = {aefacts[i]: (i + 1) for i in range(naefacts)}

    spline_map = {}
    #if model.splines:
    #splines = model.splines.keys()
    #splines.sort()
    #nsplines = len(splines)
    #spline_map = {splines[i] : (i+1) for i in range(nsplines)}

    set_map = {}
    if model.sets:
        sets = model.sets.keys()
        sets.sort()
        nsets = len(sets)
        set_map = {sets[i]: (i + 1) for i in range(nsets)}

    #load_map = {}
    maps = {
        'node': nid_map,
        'coord': cid_map,
        'property': pid_map,
        'element': eid_map,
        'load': load_map,
        'material': mid_map,
        'caero': caero_map,  # ???
        'paero': paero_map,  # PAEROx
        'aefact': aefact_map,  # ???
        'spline': spline_map,  # SPLINE1-SPLINE5
        'set': set_map,
    }

    model.grid.update(maps)
    model.coords.update(maps)
    for elem in elements:
        elem.update(maps)

    rigid_elements2 = {}
    for eid, elem in iteritems(model.rigid_elements):
        eid2 = eid_map[eid]
        rigid_elements2[eid2] = eid_map[eid]
        elem.update(maps)

    for prop in props:
        prop.update(maps)
    for mat in materials:
        mat.update(maps)
    for spc_dict in spcs:
        for spc_id, spc in iteritems(spc_dict):
            spc.update(maps)

    if model.aero is not None:
        model.aero.update(maps)
    if model.aeros is not None:
        model.aeros.update(maps)

    for caero in itervalues(model.caeros):
        caero.update(maps)
    for spline in itervalues(model.splines):
        spline.update(model, maps)
    for flutter in itervalues(model.flutters):
        flutter.update(maps)
    for flfact in itervalues(model.flfacts):
        flfact.update(maps)
    for flutter in itervalues(model.flutters):
        flutter.update(maps)

    for desvar in itervalues(model.desvars):
        desvar.update(maps)
    for dconstr in itervalues(model.dconstrs):
        dconstr.update(maps)
    for dresp in itervalues(model.dresps):
        dresp.update(maps)
    for dconadd in itervalues(model.dconadds):
        dconadd.update(maps)
    for dvgrid in itervalues(model.dvgrids):
        dvgrid.update(maps)
    for dvcrel in itervalues(model.dvcrels):
        dvcrel.update(maps)
    for dvmrel in itervalues(model.dvmrels):
        dvmrel.update(maps)
    for dvprel in itervalues(model.dvprels):
        dvprel.update(maps)

    model.darea.update(maps)
    model.dphase.update(maps)

    if bdf_filename_out is not None:
        model.write_bdf(bdf_filename_out,
                        size=size,
                        is_double=is_double,
                        interspersed=False)
    return model
Example #7
0
    def test_mass_shell_1(self):  # passes
        model = BDF(debug=False, log=None)
        bdfname = os.path.join(testpath, 'test_mass.dat')
        model.read_bdf(bdfname, xref=True)

        ###########
        # QUADS
        centroid = array([.5, .5, 0.])
        normal = array([.0, .0, 1.])
        ###########
        # quad - pcomp
        quad = model.elements[1]
        i = model.properties_shell.pcomp.get_property_index_by_property_id(quad.property_id)
        prop = model.properties_shell.pcomp[i]
        #mat = model.properties_shell.pshell[prop.material_id]
        mass = 0.12
        area = 1.0
        nsm = 0.
        thickness = 0.7
        rho1 = 0.1
        rho10 = 0.2
        t1 = 0.1
        t10 = 0.5
        # there are two layers of t1
        mpa = (2. * rho1 * t1 + rho10 * t10) + nsm
        mass2 = mpa * area
        assert allclose(mass, mass2), 'mass=%s mass2=%s diff=%s' % (mass, mass2, abs(mass - mass2))
        self.verify_pcomp_element(quad, prop, nsm, thickness, mass, area, centroid, normal)

        rho = None

        # quad - pshell, nsm=0
        eid = 3
        pid = 2
        quad = model.elements[eid]
        prop = model.properties_shell.pshell.slice_by_property_id(pid)
        #mat = model.materials[prop.material_id]  # good?
        mat = None
        rho = 0.1
        mass = 0.0125
        t = 0.125
        nsm = 0.
        area = 1.
        mass2 = area * (rho * t + nsm)
        assert allclose(mass, mass2), 'eid=%s pid=%s mass=%s mass2=%s diff=%s\n%s%s%s\nrho=%s A=%s t=%s nsm=%s' % (
            eid, pid, mass, mass2, abs(mass - mass2), quad, prop, mat, rho, area, t, nsm)
        centroid = array([.5, .5, 0.])
        normal = array([.0, .0, 1.])
        self.verify_pshell_element(quad, prop, mat, rho, mass, area, centroid, normal, nsm)

        # quad - pshell, nsm=1
        quad = model.elements[5]
        prop = model.properties_shell.pshell.slice_by_property_id(quad.property_id)
        #mat = model.properties_shell.pshell[prop.material_id]
        mat = None
        mass = 1.0125 # mass w/o nsm + 1.0 b/c area=1
        nsm = 1.
        self.verify_pshell_element(quad, prop, mat, rho, mass, area, centroid, normal, nsm)

        ###########
        # TRIS
        centroid = array([2., 1., 0.]) / 3.
        normal = array([.0, .0, 1.])
        ###########
        # tri - pcomp
        tri = model.elements[2]
        prop = model.properties_shell.pcomp.slice_by_property_id(tri.property_id)
        #mat = model.properties_shell.pshell[prop.material_id]
        mass = 0.06
        area = 0.5
        nsm = 0.
        thickness = 0.7
        self.verify_pcomp_element(tri, prop, nsm, thickness, mass, area, centroid, normal)

        # tri - pshell, nsm=0
        tri = model.elements[4]
        i = model.properties_shell.pshell.get_property_index_by_property_id(tri.property_id)
        prop = model.properties_shell.pshell[i]
        #mat = model.properties_shell.pshell[prop.material_id]
        mat = None
        mass = 0.00625
        nsm = 0.
        self.verify_pshell_element(tri, prop, mat, rho, mass, area, centroid, normal, nsm)

        # tri - pshell, nsm=1
        tri = model.elements[6]
        prop = model.properties_shell.pshell.slice_by_property_id(tri.property_id)
        #mat = model.properties_shell.pshell[prop.material_id]
        mat = None
        mass = 0.50625 # mass w/o nsm + 0.5 b/c area=0.5
        nsm = 1.
        self.verify_pshell_element(tri, prop, mat, rho, mass, area, centroid, normal, nsm)