def _not_equal_nodes_build_tree(nodes_xyz, xyz_compare, tol, neq_max=4, msg=''): # type: (np.ndarray, np.ndarray, float, int, str) -> (Any, np.ndarray, np.ndarray) """ helper function for `bdf_equivalence_nodes` Parameters ---------- nodes_xyz : (Nnodes, 3) float ndarray the source points xyz_compare : (Ncompare, 3) float ndarray the xyz points to compare to tol : float the max spherical tolerance neq_max : int; default=4 the number of close nodes msg : str; default='' error message Returns ------- kdt : cKDTree() the kdtree object ieq : int ndarray The indices of nodes_xyz where the nodes in xyz_compare are close??? neq_max = 1: (N, ) int ndarray neq_max > 1: (N, N) int ndarray slots : int ndarray The indices of nodes_xyz where the nodes in xyz_compare are close??? neq_max = 1: (N, ) int ndarray neq_max > 1: (N, N) int ndarray msg : str; default='' error message """ assert isinstance(xyz_compare, np.ndarray), type(xyz_compare) if nodes_xyz.shape[1] != xyz_compare.shape[1]: msgi = 'nodes_xyz.shape=%s xyz_compare.shape=%s%s' % ( str(nodes_xyz.shape), str(xyz_compare.shape), msg) raise RuntimeError(msgi) kdt = _get_tree(nodes_xyz, msg=msg) # check the closest 10 nodes for equality deq, ieq = kdt.query(xyz_compare, k=neq_max, distance_upper_bound=tol) #print(deq) #print('ieq =', ieq) #print('neq_max = %s' % neq_max) # get the ids of the duplicate nodes nnodes = nodes_xyz.shape[0] if neq_max == 1: assert len(deq.shape) == 1, deq.shape slots = np.where(ieq < nnodes) else: assert len(deq.shape) == 2, deq.shape slots = np.where(ieq[:, :] < nnodes) #print('slots =', slots) return kdt, ieq, slots
def _not_equal_nodes_build_tree(nodes_xyz, xyz_compare, tol, neq_max=4): """ helper function for `bdf_equivalence_nodes` Parameters ---------- nodes_xyz : (N, 3) float ndarray the source points xyz_compare : (N, 3) float ndarray the xyz points to compare to tol : float the max spherical tolerance neq_max : int; default=4 the number of close nodes Returns ------- kdt : cKDTree() or KDTree() the kdtree object ieq : int ndarray The indices of nodes_xyz where the nodes in xyz_compare are close??? neq_max = 1: (N, ) int ndarray neq_max > 1: (N, N) int ndarray slots : int ndarray The indices of nodes_xyz where the nodes in xyz_compare are close??? neq_max = 1: (N, ) int ndarray neq_max > 1: (N, N) int ndarray """ assert isinstance(xyz_compare, np.ndarray), type(xyz_compare) if nodes_xyz.shape[1] != xyz_compare.shape[1]: msg = 'nodes_xyz.shape=%s xyz_compare.shape=%s' % ( str(nodes_xyz.shape), str(xyz_compare.shape)) raise RuntimeError(msg) kdt = _get_tree(nodes_xyz) # check the closest 10 nodes for equality deq, ieq = kdt.query(xyz_compare, k=neq_max, distance_upper_bound=tol) #print(deq) #print('ieq =', ieq) #print('neq_max = %s' % neq_max) # get the ids of the duplicate nodes nnodes = nodes_xyz.shape[0] if neq_max == 1: assert len(deq.shape) == 1, deq.shape slots = where(ieq < nnodes) else: assert len(deq.shape) == 2, deq.shape slots = where(ieq[:, :] < nnodes) #print('slots =', slots) return kdt, ieq, slots
def pierce_shell_model(bdf_filename, xyz_points, tol=1.0): # type: (Union[BDF, str], Any, float) -> List[int], np.ndarray, List[List[int]] """ Pierces a shell model with a <0., 0., 1.> vector. In other words, models are pierced in the xy plane. Parameters ---------- bdf_filename : str / BDF() the model to run xyz_points : (npoints, 3) float ndarray the xyz_points to pierce tol : float; default=1.0 the pierce tolerance pick a value that is ~3x the max local element edge length Returns ------- eids_pierce : List[int] int : The element ids that were pierced. If multiple elements are pierced, the one with the largest pierced z value will be returned. None : invalid pierce xyz_pierces_max : List[float ndarray, None] ndarray : pierce location None : invalid pierce node_ids : List[int ndarray, None] ndarray : pierced element's nodes None : invalid pierce """ xyz_points = np.asarray(xyz_points) assert xyz_points.shape[1] == 3, xyz_points.shape xy_points = xyz_points[:, :2] assert xy_points.shape[1] == 2, xy_points.shape if isinstance(bdf_filename, BDF): model = bdf_filename else: model = read_bdf(bdf_filename) eids = [] centroids = [] etypes_to_skip = [ 'CHEXA', 'CPENTA', 'CTETRA', 'CPYRAM', 'CBUSH', 'CBUSH1D', 'CBUSH2D', 'CBEAM', 'CROD', 'CONROD', 'CELAS1', 'CELAS2', 'CELAS3', 'CELAS4', 'CDAMP1', 'CDAMP2', 'CDAMP3', 'CDAMP4', 'CDAMP5', ] for eid, elem in iteritems(model.elements): if elem.type in ['CQUAD4', 'CTRIA3']: centroid = elem.Centroid() elif elem.type in etypes_to_skip: continue else: print(elem.type) #raise NotImplementedError(elem) continue eids.append(eid) centroids.append(centroid) eids = np.array(eids, dtype='int32') assert len(eids) > 0, 'eids=%s\n' % eids centroids_xy = np.array(centroids, dtype='float64')[:, :2] #print('centroids:\n%s\n' % str(centroids_xy)) assert centroids_xy.shape[1] == 2, centroids_xy.shape msg = 'which is required by pierce_shell_model' kdt = _get_tree(centroids_xy, msg=msg) results = kdt.query_ball_point(xy_points, tol) nresults = len(results) iresults = np.arange(nresults) #print(results) #print(iresults) direction = np.array([0., 0., 1.]) ipoints = [] eids_pierce = [] xyz_pierces_max = [] node_ids = [] for i, xyz_point, eidsi in zip(count(), xyz_points, results): model.log.debug('eidsi = [%s]' % ', '.join([str(eidii).rstrip('L') for eidii in eidsi])) if not eidsi: ipoints.append(i) eids_pierce.append(None) xyz_pierces_max.append(None) node_ids.append(None) model.log.warning( 'skipping %s because it failed tolerancing (tol=%s)' % (xyz_point, tol)) continue model.log.debug('xyz_point = %s' % xyz_point) eidsi2 = eids[eidsi] eids_newi = [] piercesi = [] zpiercesi = [] for eid in eidsi2: elem = model.elements[eid] if elem.type == 'CQUAD4': v0 = elem.nodes_ref[0].get_position() v1 = elem.nodes_ref[1].get_position() v2 = elem.nodes_ref[2].get_position() v3 = elem.nodes_ref[3].get_position() xyz_pierce = quad_intersection(xyz_point, direction, v0, v1, v2, v3) elif elem.type == 'CTRIA3': v0 = elem.nodes_ref[0].get_position() v1 = elem.nodes_ref[1].get_position() v2 = elem.nodes_ref[2].get_position() xyz_pierce = triangle_intersection(xyz_point, direction, v0, v1, v2) else: raise NotImplementedError(elem) if xyz_pierce is None: #model.log.warning('failed to pierce eid=%s' % eid) continue zpierce = xyz_pierce[2] model.log.debug(' eid=%s xyz_pierce=%s zpierce=%s' % (eid, xyz_pierce, zpierce)) eids_newi.append(eid) piercesi.append(xyz_pierce) zpiercesi.append(zpierce) if len(zpiercesi) == 0: ipoints.append(i) eids_pierce.append(None) xyz_pierces_max.append(None) node_ids.append(None) model.log.warning('skipping %s because no pierces found (tol=%s)' % (xyz_point, tol)) continue #print('zpiercesi = %s' % zpiercesi) zpiercesi_max = max(zpiercesi) ipierce_max = zpiercesi.index(zpiercesi_max) eid_max = eids_newi[ipierce_max] xyz_piercei_max = piercesi[ipierce_max] model.log.debug( 'i=%s xyz_point=%s xyz_piercei_max=%s zpiercesi=%s zmax=%s eid_max=%s' % (i, xyz_point, xyz_piercei_max, zpiercesi, zpiercesi_max, eid_max)) ipoints.append(i) eids_pierce.append(eid_max) xyz_pierces_max.append(xyz_piercei_max) #print(model.elements[eid_max]) node_ids.append(model.elements[eid_max].node_ids) xyz_pierces_max = np.array(xyz_pierces_max) model.log.debug('ipoints=%s' % ipoints) model.log.info('eids_pierce=%s' % eids_pierce) model.log.info('xyz_pierces_max:\n%s' % xyz_pierces_max) model.log.info('node_ids=%s' % node_ids) return eids_pierce, xyz_pierces_max, node_ids