docstr: sph_from_ray, CUDA implementation
  get spherical coordinate on the background sphere from rays.
  Assume rays_o are inside the Sphere(radius).
  Args:
      rays_o: [N, 3]
      rays_d: [N, 3]
      radius: scalar, float
  Return:
      coords: [N, 2], in [-1, 1], theta and phi on a sphere. (further-surface)
docstr_tok: ["sph_from_ray",",","CUDA","implementation","get","spherical","coordinate","on","the","background","sphere","from","rays",".","Assume","rays_o","are","inside","the","Sphere","(","radius",")",".","Args",":","rays_o",":","[","N",",","3","]","rays_d",":","[","N",",","3","]","radius",":","scalar",",","float","Return",":","coords",":","[","N",",","2","]",",","in","[","-1",",","1","]",",","theta","and","phi","on","a","sphere",".","(","further-surface",")"]
code: def forward(ctx, rays_o, rays_d, radius):
      """sph_from_ray, CUDA implementation
      get spherical coordinate on the background sphere from rays.
      Assume rays_o are inside the Sphere(radius).
      Args:
          rays_o: [N, 3]
          rays_d: [N, 3]
          radius: scalar, float
      Return:
          coords: [N, 2], in [-1, 1], theta and phi on a sphere. (further-surface)
      """
      if not rays_o.is_cuda:
          rays_o = rays_o.cuda()
      if not rays_d.is_cuda:
          rays_d = rays_d.cuda()
  
      rays_o = rays_o.contiguous().view(-1, 3)
      rays_d = rays_d.contiguous().view(-1, 3)
  
      N = rays_o.shape[0]  # num rays
  
      coords = torch.empty(
          N, 2, dtype=rays_o.dtype, device=rays_o.device
      )
  
      get_backend().sph_from_ray(rays_o, rays_d, radius, N, coords)
  
      return coords
  
imports: import torch
  from torch.autograd import Function
  from torch.cuda.amp import custom_bwd, custom_fwd
label_desc: Use image node_id 1 for calling the _sph_from_ray obj's underlying member method code with example usage: obj.forward(ctx, rays_o, rays_d, radius) and returns: coords