I try to find points on the surface of an ellipsoid that are also within a conical frustum.The ellipsoid and frustum are centred at ce and cf, respectively.The ellipsoid has semi-axes lengths defined in l.The frustum had a radius r1 at its base, an opening div, and a height h.To solve the issue at hand, I use python, together with numpy and scipy.More specifically, I use the fsolve function from scipy.optimize to minimise the difference between the ellipsoid and frustum equations.Based on that function, I have a Jacobian.My code is
import numpy as npfrom scipy.optimize import fsolveimport matplotlib.pyplot as pltfrom mpl_toolkits.mplot3d import Axes3Ddef get_ellispoid(c, l): X_ell = c[0] + l[0] * np.outer(np.sin(Phi), np.cos(Theta)) Y_ell = c[1] + l[1] * np.outer(np.sin(Phi), np.sin(Theta)) Z_ell = c[2] + l[2] * np.outer(np.cos(Phi), np.ones_like(Theta)) return X_ell, Y_ell, Z_elldef get_conical_frustum(cf, r1, div, h, npt_z): z = np.linspace(0, h, npt_z) Theta, Z = np.meshgrid(theta, z) R = r1 + Z * np.tan(div) X_fru = cf[0] + R * np.cos(Theta) Y_fru = cf[1] + R * np.sin(Theta) Z_fru = cf[2] + Z return X_fru, Y_fru, Z_frudef ellipsoid(theta, phi, ce, l): return np.array( [ce[0] + l[0] * np.cos(theta) * np.cos(phi), ce[1] + l[1] * np.sin(theta) * np.cos(phi), ce[2] + l[2] * np.sin(phi)] )def frustum(theta, z, cf, r1, div): return np.array( [cf[0] + (r1 + z * np.tan(div)) * np.cos(theta), cf[1] + (r1 + z * np.tan(div)) * np.sin(theta), cf[2] + z] )# Define the function for which we want to find the rootsdef func(x, theta, phi, z, ce, cf, l, r1, div): return ellipsoid(theta, phi, ce, l) - frustum(theta, z, cf, r1, div)# Define the Jacobian matrix of the functiondef jacobian(x, theta, phi, z, ce, cf, l, r1, div): return np.array( [ [-(l[0] * np.cos(phi) - r1 - z * np.tan(div)) * np.sin(theta), -l[0] * np.cos(theta) * np.sin(phi), -np.tan(div) * np.cos(theta)], [-(l[1] * np.cos(phi) - r1 - z * np.tan(div)) * np.cos(theta), -l[1] * np.cos(theta) * np.sin(phi), -np.tan(div) * np.sin(theta)], [0.0, l[2] * np.cos(phi), -1], ] )num_points = 20theta = np.linspace(0, 2*np.pi, num_points)phi = np.linspace(0, np.pi, num_points)Theta, Phi = np.meshgrid(theta, phi)# Ellipsoidce = [0.0, 0.0, 0.0]l = [1.5, 1.1, 0.45]# Conical frustumcf = [0.0, 0.0, -1.5]h = np.linalg.norm(np.array(cf) - np.array(ce))r1 = 0.15div = np.pi / 18# Initial guessz = np.linspace(-2.0, h, num_points)x0 = np.array([0.0, 0.0, ce[-1]])# Iterate over theta, phi, and z valuessol = []for it, t in enumerate(theta): for ip, p in enumerate(phi): for iz, z_val in enumerate(z): try: root = fsolve(func, x0, args=(t, p, z_val, ce, cf, l, r1, div), fprime=jacobian, xtol=1e-9) sol.append(root) except RuntimeError: continuesol = np.array(sol)# Create a 3D plotfig = plt.figure(figsize = (8, 6))ax = fig.add_subplot(111, projection = '3d')# Plot the volumesxell, yell, zell = get_ellispoid(ce, l)ax.plot_surface(xell, yell, zell, color = 'r', alpha = 0.005)xfru, yfru, zfru = get_conical_frustum(cf, r1, div, h)ax.plot_surface(xfru, yfru, zfru, color = 'b', alpha = 0.35)# Plot the intersectionsax.scatter(sol[:, 0], sol[:, 1], sol[:, 2], color = 'g')# Set labels and titleax.set_xlabel('X')ax.set_ylabel('Y')ax.set_zlabel('Z')# Show the plotplt.show()When the code is run, the only point to which the code converges is x0 (which is not a valid solution), repeated over and over again.The solutions should be all the points of the frustum lying on the ellipsoid surface.I do not get why my code does not behave as expected?Can someone help me find out?
P.S. : I also tried to change the initial guess x0 passed to fsolve from x0 to [t, p, z_val] (never know...), but still no good outcome solution