code: def get_reflection_angles(normal, v):
      angles = (normal * (v / norm(v))).sum(axis=1)
      # mask_forward1 = angles < 0
  
      # additionally, the reverse should work:
      vnew = -(
          v.reshape((1, -1)) - 2 * angles.reshape((-1, 1)) * normal
      )
      anglesnew = (
          normal * (vnew / norm(vnew, axis=1).reshape((-1, 1)))
      ).sum(axis=1)
      assert anglesnew.shape == (len(normal),), (
          anglesnew.shape,
          normal.shape,
      )
      mask_forward = np.logical_and(angles < 0, anglesnew < 0)
      return mask_forward, angles, anglesnew
  
file_path: ultranest/tests/test_samplingpath.py
imports: import numpy
  import matplotlib.pyplot
  from ultranest.mlfriends import AffineLayer, MLFriends
  from ultranest.samplingpath import SamplingPath, ContourSamplingPath
  from ultranest.samplingpath import box_line_intersection, nearest_box_intersection_line, linear_steps_with_reflection, angle, get_sphere_tangents, norm
  from numpy.testing import assert_allclose
label_desc: Use image node_id 9 for calling a global function with example usage: get_reflection_angles(normal, v) and returns: mask_forward,  angles,  anglesnew