修改n、m参数为何不影响六边形晶格转圆柱的3D坐标?
问题描述
我写了一段Python代码,用来把六边形连接晶格的2D坐标转换为3D圆柱坐标,但修改n、m变量后,输出的3D坐标完全没变化。参考手性向量定义(手性向量为Chiral Vector = n·a₁ + m·a₂,其中a₁沿x轴),怎么让n、m影响手性向量、theta角,进而改变最终圆柱的形状?
原代码
import numpy as np import matplotlib.pyplot as plt import mpl_toolkits.mplot3d.axes3d as axes3d import matplotlib.colors with open("test_A_aux.dat", "r") as aux: dim = np.genfromtxt(aux, skip_header =3, max_rows = 1) n = int(input("Enter the value for n: ")) m = int(input("Enter the value for m: ")) # Open coordinate file and import data to array with open("test_A_crds.dat", "r") as crds: array = np.genfromtxt(crds) # Defines the chiral angle based on a1 and a2 vectors # This is then used to manipulate x,y coords onto the vector def chiral_angle(n, m): # a1 vector is set along x axis a1 = np.array([np.sqrt(3),0]) a2 = np.array([np.sqrt(3)/2, 3/2]) # chiral vector is the dot product of n * a1 and m * a2 chiral_vector = np.add(np.multiply(a1, n), np.multiply(a2, m)) # magnitude of chiral vector mag = np.linalg.norm(chiral_vector) # dot product formula to find cos theta cos_theta = np.dot(chiral_vector, np.array([1,0])) / mag theta = np.arccos(cos_theta) return theta # This function wraps the 2d coordinates into a cylinder by maniuplating # the y cooridnates and generating z coordinates # x coordinates unchaged def wrap(n, m): # normalises to max length of the dimensions of the input cell normalise = matplotlib.colors.Normalize(0, dim[1]) X = array[:,0] THETA = np.array([2*np.pi * normalise(i) for i in array[:,1]]) r = dim[1] / (2 * np.pi) Y = np.array([r * np.sin(angle) for angle in THETA]) Z = np.array([r * np.cos(angle) for angle in THETA]) # stacks X and Y into n*2 array tube = np.vstack((X, Y)) # stacks above n*2 array with Z to make n*3 array tube = np.vstack((tube, Z)) # transposes array to make 3*n array of 3D coordinates tube = np.transpose(tube) return tube # Plotting function def plot_tube(): fig = plt.figure() ax = fig.add_subplot(1,1,1, projection='3d') plot = ax.scatter(tube[:,0], tube[:,1], tube[:,2]) plt.show() return # creates file and writes it to vmd for visualisation # with open("nanotube.xyz", "w") as vmd: # vmd.write("{:}\n\n ".format(array.shape[0])) # for i in range(array.shape[0]): # vmd.write("{:} {:<10} {:<10} {:<10}\n".format(i, tube[i,0], tube[i,1], tube[i,2])) tube = wrap(n, m) print(tube) plot_tube()
问题根源与修复方案
核心问题是你写的chiral_angle函数计算出的theta角完全没被wrap函数调用,n、m的改动根本没参与到坐标变换里,所以输出结果不会变。要让n、m影响圆柱形状,得把手性角、手性向量的参数融入整个坐标变换流程,同时遵循碳纳米管的卷绕逻辑。
以下是修复后的完整代码,关键改动会标注:
import numpy as np import matplotlib.pyplot as plt import mpl_toolkits.mplot3d.axes3d as axes3d import matplotlib.colors with open("test_A_aux.dat", "r") as aux: dim = np.genfromtxt(aux, skip_header=3, max_rows=1) n = int(input("Enter the value for n: ")) m = int(input("Enter the value for m: ")) # 读取2D坐标数据 with open("test_A_crds.dat", "r") as crds: array = np.genfromtxt(crds) # 计算手性参数:手性角theta、纳米管半径r、手性向量 def chiral_params(n, m): a1 = np.array([np.sqrt(3), 0]) # a1沿x轴 a2 = np.array([np.sqrt(3)/2, 3/2]) chiral_vector = n * a1 + m * a2 mag_chiral = np.linalg.norm(chiral_vector) # 计算手性角(与x轴的夹角) theta = np.arccos(np.dot(chiral_vector, [1, 0]) / mag_chiral) # 纳米管半径公式:手性向量长度/(2π) r = mag_chiral / (2 * np.pi) return theta, r, chiral_vector # 核心修改:让n、m参与坐标变换的全流程 def wrap(n, m): theta, r, chiral_vec = chiral_params(n, m) # 第一步:旋转2D坐标,让手性向量对齐到x轴(卷绕前的对齐操作) rotation_mat = np.array([[np.cos(-theta), -np.sin(-theta)], [np.sin(-theta), np.cos(-theta)]]) rotated_coords = array @ rotation_mat.T # 第二步:将旋转后的y坐标归一化,生成圆柱的周向角度 normalise = matplotlib.colors.Normalize(0, dim[1]) THETA = 2 * np.pi * normalise(rotated_coords[:, 1]) # 第三步:生成圆柱的3D坐标 X = rotated_coords[:, 0] # 旋转后的x作为圆柱的轴向 Y = r * np.sin(THETA) Z = r * np.cos(THETA) # 第四步:将坐标旋转回原手性角的方向,还原手性 final_rotation = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) # 处理Y-Z平面的旋转,再与X轴坐标合并 yz_coords = np.vstack((Y, Z)).T @ final_rotation.T tube = np.hstack((X.reshape(-1, 1), yz_coords)) return tube # 绘图函数 def plot_tube(): fig = plt.figure() ax = fig.add_subplot(1, 1, 1, projection='3d') ax.scatter(tube[:, 0], tube[:, 1], tube[:, 2]) plt.show() # 执行流程 tube = wrap(n, m) print(tube) plot_tube()
关键改动说明
- 激活手性参数的作用:新增
chiral_params函数计算的theta、r、手性向量,直接传入wrap函数参与变换,让n、m的改动真正影响结果 - 坐标旋转对齐:卷绕前先把2D坐标旋转到手性向量对齐x轴的状态,卷绕完成后再旋转回原角度,符合碳纳米管的实际卷绕逻辑
- 动态半径计算:圆柱半径由手性向量长度决定,不同n、m组合会生成不同半径的纳米管
- 完整的变换链路:n、m从手性向量计算,到手性角,再到坐标旋转、圆柱生成,全程参与,修改n、m后3D坐标会明显变化
这样修改后,调整n和m的值就能得到不同手性、不同尺寸的圆柱结构了。
内容的提问来源于stack exchange,提问作者van10
相关产品推荐
相关产品推荐

