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
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