123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- """Expand and reconstruct any surface
- (here a simple box) into spherical harmonics"""
- # Expand an arbitrary closed shape into spherical harmonics
- # using SHTOOLS (https://shtools.github.io/SHTOOLS)
- # and then truncate the expansion to a specific lmax and
- # reconstruct the projected points on a finer grid.
- import pyshtools
- import numpy as np
- from scipy.interpolate import griddata
- from vedo import spher2cart, mag, Box, Point, Points, Plotter
- ###########################################################################
- lmax = 8 # maximum degree of the spherical harm. expansion
- N = 50 # number of grid intervals on the unit sphere
- rmax = 500 # line length
- x0 = [250, 250, 250] # set SPH sphere at this position
- ###########################################################################
- x0 = np.array(x0)
- surface = Box(pos=x0+[10,20,30], size=(300,150,100))
- surface.color('grey').alpha(0.2)
- ############################################################
- # cast rays from the sphere center and find intersections
- agrid, pts = [], []
- for th in np.linspace(0, np.pi, N, endpoint=True):
- longs = []
- for ph in np.linspace(0, 2*np.pi, N, endpoint=False):
- p = spher2cart(rmax, th, ph)
- intersections = surface.intersect_with_line(x0, x0+p)
- if len(intersections):
- value = mag(intersections[0]-x0)
- longs.append(value)
- pts.append(intersections[0])
- else:
- print('No hit for theta, phi =', th, ph, c='r')
- longs.append(rmax)
- pts.append(p)
- agrid.append(longs)
- agrid = np.array(agrid)
- hits = Points(pts)
- hits.cmap('jet', agrid.ravel()).add_scalarbar3d('scalar distance to x_0')
- hits.scalarbar = hits.scalarbar.clone2d(size=0.12)
- #############################################################
- grid = pyshtools.SHGrid.from_array(agrid)
- clm = grid.expand()
- grid_reco = clm.expand(lmax=lmax).to_array() # cut "high frequency" components
- #############################################################
- # interpolate to a finer grid
- ll = []
- for i, long in enumerate(np.linspace(0, 360, num=grid_reco.shape[1], endpoint=False)):
- for j, lat in enumerate(np.linspace(90, -90, num=grid_reco.shape[0], endpoint=True)):
- th = np.deg2rad(90 - lat)
- ph = np.deg2rad(long)
- p = spher2cart(grid_reco[j][i], th, ph)
- ll.append((lat, long))
- radii = grid_reco.T.ravel()
- n = 200j
- lnmin, lnmax = np.array(ll).min(axis=0), np.array(ll).max(axis=0)
- grid = np.mgrid[lnmax[0]:lnmin[0]:n, lnmin[1]:lnmax[1]:n]
- grid_x, grid_y = grid
- grid_reco_finer = griddata(ll, radii, (grid_x, grid_y), method='cubic')
- pts2 = []
- for i, long in enumerate(np.linspace(0, 360, num=grid_reco_finer.shape[1], endpoint=False)):
- for j, lat in enumerate(np.linspace(90, -90, num=grid_reco_finer.shape[0], endpoint=True)):
- th = np.deg2rad(90 - lat)
- ph = np.deg2rad(long)
- p = spher2cart(grid_reco_finer[j][i], th, ph)
- pts2.append(p+x0)
- plt = Plotter(N=2, axes=1)
- plt.at(0).show(surface, hits, Point(x0), __doc__)
- plt.at(1).show(
- f'Spherical harmonics expansion of order {lmax}',
- Points(pts2).c("red5").alpha(0.5),
- surface,
- )
- plt.interactive().close()
|