Ejemplo n.º 1
0
def _pload4_helper(loadcase_id, load, scale, elem, xyz, p):
    """gets the contribution for a single PLOAD4 element"""
    #eid = elem.eid
    nodes, area, face_centroid, normal, nface = _get_pload4_area_centroid_normal_nface(
        loadcase_id, load, elem, xyz)

    pressures = load.pressures[:nface]
    assert len(pressures) == nface
    cid = load.Cid()
    if load.surf_or_line == 'SURF':
        pressure = _mean_pressure_on_pload4(pressures, load, elem)
        load_dir = update_pload4_vector(load, normal, cid)

        r = face_centroid - p
        fi = pressure * area * load_dir * scale
        #load.cid_ref.transform_to_global()
        mi = cross(r, fi)

    elif load.surf_or_line == 'LINE':
        load_dir = update_pload4_vector(load, normal, cid)
        fi, mi = _pload4_helper_line(load, load_dir, elem, scale, pressures, nodes, xyz, p)
    else:  # pragma: no cover
        msg = 'surf_or_line=%r on PLOAD4 is not supported\n%s' % (
            load.surf_or_line, str(load))
        raise NotImplementedError(msg)
    return fi, mi
Ejemplo n.º 2
0
def get_forces_moments_array(model: BDF,
                             p0,
                             load_case_id: int,
                             eid_map,
                             nnodes,
                             normals,
                             dependents_nodes,
                             nid_map=None,
                             include_grav=False):
    """
    Gets the forces/moments on the nodes.

    Parameters
    ----------
    p0 : (3, ) float ndarray
        the reference location
    load_case_id : int
        the load id
    nid_map : ???
        ???
    eid_map : Dict[int eid : int index]
        ???
    nnodes : ???
        the number of nodes in nid_map
    normals : (nelements, 3) float ndarray
        the normal vectors for the shells
        what about solids???
    dependents_nodes : ???
        ???
    include_grav : bool; default=False
        is the mass of the elements considered; unused

    Returns
    -------
    temperature_data : tuple(temperature_key, temperatures)
        temperature_key : str
            One of the following:
              TEMPERATURE(MATERIAL)
              TEMPERATURE(INITIAL)
              TEMPERATURE(LOAD)
              TEMPERATURE(BOTH)
        temperatures : (nnodes, 1) float ndarray
            the temperatures
    load_data : tuple(centroidal_pressures, forces, spcd)
        centroidal_pressures : (nelements, 1) float ndarray
            the pressure
        forces : (nnodes, 3) float ndarray
            the pressure
        spcd : (nnodes, 3) float ndarray
            the SPCD load application

    Considers
    FORCE
    PLOAD2 - CTRIA3, CQUAD4, CSHEAR
    PLOAD4 - CTRIA3, CTRIA6, CTRIAR
             CQUAD4, CQUAD8, CQUAD, CQUADR, CSHEAR
             CTETRA, CPENTA, CHEXA
    SPCD

    """
    if nid_map is None:
        nid_map = model.nid_map
    if not any([
            'FORCE' in model.card_count, 'PLOAD' in model.card_count, 'PLOAD2'
            in model.card_count, 'PLOAD4' in model.card_count, 'SPCD'
            in model.card_count, 'SLOAD' in model.card_count
    ]):
        return None, None, None
    assert len(
        nid_map) == nnodes, f'len(nid_map)={len(nid_map)} nnodes={nnodes}'

    loads, scale_factors = model.get_reduced_loads(load_case_id,
                                                   skip_scale_factor0=True)[:2]

    #eids = sorted(model.elements.keys())
    centroidal_pressures = np.zeros(len(model.elements), dtype='float32')
    nodal_pressures = np.zeros(len(model.node_ids), dtype='float32')

    forces = np.zeros((nnodes, 3), dtype='float32')
    spcd = np.zeros((nnodes, 3), dtype='float32')
    # loop thru scaled loads and plot the pressure
    cards_ignored = set()

    assert normals is not None
    fail_nids = set()
    fail_count = 0
    fail_count_max = 3
    loads_to_skip = ['MOMENT', 'MOMENT1', 'MOMENT2', 'FORCE1', 'TEMP']
    nodes = model.nodes
    for load, scale in zip(loads, scale_factors):
        load_type = load.type
        if load_type in loads_to_skip:
            pass
        elif load_type == 'FORCE':
            scale2 = load.mag * scale  # does this need a magnitude?
            nid = load.node
            if nid in dependents_nodes:
                fail_nids.add(nid)
                fail_count += 1
                if fail_count < fail_count_max:
                    print(
                        '    nid=%s is a dependent node and has a FORCE applied\n%s'
                        % (nid, str(load)))
            forces[nid_map[nid]] += load.xyz * scale2

        elif load_type == 'PLOAD':
            pressure = load.pressure * scale
            nnodes = len(load.nodes)
            if nnodes == 4:
                n1, n2, n3, n4 = load.nodes
                xyz1 = nodes[n1].get_position()
                xyz2 = nodes[n2].get_position()
                xyz3 = nodes[n3].get_position()
                xyz4 = nodes[n4].get_position()
                normal_area = np.cross(xyz3 - xyz1,
                                       xyz4 - xyz2)  # TODO: not validated
            elif nnodes == 3:
                n1, n2, n3 = load.nodes
                xyz1 = nodes[n1].get_position()
                xyz2 = nodes[n2].get_position()
                xyz3 = nodes[n3].get_position()
                normal_area = np.cross(xyz2 - xyz1,
                                       xyz3 - xyz1)  # TODO: not validated
            else:
                model.log.debug(
                    '    case=%s nnodes=%r loadtype=%r not supported' %
                    (load_case_id, nnodes, load.type))
                continue
            forcei = pressure * normal_area / nnodes
            for nid in load.nodes:
                forces[nid_map[nid]] += forcei

        elif load_type == 'PLOAD2':
            pressure = load.pressure * scale  # there are 4 pressures, but we assume p0
            for eid in load.eids:
                elem = model.elements[eid]
                if elem.type in ['CTRIA3', 'CQUAD4', 'CSHEAR']:
                    node_ids = elem.node_ids
                    nnodes = len(node_ids)
                    ie = eid_map[eid]
                    normal = normals[ie, :]

                    area = elem.Area()
                    forcei = pressure * normal * area / nnodes
                    # r = elem.Centroid() - p0
                    # m = cross(r, f)
                    for nid in node_ids:
                        if nid in dependents_nodes:
                            fail_nids.add(nid)
                            fail_count += 1
                            if fail_count < fail_count_max:
                                print(
                                    f'    nid={nid} is a dependent node and has a '
                                    f'PLOAD2 applied\n{load}')
                        forces[nid_map[nid]] += forcei
                    forces += forcei
                    # F += f
                    # M += m
                else:
                    model.log.debug(
                        '    case=%s etype=%r loadtype=%r not supported' %
                        (load_case_id, elem.type, load.type))

        elif load_type == 'PLOAD4':
            # multiple elements
            eids_missing = []
            for elem in load.eids_ref:
                if isinstance(elem, integer_types):
                    # Nastran is NOT OK with missing element ids
                    eids_missing.append(elem)
                    continue
                ie = eid_map[elem.eid]
                normal = normals[ie, :]
                # pressures[eids.index(elem.eid)] += p
                if elem.type in ['CTRIA3', 'CTRIA6', 'CTRIA', 'CTRIAR']:
                    area = elem.get_area()
                    elem_node_ids = elem.node_ids
                    nface = len(elem_node_ids)

                    if load.surf_or_line == 'SURF':
                        cid = load.Cid()
                        normal = update_pload4_vector(load, normal, cid)
                    else:
                        msg = (
                            f'surf_or_line={load.surf_or_line!r} on PLOAD4 is not supported\n'
                            f'{load}')
                        model.log.debug(msg)
                        continue

                    pressures = load.pressures[:nface]
                    pressure = _mean_pressure_on_pload4(pressures, load, elem)

                    forcei = pressure * area * normal / nface
                    for nid in elem_node_ids:
                        if nid in dependents_nodes:
                            fail_nids.add(nid)
                            fail_count += 1
                            if fail_count < fail_count_max:
                                print(
                                    '    nid=%s is a dependent node and has a'
                                    ' PLOAD4 applied\n%s' % (nid, str(load)))
                        #forces[nids.index(nid)] += F
                        i = nid_map[nid]
                        try:
                            forces[i, :] += forcei
                        except IndexError:
                            print(f'i = {i}')
                            print('normals.shape = %s' % str(normals.shape))
                            print('forces.shape = %s' % str(forces.shape))
                            print('normal = ', normal)
                            print('forces[i, :] = ', forces[i, :])
                            raise
                    #nface = 3
                elif elem.type in [
                        'CQUAD4', 'CQUAD8', 'CQUAD', 'CQUADR', 'CSHEAR'
                ]:
                    area = elem.get_area()
                    elem_node_ids = elem.node_ids
                    nface = len(elem_node_ids)

                    if load.surf_or_line == 'SURF':
                        cid = load.Cid()
                        if cid in [0, None] and np.abs(
                                load.nvector).max() == 0.0:
                            # element surface normal
                            pass
                        else:
                            if np.linalg.norm(load.nvector) != 0.0 and cid in [
                                    0, None
                            ]:
                                normal = load.nvector / np.linalg.norm(
                                    load.nvector)
                            else:
                                raise NotImplementedError(
                                    'cid=%r nvector=%s on a PLOAD4 is not supported\n%s'
                                    % (cid, load.nvector, str(load)))
                    else:  # pragma: no cover
                        msg = (
                            f'surf_or_line={load.surf_or_line} on PLOAD4 is not supported\n'
                            f'{load}')
                        model.log.debug(msg)
                        continue

                    pressures = load.pressures[:nface]
                    pressure = _mean_pressure_on_pload4(pressures, load, elem)

                    forcei = pressure * area * normal / nface

                    for nid in elem_node_ids:
                        if nid in dependents_nodes:
                            fail_nids.add(nid)
                            fail_count += 1
                            if fail_count < fail_count_max:
                                print(
                                    '    nid=%s is a dependent node and has a'
                                    ' PLOAD4 applied\n%s' % (nid, str(load)))
                        #forces[nids.index(nid)] += F
                        i = nid_map[nid]
                        try:
                            forces[i, :] += forcei
                        except IndexError:
                            print('i = %s' % i)
                            print('normals.shape = %s' % str(normals.shape))
                            print('forces.shape = %s' % str(forces.shape))
                            print('normal = ', normal)
                            print('forces[i, :] = ', forces[i, :])
                            raise
                        nface = 4
                else:
                    elem_node_ids = elem.node_ids
                    if elem.type == 'CTETRA':
                        #face1 = elem.get_face(load.g1_ref.nid, load.g34_ref.nid)
                        facn = elem.get_face_area_centroid_normal(
                            load.g1_ref.nid, load.g34_ref.nid)
                        face, area, face_centroid, normal = facn
                        #assert face == face1
                        nface = 3
                    elif elem.type == 'CHEXA':
                        #face1 = elem.get_face(load.g34_ref.nid, load.g1_ref.nid)
                        facn = elem.get_face_area_centroid_normal(
                            load.g34_ref.nid, load.g1_ref.nid)
                        face, area, face_centroid, normal = facn
                        #assert face == face1
                        nface = 4
                    elif elem.type == 'CPENTA':
                        g1 = load.g1_ref.nid
                        if load.g34 is None:
                            #face1 = elem.get_face(g1)
                            facn = elem.get_face_area_centroid_normal(g1)
                            face, area, face_centroid, normal = facn
                            nface = 3
                        else:
                            #face1 = elem.get_face(g1, load.g34.nid)
                            facn = elem.get_face_area_centroid_normal(
                                g1, load.g34_ref.nid)
                            face, area, face_centroid, normal = facn
                            nface = 4
                        #assert face == face1
                    #elif elem.type == 'CPYRAM':
                    else:
                        msg = (
                            f'case={load_case_id} eid={eid} etype={elem.type!r} '
                            f'loadtype={load.type!r} not supported')
                        model.log.debug(msg)
                        continue

                    pressures = load.pressures[:nface]
                    assert len(pressures) == nface
                    cid = load.Cid()
                    if load.surf_or_line == 'SURF':
                        pressure = _mean_pressure_on_pload4(
                            pressures, load, elem)
                        load_dir = update_pload4_vector(load, normal, cid)

                        f = pressure * area * load_dir * scale
                    else:
                        msg = (
                            f'surf_or_line={load.surf_or_line!r} on PLOAD4 is not supported\n'
                            '{load}')
                        model.log.debug(msg)
                        continue

                    for inid in face:
                        inidi = nid_map[elem_node_ids[inid]]
                        nodal_pressures[inid] += pressure * scale / nface
                        forces[inidi, :] += f / nface
                    centroidal_pressures[ie] += pressure

                    #r = centroid - p
                    #load.cid.transformToGlobal()
                    #m = cross(r, f)
                    #M += m
            if eids_missing:
                model.log.error('missing PLOAD4 element ids=%s on:\n%s' %
                                (eids_missing, load.rstrip()))

        elif load_type == 'SPCD':
            #self.nodes = [integer(card, 2, 'G1'),]
            #self.constraints = [components_or_blank(card, 3, 'C1', 0)]
            #self.enforced = [double_or_blank(card, 4, 'D1', 0.0)]
            for nid, c1, d1 in zip(load.node_ids, load.components,
                                   load.enforced):
                if nid in dependents_nodes:
                    fail_nids.add(nid)
                    fail_count += 1
                    if fail_count < fail_count_max:
                        model.log.warning(
                            '    nid=%s is a dependent node and has an'
                            ' SPCD applied\n%s' % (nid, str(load)))
                c1 = int(c1)
                assert c1 in [1, 2, 3, 4, 5, 6], c1
                if c1 < 4:
                    spcd[nid_map[nid], c1 - 1] = d1
        elif load_type == 'SLOAD':
            for nid, mag in zip(load.nodes, load.mags):
                forces[nid_map[nid]] += np.array([mag, 0., 0.])
        else:
            if load_type not in cards_ignored:
                cards_ignored.add(load_type)
                model.log.warning('  get_forces_moments_array - unsupported '
                                  f'load.type = {load_type}')
    if fail_count:
        fail_nids_list = list(fail_nids)
        fail_nids_list.sort()
        model.log.warning('fail_nids = %s' % np.array(fail_nids_list))
    return centroidal_pressures, forces, spcd