While this is a very old query, here is an answer in python 3, using SciPy.
If you are using a version of SciPy prior to v1.6.0, then use a cKDTree.
One can subdivide each triangle into nine sub-triangles repeatedly for finer location without having to worry about changing the lookup methodology.
import numpy as np
import scipy as sp
import scipy.spatial
import math
def xyz_ll(p: tuple) -> tuple:
x, y, z = p
return math.degrees(math.atan2(z, math.sqrt(x * x + y * y))), math.degrees(math.atan2(y, x))
if __name__ == '__main__':
# This is a rendering (in unit sphere coordinates)
# of the centres of the 20 faces of a dymaxion icosahedron.
# suitable for equilateral triangles!
cx = np.array([
(0.17476898, 0.5231760133333333, 0.5720300666666667),
(-0.08387563000000002, 0.77832093, 0.13659113999999997),
(-0.5903144233333334, 0.28559418333333336, -0.44882131666666664),
(-0.5884910200000001, 0.5302967366666667, 0.0627648033333333),
(0.6446662, 0.27407261, 0.37518718666666667),
(0.5903144233333334, -0.28559418333333336, 0.44882131666666664),
(-0.16999525000000001, 0.11746359000000002, 0.7673197833333334),
(0.08682595666666666, -0.38238388000000006, 0.69117259),
(0.5884910200000001, -0.5302967366666667, -0.0627648033333333),
(-0.22617043, -0.6869057566666666, 0.3293677933333333),
(0.08387563000000002, -0.77832093, -0.13659113999999997),
(-0.17476898, -0.5231760133333333, -0.5720300666666667),
(0.22617043, 0.6869057566666666, -0.3293677933333333),
(-0.08682595666666666, 0.38238387999999995, -0.69117259),
(0.6764340433333333, 0.3752631566666666, -0.18190732666666665),
(0.6417158733333334, -0.12186444, -0.4525765433333333),
(0.16999525000000001, -0.11746359, -0.7673197833333333),
(-0.6417158733333334, 0.12186444, 0.4525765433333333),
(-0.6764340433333333, -0.3752631566666666, 0.18190732666666665),
(-0.6446662, -0.27407261, -0.37518718666666667)
])
tree = sp.spatial.KDTree(cx) # this was improved in SciPy 1.6
# make 100 random unit vectors suitable for a sphere and normalise.
n = 100
v = np.random.normal(size=(n, 3))
vn = [0, 0, 1] + v / np.linalg.norm(v, axis=1, keepdims=True)
for pt in vn:
dx, k = tree.query(pt, workers=-1, k=1)
print(pt, tree.data[k], xyz_ll(tree.data[k]), dx)