You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 14:25:54