Source code for pyNastran.bdf.mesh_utils.find_closest_nodes

"""
defines:
    * nids_close = find_closest_nodes(nodes_xyz, nids, xyz_compare, neq_max, tol)
    * ieq = find_closest_nodes_index(nodes_xyz, xyz_compare, neq_max, tol)

"""
from itertools import count
from typing import Optional, Any
import numpy as np

from pyNastran.bdf.mesh_utils.bdf_equivalence import _get_tree

from pyNastran.nptyping_interface import NDArray3float, NDArrayNint

[docs] def find_closest_nodes(nodes_xyz: NDArray3float, nids: NDArrayNint, xyz_compare: NDArray3float, neq_max: int=1, tol: Optional[float]=None, msg: str='') -> NDArrayNint: """ Finds the closest nodes to an arbitrary set of xyz points Parameters ---------- nodes_xyz : (Nnodes, 3) float ndarray the source points (e.g., xyz_cid0) nids : (Nnodes, ) int ndarray the source node ids (e.g.; nid_cp_cid[:, 0]) xyz_compare : (Ncompare, 3) float ndarray the xyz points to compare to; xyz_to_find tol : float; default=None the max spherical tolerance None : the whole model neq_max : int; default=1 the number of "close" points msg : str; default='' custom message used for errors Returns ------- nids_close: (Ncompare, ) int ndarray the close node ids """ if not isinstance(neq_max, int): msgi = 'neq_max=%r must be an int; type=%s\n%s' % ( neq_max, type(neq_max), msg) raise TypeError(msgi) #ieq = find_closest_nodes_index(nodes_xyz, xyz_compare, neq_max, tol) if tol is None: xyz_max = nodes_xyz.max(axis=0) xyz_min = nodes_xyz.min(axis=0) assert len(xyz_max) == 3, xyz_max dxyz = np.linalg.norm(xyz_max - xyz_min) tol = 2. * dxyz ieq = _not_equal_nodes_build_tree(nodes_xyz, xyz_compare, tol, neq_max=neq_max, msg=msg)[1] ncompare = xyz_compare.shape[0] assert len(ieq) == ncompare, 'increase the tolerance so you can find nodes; tol=%r' % tol try: nids_out = nids[ieq] except IndexError: # if you get a crash while trying to create the error message # check to see if your nodes are really far from each other # nnids = len(nids) msgi = 'Cannot find:\n' for i, ieqi, nid in zip(count(), ieq, nids): if ieqi == nnids: xyz = xyz_compare[i, :] msgi += ' nid=%s xyz=%s\n' % (nid, xyz) msgi += msg raise IndexError(msgi) return nids_out
[docs] def find_closest_nodes_index(nodes_xyz: NDArray3float, xyz_compare: NDArray3float, neq_max: int, tol: float, msg: str=''): """ Finds the closest nodes to an arbitrary set of xyz points Parameters ---------- nodes_xyz : (Nnodes, 3) float ndarray the source points xyz_compare : (Ncompare, 3) float ndarray the xyz points to compare to neq_max : int the number of "close" points (default=4) tol : float the max spherical tolerance msg : str; default='' error message Returns ------- slots : (Ncompare, ) int ndarray the indices of the close nodes corresponding to nodes_xyz """ #nodes_xyz, model, nids, inew = _eq_nodes_setup( #bdf_filename, renumber_nodes=renumber_nodes, #xref=xref, node_set=node_set, debug=debug) ieq, slots = _not_equal_nodes_build_tree(nodes_xyz, xyz_compare, tol, neq_max=neq_max, msg=msg)[1:3] return ieq
[docs] def _not_equal_nodes_build_tree(nodes_xyz: NDArray3float, xyz_compare: NDArray3float, tol: float, neq_max: int=4, msg: str='') -> tuple[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 : 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 msg : str; default='' error message """ assert isinstance(nodes_xyz, np.ndarray), type(nodes_xyz) assert isinstance(xyz_compare, np.ndarray), type(xyz_compare) if len(nodes_xyz.shape) != len(xyz_compare.shape) or 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