def METHOD_NAME(self, fname):
    from yt.utilities.lib.cykdtree import PyKDTree
    if fname is not None:
        if os.path.exists(fname):
            mylog.info("Loading KDTree from %s", os.path.basename(fname))
            kdtree = PyKDTree.from_file(fname)
            if kdtree.data_version != self.ds._file_hash:
                mylog.info("Detected hash mismatch, regenerating KDTree")
            else:
                self._kdtree = kdtree
                return
    positions = []
    for data_file in self.data_files:
        for _, ppos in self.io._yield_coordinates(
            data_file, needed_ptype=self.ds._sph_ptypes[0]
        ):
            positions.append(ppos)
    if positions == []:
        self._kdtree = None
        return
    positions = np.concatenate(positions)
    mylog.info("Allocating KDTree for %s particles", positions.shape[0])
    num_neighbors = getattr(self.ds, "num_neighbors", 32)
    self._kdtree = PyKDTree(
        positions.astype("float64"),
        left_edge=self.ds.domain_left_edge,
        right_edge=self.ds.domain_right_edge,
        periodic=np.array(self.ds.periodicity),
        leafsize=2 * int(num_neighbors),
        data_version=self.ds._file_hash,
    )
    if fname is not None:
        self._kdtree.save(fname)