import numpy as np import datetime as datetime import matplotlib.pyplot as plt from matplotlib import cm, colors import plotly.graph_objects as go # ============================================================ # Parameters # ============================================================ N = 5 # quintic α = np.pi / 4 # projection angle U_MIN, U_MAX = -1.25, 1.25 V_MIN, V_MAX = 0.0, np.pi / 2 NU, NV = 100, 100 # mesh resolution # ============================================================ # Core geometry # ============================================================ def make_parameter_grid(umin=U_MIN, umax=U_MAX, vmin=V_MIN, vmax=V_MAX, nu=NU, nv=NV): """ Construct a rectangular parameter grid in the complex z-plane. The parameters u and v define z = u + i v. The resulting arrays U, V have shape (nv, nu), with u varying horizontally and v vertically. """ u = np.linspace(umin, umax, nu) v = np.linspace(vmin, vmax, nv) # U[j, i] is the u-coordinate and V[j, i] is the v-coordinate. U, V = np.meshgrid(u, v, indexing='xy') return U, V def calabi_yau_sheet(U, V, k1, k2, n=N, alpha=α): """ Compute one sheet of the projected Riemann surface slice inside the given Calabi-Yau manifold. The output is a real 3d projection. 1. Our Calabi-Yau manifold is X : Z_0^N + Z_1^N + Z_2^N + Z_3^N + Z_4^N = 0 inside ℙ^4 . Here, [Z_0 : Z_1 : Z_2 : Z_3 : Z_4] are the homogeneous coordinates on ℙ^4. 2. Consider the open subset X_0 ⊂ X given by Z_0 ≠ 0, hence: X_0 : 1 + (Z_1/Z_0)^N + (Z_2/Z_0)^N + (Z_3/Z_0)^N + (Z_4/Z_0)^N = 0 . 3. Study the complex surface X_1 ⊂ X_0 determined by (Z_3/Z_0) = (Z_4/Z_0) = (-1)^{1/N}. Let z_1 := Z_1/Z_0 and z_2 := Z_2/Z_0, so that X_1 ⊂ X_0 ⊂ X is given in ℂ^2 by X_1 : z_1^N + z_2^N = 1 . 4. Consider an array of Riemann surfaces inside X_1: X_2 (k_1,k_2) ⊂ X_1 ⊂ X_0 ⊂ X ∀ 0 ≤ k_1, k_2 ≤ N-1 . Each X_2 (k_1,k_2) is parameterised by z = U + iV and given by X_2 (k_1, k_2) : z_1 = e^{2πi k_1 / n} cosh(z)^{2/n} z_2 = e^{2πi k_2 / n} sinh(z)^{2/n} Thus, the integers k_1 and k_2 select choices of nth-root branches for the two complex coordinates z_1 and z_2. 5. Finally, we project from ℂ^2 = ℝ^4 to ℝ^3 as follows X = Re(z_1), Y = Re(z_2), Z = cos(α) Im(z_1) + sin(α) Im(z_2). """ z = U + 1j * V z1 = np.exp(2j * np.pi * k1 / n) * np.power(np.cosh(z), 2.0 / n) z2 = np.exp(2j * np.pi * k2 / n) * np.power(np.sinh(z), 2.0 / n) X = np.real(z1) Y = np.real(z2) Z = np.cos(alpha) * np.imag(z1) + np.sin(alpha) * np.imag(z2) return X, Y, Z def generate_all_sheets(n=N, alpha=α, umin=U_MIN, umax=U_MAX, vmin=V_MIN, vmax=V_MAX, nu=NU, nv=NV): """ Generate all n^2 sheets of the projected surface. Each sheet corresponds to a pair of branch choices (k_1, k_2). Returns a list of dictionaries, one dictionary per sheet. """ U, V = make_parameter_grid(umin, umax, vmin, vmax, nu, nv) sheets = [] # Loop over all branch choices for z_1 and z_2. for k1 in range(n): for k2 in range(n): X, Y, Z = calabi_yau_sheet(U, V, k1, k2, n=n, alpha=alpha) sheets.append({ 'k1': k1, 'k2': k2, 'X': X, 'Y': Y, 'Z': Z }) return sheets def structured_triangles(nu=NU, nv=NV): """ Construct a triangle mesh for a structured nu by nv parameter grid. Each rectangular grid cell is split into two triangles. The vertex ordering is compatible with row-major flattening of arrays of shape (nv, nu); e.g. X.ravel(), Y.ravel(), Z.ravel(). """ faces = [] # j indexes rows in the v-direction; i indexes columns in the u-direction. for j in range(nv - 1): for i in range(nu - 1): a = j * nu + i b = a + 1 c = a + nu d = c + 1 # Split the quadrilateral (a, b, d, c) into two triangles. faces.append([a, b, d]) faces.append([a, d, c]) return np.array(faces, dtype=np.int32) def all_vertices_from_sheets(sheets): """ Collect all vertices from all sheets into a single array. Returns an array of shape (total_vertices, 3), where each row is an (X, Y, Z) point. """ pts = [] for s in sheets: # Stack flattened X, Y, Z arrays columnwise into 3D vertex coordinates. pts.append(np.c_[s['X'].ravel(), s['Y'].ravel(), s['Z'].ravel()]) return np.vstack(pts) def bounding_box_from_sheets(sheets): """ Compute the global axis-aligned bounding box of all sheets. Returns: mins: array [xmin, ymin, zmin] maxs: array [xmax, ymax, zmax] """ pts = all_vertices_from_sheets(sheets) mins = pts.min(axis=0) maxs = pts.max(axis=0) return mins, maxs # ============================================================ # Plotting setup # ============================================================ def set_axes_equal_3d(ax, mins, maxs): """ Force a 3d matplotlib axis to use equal scale in all directions. This prevents the surface from appearing artificially stretched. """ # Centre of the global bounding box. center = 0.5 * (mins + maxs) # Use the largest side length to define a cubic plotting box. radius = 0.5 * np.max(maxs - mins) # Set identical plotting ranges in x, y, and z. ax.set_xlim(center[0] - radius, center[0] + radius) ax.set_ylim(center[1] - radius, center[1] + radius) ax.set_zlim(center[2] - radius, center[2] + radius) # Ask matplotlib to render the 3d box with equal visual proportions. ax.set_box_aspect([1, 1, 1]) def plot_matplotlib(sheets, elev=24, azim=35, figsize=(10, 10), dpi=300): """ Plot all sheets using matplotlib's 3d surface plotting. Returns a static rendered view of the projected surface. """ fig = plt.figure(figsize=figsize, dpi=dpi) ax = fig.add_subplot(111, projection='3d') # Use a continuous colormap to assign a different colour to each sheet. cmap = cm.jet n_sheets = len(sheets) for idx, s in enumerate(sheets): # Pick a colour according to the sheet index. colour = cmap(idx / max(1, n_sheets - 1)) # Plot one parametrised sheet as a semi-transparent surface. ax.plot_surface( s['X'], s['Y'], s['Z'], # Surface coordinates as 2d arrays rstride=1, # Use every row of the grid cstride=1, # Use every column of the grid linewidth=0.001, # Very thin mesh-edge lines edgecolor=(0, 0, 0, 0.15), # Semi-transparent black mesh edges color=colour, # Solid face colour for this sheet alpha=0.58, # Surface transparency antialiased=True, # Smooth jagged edges visually shade=True # Apply lighting/shading for 3d depth ) # Compute a global bounding box and use it to enforce equal 3d scaling. mins, maxs = bounding_box_from_sheets(sheets) set_axes_equal_3d(ax, mins, maxs) # Set the viewing angle. ax.view_init(elev=elev, azim=azim) # Remove axes, ticks, and frame for a cleaner visual. ax.set_axis_off() # Save plot as pdf image locally. plt.savefig("CY.pdf", format='pdf') # Display the plot with tight layout. plt.tight_layout() plt.show() def plot_plotly(sheets, nu=NU, nv=NV): """ Plot all sheets as an interactive plotly mesh3d figure. Each sheet is converted from structured grid data into a triangle mesh. Returns an HTML file with an interactive plot. """ # Triangulation shared by every sheet, since each sheet uses the same grid. faces = structured_triangles(nu, nv) fig = go.Figure() # Use the same colormap idea as in the matplotlib version. cmap = cm.jet n_sheets = len(sheets) for idx, s in enumerate(sheets): # Flatten the sheet arrays into a list of 3d vertices. verts = np.c_[s['X'].ravel(), s['Y'].ravel(), s['Z'].ravel()] # Convert the matplotlib RGBA colour to a plotly-compatible hex string. colour = colors.to_hex(cmap(idx / max(1, n_sheets - 1))) # Add one triangular mesh for this sheet. fig.add_trace(go.Mesh3d( x=verts[:, 0], y=verts[:, 1], z=verts[:, 2], # Triangle vertex indices. i=faces[:, 0], j=faces[:, 1], k=faces[:, 2], color=colour, opacity=0.58, flatshading=False, # Lighting parameters controlling the rendered 3d appearance. lighting=dict( ambient=0.35, # Base light level; higher values make shadows less dark diffuse=0.75, # Matte surface lighting; higher values emphasise 3D shape specular=0.30, # Shiny highlight strength; higher values make surfaces glossier roughness=0.45, # Surface roughness; higher values spread/soften highlights fresnel=0.10 # Edge glow effect; higher values brighten grazing-angle edges ), # Position of the virtual light source. lightposition=dict(x=60, y=40, z=80), # Disable hover labels to keep the interaction visually clean. hoverinfo='skip', # No scalar colourbar is needed because sheets are coloured manually. showscale=False, # Name the sheet by its branch indices. name=f"({s['k1']},{s['k2']})" )) fig.update_layout( width=950, height=900, showlegend=False, scene=dict( # Hide coordinate axes for a clean geometric rendering. xaxis=dict(visible=False), yaxis=dict(visible=False), zaxis=dict(visible=False), # Preserve the actual geometric aspect ratio of the data. aspectmode='data', # Initial camera position. camera=dict( eye=dict(x=1.6, y=1.4, z=1.0) ), bgcolor='white' ), # Remove exterior whitespace around the plot. margin=dict(l=0, r=0, b=0, t=0) ) # Save an interactive standalone HTML version. fig.write_html("CY.html") # Display the interactive figure in the current notebook/session. fig.show() # ============================================================ # Execute matplot # ============================================================ sheets = generate_all_sheets() plot_matplotlib(sheets) # ============================================================ # Execute plotly # ============================================================ plot_plotly(sheets)