第八十八篇:纳米技术与分子工程

摘要

纳米技术与分子工程是现代科学与工程的前沿交叉领域,涉及从原子尺度到宏观尺度的多尺度建模与仿真。本教程系统介绍纳米技术的仿真方法,包括分子动力学模拟、密度泛函理论、连续介质模型以及多尺度耦合方法。通过六个典型案例——碳纳米管力学性能仿真、纳米颗粒自组装模拟、分子机器运动仿真、石墨烯电子性质计算、纳米流体传热仿真和DNA分子动力学模拟,展示纳米尺度下的物理化学现象和工程应用。本教程将帮助读者掌握纳米尺度仿真的核心方法,理解从分子到宏观的跨尺度传递机制,为纳米材料设计和分子工程应用奠定基础。

关键词

纳米技术, 分子动力学, 密度泛函理论, 自组装, 分子机器, 多尺度建模, 纳米材料, 分子工程


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1. 纳米技术基础理论

1.1 纳米尺度特征

纳米技术研究的尺度范围通常在1-100纳米之间,这一尺度具有独特的物理化学性质:

表面效应:纳米材料的比表面积显著增大,表面原子比例急剧上升。对于球形纳米颗粒,表面原子比例可近似表示为:

fsurface=4πr2⋅d43πr3⋅ρ=3drρf_{surface} = \frac{4\pi r^2 \cdot d}{\frac{4}{3}\pi r^3 \cdot \rho} = \frac{3d}{r\rho}fsurface=34πr3ρ4πr2d=rρ3d

其中ddd为原子直径,rrr为颗粒半径,ρ\rhoρ为原子数密度。当颗粒尺寸减小到10纳米以下时,表面原子可占总原子数的50%以上。

量子尺寸效应:当材料尺寸减小到与电子德布罗意波长或激子玻尔半径相当时,电子能级由连续变为离散,导致光学、电学和磁学性质发生显著变化。量子限域效应可用粒子在势阱中的能级公式描述:

En=n2h28m∗L2E_n = \frac{n^2 h^2}{8m^* L^2}En=8mL2n2h2

其中nnn为量子数,hhh为普朗克常数,m∗m^*m为有效质量,LLL为限域尺寸。

宏观量子隧道效应:微观粒子具有贯穿势垒的能力,在纳米尺度下这一效应更加显著,影响电子输运和磁化反转等过程。

1.2 纳米材料分类

纳米材料按维度可分为四类:

零维纳米材料:量子点、纳米颗粒、富勒烯。在所有三个维度上都处于纳米尺度,具有离散的电子态。

一维纳米材料:纳米线、纳米管、纳米棒。在两个维度上受限,电子在一个方向上自由运动,表现出独特的量子输运性质。

二维纳米材料:石墨烯、纳米薄膜、二维材料。在一个维度上受限,电子在平面内自由运动,具有优异的电子和力学性能。

三维纳米材料:纳米多孔材料、纳米复合材料。由纳米结构单元组装而成的宏观材料,兼具纳米效应和宏观可加工性。

1.3 分子工程原理

分子工程是通过设计和操控分子结构来实现特定功能的科学。核心原理包括:

自下而上组装:从原子、分子出发,通过化学合成或自组装构建复杂结构。这种方法可以精确控制材料的组成和结构。

分子识别与自组装:利用分子间的非共价相互作用(氢键、范德华力、静电作用、疏水作用)实现分子的选择性识别和有序组装。

分子机器:能够在外界刺激下执行机械运动的分子器件,包括分子马达、分子开关、分子电梯等。2016年诺贝尔化学奖授予了分子机器的设计与合成研究。


2. 分子动力学模拟方法

2.1 基本原理

分子动力学(Molecular Dynamics, MD)模拟通过数值求解牛顿运动方程来追踪系统中所有原子的运动轨迹。对于第iii个原子,运动方程为:

mid2ridt2=Fi=−∇iU(r1,r2,...,rN)m_i \frac{d^2 \mathbf{r}_i}{dt^2} = \mathbf{F}_i = -\nabla_i U(\mathbf{r}_1, \mathbf{r}_2, ..., \mathbf{r}_N)midt2d2ri=Fi=iU(r1,r2,...,rN)

其中mim_imi为原子质量,ri\mathbf{r}_iri为位置矢量,Fi\mathbf{F}_iFi为作用力,UUU为系统势能函数。

2.2 势能函数

势能函数(力场)是分子动力学模拟的核心,决定了计算的精度和效率。常用的势能函数包括:

Lennard-Jones势:描述中性原子或分子间的范德华相互作用:

ULJ(r)=4ε[(σr)12−(σr)6]U_{LJ}(r) = 4\varepsilon \left[\left(\frac{\sigma}{r}\right)^{12} - \left(\frac{\sigma}{r}\right)^6\right]ULJ(r)=4ε[(rσ)12(rσ)6]

其中ε\varepsilonε为势阱深度,σ\sigmaσ为原子直径。r−12r^{-12}r12项描述短程排斥,r−6r^{-6}r6项描述长程吸引。

键合势:描述化学键的伸缩、弯曲和扭转:

Ubond=12kb(r−r0)2U_{bond} = \frac{1}{2}k_b(r - r_0)^2Ubond=21kb(rr0)2

Uangle=12kθ(θ−θ0)2U_{angle} = \frac{1}{2}k_\theta(\theta - \theta_0)^2Uangle=21kθ(θθ0)2

Utorsion=∑n=13Vn[1+cos⁡(nϕ−ϕn)]U_{torsion} = \sum_{n=1}^{3} V_n[1 + \cos(n\phi - \phi_n)]Utorsion=n=13Vn[1+cos(nϕϕn)]

反应力场(ReaxFF):能够描述化学键的断裂和形成,适用于化学反应模拟。

2.3 积分算法

常用的数值积分算法包括:

Verlet算法

r(t+Δt)=2r(t)−r(t−Δt)+F(t)mΔt2\mathbf{r}(t + \Delta t) = 2\mathbf{r}(t) - \mathbf{r}(t - \Delta t) + \frac{\mathbf{F}(t)}{m}\Delta t^2r(t+Δt)=2r(t)r(tΔt)+mF(t)Δt2

速度Verlet算法

r(t+Δt)=r(t)+v(t)Δt+F(t)2mΔt2\mathbf{r}(t + \Delta t) = \mathbf{r}(t) + \mathbf{v}(t)\Delta t + \frac{\mathbf{F}(t)}{2m}\Delta t^2r(t+Δt)=r(t)+v(t)Δt+2mF(t)Δt2

v(t+Δt)=v(t)+F(t)+F(t+Δt)2mΔt\mathbf{v}(t + \Delta t) = \mathbf{v}(t) + \frac{\mathbf{F}(t) + \mathbf{F}(t + \Delta t)}{2m}\Delta tv(t+Δt)=v(t)+2mF(t)+F(t+Δt)Δt

速度Verlet算法具有时间可逆性和较好的能量守恒特性,是目前最常用的算法。

2.4 系综控制

分子动力学模拟可以在不同统计系综下进行:

NVE系综:微正则系综,粒子数NNN、体积VVV、能量EEE恒定。适用于研究系统的本征动力学行为。

NVT系综:正则系综,粒子数NNN、体积VVV、温度TTT恒定。通过Nose-Hoover热浴或Berendsen热浴控制温度。

NPT系综:等温等压系综,粒子数NNN、压强PPP、温度TTT恒定。通过Parrinello-Rahman方法或Berendsen压强耦合控制压强。


3. 密度泛函理论

3.1 Hohenberg-Kohn定理

密度泛函理论(Density Functional Theory, DFT)基于两个基本定理:

第一定理:外势v(r)v(\mathbf{r})v(r)(从而哈密顿量)由基态电子密度ρ(r)\rho(\mathbf{r})ρ(r)唯一确定(至多相差一个常数)。

第二定理:对于给定的外势,基态能量可以通过能量泛函对密度的变分极小化得到:

E[ρ]=FHK[ρ]+∫v(r)ρ(r)drE[\rho] = F_{HK}[\rho] + \int v(\mathbf{r})\rho(\mathbf{r})d\mathbf{r}E[ρ]=FHK[ρ]+v(r)ρ(r)dr

其中FHK[ρ]F_{HK}[\rho]FHK[ρ]是普适的密度泛函,包含动能和电子相互作用能。

3.2 Kohn-Sham方程

Kohn和Sham将多电子问题转化为等效的单电子问题。Kohn-Sham方程为:

[−ℏ22m∇2+veff(r)]ϕi(r)=εiϕi(r)\left[-\frac{\hbar^2}{2m}\nabla^2 + v_{eff}(\mathbf{r})\right]\phi_i(\mathbf{r}) = \varepsilon_i\phi_i(\mathbf{r})[2m22+veff(r)]ϕi(r)=εiϕi(r)

其中有效势包含外势、Hartree势和交换关联势:

veff(r)=vext(r)+∫ρ(r′)∣r−r′∣dr′+vxc(r)v_{eff}(\mathbf{r}) = v_{ext}(\mathbf{r}) + \int \frac{\rho(\mathbf{r}')}{|\mathbf{r} - \mathbf{r}'|}d\mathbf{r}' + v_{xc}(\mathbf{r})veff(r)=vext(r)+rrρ(r)dr+vxc(r)

电子密度由Kohn-Sham轨道构造:

ρ(r)=∑i=1N∣ϕi(r)∣2\rho(\mathbf{r}) = \sum_{i=1}^{N} |\phi_i(\mathbf{r})|^2ρ(r)=i=1Nϕi(r)2

3.3 交换关联泛函

交换关联泛函的近似是DFT计算精度的关键:

LDA(局域密度近似):假设电子密度在空间缓慢变化,使用均匀电子气的交换关联能。

GGA(广义梯度近似):考虑电子密度的梯度修正,如PBE、BLYP等泛函。

杂化泛函:混合Hartree-Fock交换和DFT交换关联,如B3LYP、HSE06等,通常能给出更精确的结果。


4. 纳米尺度传热与输运

4.1 声子输运

在纳米尺度,声子(晶格振动的量子)的输运行为与宏观尺度显著不同。声子输运可以用玻尔兹曼输运方程描述:

∂f∂t+vg⋅∇f=(∂f∂t)coll\frac{\partial f}{\partial t} + \mathbf{v}_g \cdot \nabla f = \left(\frac{\partial f}{\partial t}\right)_{coll}tf+vgf=(tf)coll

其中fff为声子分布函数,vg\mathbf{v}_gvg为群速度。

声子平均自由程:声子在两次散射之间传播的平均距离。当结构尺寸小于声子平均自由程时,出现弹道输运,热导率显著降低。

界面热阻(Kapitza热阻):由于声子在界面处的反射和透射不完全,导致界面处存在温度跃变:

RK=ΔTQ/AR_K = \frac{\Delta T}{Q/A}RK=Q/AΔT

其中ΔT\Delta TΔT为温度跃变,QQQ为热流,AAA为界面面积。

4.2 电子输运

纳米结构的电子输运表现出量子特性:

弹道输运:当通道长度小于电子平均自由程时,电子不发生散射,电导量子化为:

G=2e2h∑nTnG = \frac{2e^2}{h} \sum_{n} T_nG=h2e2nTn

其中TnT_nTn为第nnn个模式的透射系数。

库仑阻塞:在量子点等小型导体中,单个电子的充电能EC=e2/2CE_C = e^2/2CEC=e2/2C可能远大于热能kBTk_BTkBT,导致电子输运呈现离散台阶(库仑台阶)。


5. 典型案例分析

案例1:碳纳米管力学性能仿真

碳纳米管是由石墨烯片层卷曲而成的管状结构,具有优异的力学性能。本案例通过分子动力学方法模拟单壁碳纳米管的拉伸行为。

物理模型

  • 采用(10,10)扶手椅型单壁碳纳米管
  • 使用AIREBO势函数描述碳-碳相互作用
  • 应用周期性边界条件
  • 在恒温恒容(NVT)系综下进行模拟

仿真步骤

  1. 构建碳纳米管初始结构
  2. 能量最小化弛豫
  3. 一端固定,另一端施加拉伸位移
  4. 记录应力和应变,计算杨氏模量和断裂强度

Python实现

# -*- coding: utf-8 -*-
"""
案例1:碳纳米管力学性能仿真
使用简化分子动力学模型模拟碳纳米管拉伸
"""
import matplotlib
matplotlib.use('Agg')
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, FancyArrowPatch
import warnings
warnings.filterwarnings('ignore')
import os

# 创建输出目录
output_dir = r'd:\\文档\\500仿真领域\\工程仿真\\多场耦合优化\\主题088\\output'
os.makedirs(output_dir, exist_ok=True)

# 设置字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

print("案例1:碳纳米管力学性能仿真")
print("=" * 60)

class CarbonNanotubeMD:
    """碳纳米管分子动力学模拟器"""
    
    def __init__(self, n=10, m=10, length=10):
        """
        初始化碳纳米管
        n, m: 手性指数 (n,n)为扶手椅型
        length: 管长 (nm)
        """
        self.n = n
        self.m = m
        self.length = length
        
        # 碳纳米管几何参数
        self.a_cc = 0.142  # C-C键长 (nm)
        self.diameter = self.a_cc * np.sqrt(n**2 + m**2 + n*m) / np.pi * np.sqrt(3)
        self.radius = self.diameter / 2
        
        # 力场参数 (简化Lennard-Jones + 谐振键)
        self.epsilon = 0.00284  # eV
        self.sigma = 0.34  # nm
        self.k_bond = 469.0  # eV/nm^2 (键伸缩刚度)
        self.k_angle = 7.0  # eV/rad^2 (键角弯曲刚度)
        self.r0 = self.a_cc  # 平衡键长
        
        # 原子质量
        self.m_C = 12.011  # amu
        
        # 初始化原子位置
        self.build_structure()
        
    def build_structure(self):
        """构建扶手椅型碳纳米管原子结构"""
        # 每个单胞有4个碳原子
        num_unit_cells = int(self.length / (self.a_cc * np.sqrt(3)))
        atoms_per_cell = 4
        self.N_atoms = num_unit_cells * atoms_per_cell
        
        # 分配位置数组
        self.positions = np.zeros((self.N_atoms, 3))
        self.velocities = np.zeros((self.N_atoms, 3))
        self.forces = np.zeros((self.N_atoms, 3))
        self.masses = np.ones(self.N_atoms) * self.m_C
        
        # 构建原子位置
        idx = 0
        for i in range(num_unit_cells):
            z = i * self.a_cc * np.sqrt(3)
            # 单胞内4个原子的位置
            angles = np.array([0, np.pi/3, np.pi, 4*np.pi/3])
            z_offsets = np.array([0, self.a_cc, self.a_cc*np.sqrt(3)/2, self.a_cc*(1+np.sqrt(3)/2)])
            
            for j in range(4):
                if idx < self.N_atoms:
                    theta = angles[j % 4]
                    self.positions[idx, 0] = self.radius * np.cos(theta)
                    self.positions[idx, 1] = self.radius * np.sin(theta)
                    self.positions[idx, 2] = z + z_offsets[j % 4]
                    idx += 1
        
        # 构建近邻列表(简化:距离小于1.5倍键长)
        self.build_neighbor_list()
        
    def build_neighbor_list(self):
        """构建原子近邻列表"""
        self.neighbors = []
        cutoff = 1.5 * self.a_cc
        
        for i in range(self.N_atoms):
            neighbors_i = []
            for j in range(self.N_atoms):
                if i != j:
                    r_ij = np.linalg.norm(self.positions[i] - self.positions[j])
                    if r_ij < cutoff:
                        neighbors_i.append(j)
            self.neighbors.append(neighbors_i)
    
    def compute_forces(self):
        """计算原子受力"""
        self.forces.fill(0)
        potential_energy = 0
        
        # 键伸缩力 (谐振子模型)
        for i in range(self.N_atoms):
            for j in self.neighbors[i]:
                if j > i:  # 避免重复计算
                    r_vec = self.positions[j] - self.positions[i]
                    r = np.linalg.norm(r_vec)
                    
                    if r > 0:
                        # 谐振键势能
                        dr = r - self.r0
                        f_mag = -self.k_bond * dr
                        f_vec = f_mag * r_vec / r
                        
                        self.forces[i] -= f_vec
                        self.forces[j] += f_vec
                        potential_energy += 0.5 * self.k_bond * dr**2
        
        # 非键相互作用 (Lennard-Jones)
        for i in range(self.N_atoms):
            for j in range(i+1, self.N_atoms):
                r_vec = self.positions[j] - self.positions[i]
                r = np.linalg.norm(r_vec)
                
                if r < 2.5 * self.sigma and r > 0.15:  # 排除键合原子
                    # LJ势
                    sr6 = (self.sigma / r)**6
                    sr12 = sr6**2
                    f_mag = 24 * self.epsilon * (2*sr12 - sr6) / r
                    f_vec = f_mag * r_vec / r
                    
                    self.forces[i] -= f_vec
                    self.forces[j] += f_vec
                    potential_energy += 4 * self.epsilon * (sr12 - sr6)
        
        return potential_energy
    
    def velocity_verlet(self, dt):
        """速度Verlet积分"""
        # 更新位置
        self.positions += self.velocities * dt + 0.5 * self.forces / self.masses[:, np.newaxis] * dt**2
        
        # 保存旧力
        forces_old = self.forces.copy()
        
        # 计算新力
        pe = self.compute_forces()
        
        # 更新速度
        self.velocities += 0.5 * (forces_old + self.forces) / self.masses[:, np.newaxis] * dt
        
        # 计算动能
        ke = 0.5 * np.sum(self.masses * np.sum(self.velocities**2, axis=1))
        
        return pe, ke
    
    def berendsen_thermostat(self, target_temp, tau, dt):
        """Berendsen热浴控温"""
        kinetic_energy = 0.5 * np.sum(self.masses * np.sum(self.velocities**2, axis=1))
        current_temp = 2 * kinetic_energy / (3 * self.N_atoms * 8.617e-5)  # eV to K
        
        if current_temp > 0:
            scale = np.sqrt(1 + (dt/tau) * (target_temp/current_temp - 1))
            self.velocities *= scale
    
    def apply_strain(self, strain_rate, dt):
        """施加拉伸应变"""
        # 固定底部原子,拉伸顶部原子
        z_max = np.max(self.positions[:, 2])
        z_min = np.min(self.positions[:, 2])
        
        for i in range(self.N_atoms):
            z = self.positions[i, 2]
            # 顶部10%原子受拉伸
            if z > z_max - 0.5:
                self.positions[i, 2] += strain_rate * dt * self.length
                self.velocities[i, 2] = strain_rate * self.length
            # 底部10%原子固定
            elif z < z_min + 0.5:
                self.velocities[i, :] = 0
    
    def compute_stress(self):
        """计算应力"""
        # 简化应力计算:轴向力除以截面积
        z_max = np.max(self.positions[:, 2])
        z_min = np.min(self.positions[:, 2])
        
        # 计算顶部原子受到的总力
        top_force = 0
        for i in range(self.N_atoms):
            if self.positions[i, 2] > z_max - 0.5:
                top_force += self.forces[i, 2]
        
        # 截面积 (环形)
        thickness = 0.34  # nm (石墨烯层间距)
        area = np.pi * ((self.radius + thickness/2)**2 - (self.radius - thickness/2)**2)
        
        # 应力 (GPa)
        stress = abs(top_force) / area * 160.2  # eV/nm^3 to GPa
        
        return stress

# 运行拉伸模拟
print("\n初始化碳纳米管结构...")
nanotube = CarbonNanotubeMD(n=10, m=10, length=10)
print(f"原子数: {nanotube.N_atoms}")
print(f"直径: {nanotube.diameter:.3f} nm")
print(f"长度: {nanotube.length:.1f} nm")

# 能量最小化
print("\n能量最小化...")
dt = 0.001  # ps
temp = 300  # K
for step in range(1000):
    pe, ke = nanotube.velocity_verlet(dt)
    nanotube.berendsen_thermostat(temp, 0.1, dt)
    if step % 200 == 0:
        print(f"  Step {step}: PE = {pe:.2f} eV, KE = {ke:.2f} eV")

# 拉伸模拟
print("\n开始拉伸模拟...")
strain_rate = 0.001  # 1/ps
max_strain = 0.3
num_steps = int(max_strain / strain_rate / dt)

# 记录数据
strains = []
stresses = []
positions_history = []

sample_interval = max(1, num_steps // 100)

for step in range(num_steps):
    pe, ke = nanotube.velocity_verlet(dt)
    nanotube.apply_strain(strain_rate, dt)
    nanotube.berendsen_thermostat(temp, 0.1, dt)
    
    if step % sample_interval == 0:
        strain = step * strain_rate * dt
        stress = nanotube.compute_stress()
        strains.append(strain)
        stresses.append(stress)
        
        if step % (10 * sample_interval) == 0:
            positions_history.append(nanotube.positions.copy())
    
    if step % 5000 == 0:
        print(f"  Step {step}/{num_steps}, Strain = {step*strain_rate*dt:.3f}, Stress = {stress:.2f} GPa")

strains = np.array(strains)
stresses = np.array(stresses)

print(f"\n最大应力: {np.max(stresses):.2f} GPa")
print(f"杨氏模量: {stresses[10]/strains[10]:.2f} GPa")

# 可视化结果
fig = plt.figure(figsize=(16, 12))

# 1. 应力-应变曲线
ax1 = fig.add_subplot(2, 3, 1)
ax1.plot(strains * 100, stresses, 'b-', linewidth=2)
ax1.set_xlabel('Strain (%)', fontsize=11)
ax1.set_ylabel('Stress (GPa)', fontsize=11)
ax1.set_title('Stress-Strain Curve', fontsize=12, fontweight='bold')
ax1.grid(True, alpha=0.3)
ax1.axhline(y=0, color='k', linewidth=0.5)

# 2. 碳纳米管结构示意图
ax2 = fig.add_subplot(2, 3, 2, projection='3d')
# 绘制初始结构
pos_init = positions_history[0] if positions_history else nanotube.positions
ax2.scatter(pos_init[:, 0], pos_init[:, 1], pos_init[:, 2], 
           c='gray', s=50, alpha=0.8, label='Initial')
ax2.set_xlabel('X (nm)')
ax2.set_ylabel('Y (nm)')
ax2.set_zlabel('Z (nm)')
ax2.set_title('Initial Structure', fontsize=12, fontweight='bold')

# 3. 变形后的结构
ax3 = fig.add_subplot(2, 3, 3, projection='3d')
if len(positions_history) > 5:
    pos_final = positions_history[-1]
    ax3.scatter(pos_final[:, 0], pos_final[:, 1], pos_final[:, 2], 
               c='red', s=50, alpha=0.8, label='Deformed')
    ax3.set_xlabel('X (nm)')
    ax3.set_ylabel('Y (nm)')
    ax3.set_zlabel('Z (nm)')
    ax3.set_title('Deformed Structure', fontsize=12, fontweight='bold')

# 4. 能量演化
ax4 = fig.add_subplot(2, 3, 4)
# 重新计算能量
pe_list = []
ke_list = []
total_energy = []
nanotube_temp = CarbonNanotubeMD(n=10, m=10, length=10)
for step in range(1000):
    pe, ke = nanotube_temp.velocity_verlet(dt)
    nanotube_temp.berendsen_thermostat(temp, 0.1, dt)
    pe_list.append(pe)
    ke_list.append(ke)
    total_energy.append(pe + ke)

steps = np.arange(len(pe_list))
ax4.plot(steps, pe_list, 'b-', label='Potential', linewidth=1.5)
ax4.plot(steps, ke_list, 'r-', label='Kinetic', linewidth=1.5)
ax4.plot(steps, total_energy, 'g--', label='Total', linewidth=1.5)
ax4.set_xlabel('Step', fontsize=11)
ax4.set_ylabel('Energy (eV)', fontsize=11)
ax4.set_title('Energy Minimization', fontsize=12, fontweight='bold')
ax4.legend()
ax4.grid(True, alpha=0.3)

# 5. 杨氏模量计算
ax5 = fig.add_subplot(2, 3, 5)
# 线性拟合计算杨氏模量
linear_region = strains < 0.05
if np.sum(linear_region) > 5:
    E_fit = np.polyfit(strains[linear_region], stresses[linear_region], 1)
    E_young = E_fit[0]
    ax5.plot(strains[linear_region] * 100, stresses[linear_region], 'bo', markersize=4, label='Data')
    ax5.plot(strains[linear_region] * 100, 
             np.polyval(E_fit, strains[linear_region]), 
             'r-', linewidth=2, label=f'E = {E_young:.1f} GPa')
ax5.set_xlabel('Strain (%)', fontsize=11)
ax5.set_ylabel('Stress (GPa)', fontsize=11)
ax5.set_title('Young\'s Modulus', fontsize=12, fontweight='bold')
ax5.legend()
ax5.grid(True, alpha=0.3)

# 6. 径向分布函数
ax6 = fig.add_subplot(2, 3, 6)
# 计算RDF
pos = nanotube.positions
rdf_r = np.linspace(0.1, 1.0, 100)
rdf_g = np.zeros_like(rdf_r)
dr = rdf_r[1] - rdf_r[0]

for i in range(nanotube.N_atoms):
    for j in range(i+1, nanotube.N_atoms):
        r_ij = np.linalg.norm(pos[i] - pos[j])
        idx = int((r_ij - rdf_r[0]) / dr)
        if 0 <= idx < len(rdf_r):
            rdf_g[idx] += 2  # 每对原子贡献2

# 归一化
shell_volume = 4 * np.pi * rdf_r**2 * dr
rho = nanotube.N_atoms / (np.pi * nanotube.radius**2 * nanotube.length)
rdf_g = rdf_g / (nanotube.N_atoms * rho * shell_volume)

ax6.plot(rdf_r, rdf_g, 'b-', linewidth=2)
ax6.set_xlabel('r (nm)', fontsize=11)
ax6.set_ylabel('g(r)', fontsize=11)
ax6.set_title('Radial Distribution Function', fontsize=12, fontweight='bold')
ax6.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig(f'{output_dir}/case1_nanotube_mechanics.png', dpi=150, bbox_inches='tight')
plt.close()

print("\n✓ 案例1完成:碳纳米管力学性能仿真")
print(f"  结果保存在: {output_dir}/case1_nanotube_mechanics.png")

案例2:纳米颗粒自组装模拟

纳米颗粒的自组装是构建有序纳米结构的重要方法。本案例模拟疏水性纳米颗粒在溶液中的自组装过程。

物理模型

  • 纳米颗粒用粗粒化珠子表示
  • 颗粒间通过Lennard-Jones势相互作用
  • 疏水相互作用通过调节LJ参数实现
  • 溶剂效应隐式处理

仿真目标

  • 观察纳米颗粒从无序到有序的相变
  • 分析团簇尺寸分布
  • 研究自组装动力学

Python实现

# -*- coding: utf-8 -*-
"""
案例2:纳米颗粒自组装模拟
模拟疏水性纳米颗粒的聚集和自组装过程
"""
import matplotlib
matplotlib.use('Agg')
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
from matplotlib.collections import PatchCollection
import warnings
warnings.filterwarnings('ignore')
import os

output_dir = r'd:\\文档\\500仿真领域\\工程仿真\\多场耦合优化\\主题088\\output'
os.makedirs(output_dir, exist_ok=True)

plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

print("\n案例2:纳米颗粒自组装模拟")
print("=" * 60)

class NanoparticleSelfAssembly:
    """纳米颗粒自组装模拟器"""
    
    def __init__(self, N_particles=200, box_size=50.0, temperature=300):
        """
        初始化系统
        N_particles: 颗粒数量
        box_size: 模拟盒子尺寸 (nm)
        temperature: 温度 (K)
        """
        self.N = N_particles
        self.L = box_size
        self.T = temperature
        
        # 颗粒参数
        self.sigma = 2.0  # 颗粒直径 (nm)
        self.epsilon = 0.5  # 相互作用强度 (eV)
        self.mass = 100.0  # 颗粒质量 (amu)
        
        # 初始化位置 (随机分布)
        self.positions = np.random.rand(self.N, 3) * self.L
        self.velocities = np.random.randn(self.N, 3) * np.sqrt(self.T / self.mass)
        self.forces = np.zeros((self.N, 3))
        
        # 记录团簇信息
        self.clusters_history = []
        self.potential_energy_history = []
        
    def minimum_image(self, r):
        """最小镜像约定处理周期性边界"""
        return r - self.L * np.round(r / self.L)
    
    def compute_forces(self):
        """计算Lennard-Jones力"""
        self.forces.fill(0)
        potential = 0
        
        for i in range(self.N):
            for j in range(i+1, self.N):
                r_vec = self.positions[j] - self.positions[i]
                r_vec = self.minimum_image(r_vec)
                r = np.linalg.norm(r_vec)
                
                if r < 2.5 * self.sigma and r > 0:
                    # LJ势和力
                    sr = self.sigma / r
                    sr6 = sr**6
                    sr12 = sr6**2
                    
                    f_mag = 24 * self.epsilon * (2*sr12 - sr6) / r
                    f_vec = f_mag * r_vec / r
                    
                    self.forces[i] -= f_vec
                    self.forces[j] += f_vec
                    
                    potential += 4 * self.epsilon * (sr12 - sr6)
        
        return potential
    
    def velocity_verlet(self, dt):
        """速度Verlet积分"""
        self.positions += self.velocities * dt + 0.5 * self.forces / self.mass * dt**2
        
        # 周期性边界条件
        self.positions = self.positions % self.L
        
        forces_old = self.forces.copy()
        pe = self.compute_forces()
        
        self.velocities += 0.5 * (forces_old + self.forces) / self.mass * dt
        
        ke = 0.5 * self.mass * np.sum(self.velocities**2)
        
        return pe, ke
    
    def andersen_thermostat(self, dt, nu=0.1):
        """Andersen热浴"""
        for i in range(self.N):
            if np.random.rand() < nu * dt:
                self.velocities[i] = np.random.randn(3) * np.sqrt(self.T / self.mass)
    
    def find_clusters(self, cutoff=None):
        """识别团簇 (基于距离)"""
        if cutoff is None:
            cutoff = 1.5 * self.sigma
        
        clusters = []
        visited = np.zeros(self.N, dtype=bool)
        
        for i in range(self.N):
            if not visited[i]:
                cluster = []
                stack = [i]
                
                while stack:
                    j = stack.pop()
                    if not visited[j]:
                        visited[j] = True
                        cluster.append(j)
                        
                        # 寻找近邻
                        for k in range(self.N):
                            if not visited[k]:
                                r_vec = self.positions[k] - self.positions[j]
                                r_vec = self.minimum_image(r_vec)
                                if np.linalg.norm(r_vec) < cutoff:
                                    stack.append(k)
                
                clusters.append(cluster)
        
        return clusters
    
    def run_simulation(self, n_steps=10000, dt=0.001):
        """运行模拟"""
        print(f"\n运行自组装模拟...")
        print(f"颗粒数: {self.N}")
        print(f"盒子尺寸: {self.L} nm")
        print(f"温度: {self.T} K")
        
        # 平衡阶段
        print("\n平衡阶段...")
        for step in range(2000):
            pe, ke = self.velocity_verlet(dt)
            self.andersen_thermostat(dt)
        
        # 生产阶段
        print("生产阶段...")
        sample_interval = 100
        
        for step in range(n_steps):
            pe, ke = self.velocity_verlet(dt)
            self.andersen_thermostat(dt)
            
            if step % sample_interval == 0:
                clusters = self.find_clusters()
                self.clusters_history.append([len(c) for c in clusters])
                self.potential_energy_history.append(pe)
            
            if step % 2000 == 0:
                print(f"  Step {step}/{n_steps}, PE = {pe:.2f} eV, Clusters = {len(clusters)}")
        
        print(f"\n模拟完成!")
        print(f"最终团簇数: {len(clusters)}")
        
        return clusters

# 运行模拟
assembly = NanoparticleSelfAssembly(N_particles=200, box_size=50.0, temperature=300)
final_clusters = assembly.run_simulation(n_steps=10000, dt=0.001)

# 可视化结果
fig = plt.figure(figsize=(16, 12))

# 1. 初始构型
ax1 = fig.add_subplot(2, 3, 1)
initial_pos = np.random.rand(200, 3) * 50.0  # 重新生成初始位置用于展示
ax1.scatter(initial_pos[:, 0], initial_pos[:, 1], s=50, c='blue', alpha=0.6)
ax1.set_xlim(0, 50)
ax1.set_ylim(0, 50)
ax1.set_xlabel('X (nm)', fontsize=11)
ax1.set_ylabel('Y (nm)', fontsize=11)
ax1.set_title('Initial Configuration', fontsize=12, fontweight='bold')
ax1.set_aspect('equal')

# 2. 最终构型
ax2 = fig.add_subplot(2, 3, 2)
# 根据团簇着色
colors = plt.cm.tab20(np.linspace(0, 1, len(final_clusters)))
for idx, cluster in enumerate(final_clusters):
    cluster_pos = assembly.positions[cluster]
    ax2.scatter(cluster_pos[:, 0], cluster_pos[:, 1], 
               s=80, c=[colors[idx]], alpha=0.8, edgecolors='black', linewidth=0.5)
ax2.set_xlim(0, 50)
ax2.set_ylim(0, 50)
ax2.set_xlabel('X (nm)', fontsize=11)
ax2.set_ylabel('Y (nm)', fontsize=11)
ax2.set_title('Final Configuration (Clusters)', fontsize=12, fontweight='bold')
ax2.set_aspect('equal')

# 3. 势能演化
ax3 = fig.add_subplot(2, 3, 3)
pe_history = np.array(assembly.potential_energy_history)
steps = np.arange(len(pe_history)) * 100
colors_pe = plt.cm.coolwarm((pe_history - pe_history.min()) / (pe_history.max() - pe_history.min()))
ax3.scatter(steps, pe_history, c=colors_pe, s=20, alpha=0.6)
ax3.plot(steps, pe_history, 'b-', alpha=0.3, linewidth=1)
ax3.set_xlabel('Step', fontsize=11)
ax3.set_ylabel('Potential Energy (eV)', fontsize=11)
ax3.set_title('Potential Energy Evolution', fontsize=12, fontweight='bold')
ax3.grid(True, alpha=0.3)

# 4. 团簇尺寸分布
ax4 = fig.add_subplot(2, 3, 4)
final_sizes = [len(c) for c in final_clusters]
unique_sizes, counts = np.unique(final_sizes, return_counts=True)
ax4.bar(unique_sizes, counts, color='steelblue', edgecolor='black', alpha=0.7)
ax4.set_xlabel('Cluster Size', fontsize=11)
ax4.set_ylabel('Count', fontsize=11)
ax4.set_title('Cluster Size Distribution', fontsize=12, fontweight='bold')
ax4.grid(True, alpha=0.3, axis='y')

# 5. 团簇数量演化
ax5 = fig.add_subplot(2, 3, 5)
n_clusters_history = [len(sizes) for sizes in assembly.clusters_history]
steps_clusters = np.arange(len(n_clusters_history)) * 100
ax5.plot(steps_clusters, n_clusters_history, 'g-', linewidth=2)
ax5.set_xlabel('Step', fontsize=11)
ax5.set_ylabel('Number of Clusters', fontsize=11)
ax5.set_title('Cluster Count Evolution', fontsize=12, fontweight='bold')
ax5.grid(True, alpha=0.3)

# 6. 平均团簇尺寸演化
ax6 = fig.add_subplot(2, 3, 6)
avg_sizes = [np.mean(sizes) for sizes in assembly.clusters_history]
ax6.plot(steps_clusters, avg_sizes, 'r-', linewidth=2)
ax6.set_xlabel('Step', fontsize=11)
ax6.set_ylabel('Average Cluster Size', fontsize=11)
ax6.set_title('Average Cluster Size Evolution', fontsize=12, fontweight='bold')
ax6.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig(f'{output_dir}/case2_self_assembly.png', dpi=150, bbox_inches='tight')
plt.close()

print("\n✓ 案例2完成:纳米颗粒自组装模拟")
print(f"  结果保存在: {output_dir}/case2_self_assembly.png")

案例3:分子机器运动仿真

分子机器是能够在分子尺度执行机械功的人工分子器件。本案例模拟一个简化的分子马达模型。

物理模型

  • 转子:由3个质量点构成的三角形结构
  • 定子:固定的环形轨道
  • 驱动:通过周期性改变电场方向驱动转子转动
  • 相互作用:Lennard-Jones势 + 库仑势

仿真目标

  • 观察转子的定向旋转
  • 分析转速与驱动频率的关系
  • 研究能量转换效率

Python实现

# -*- coding: utf-8 -*-
"""
案例3:分子机器运动仿真
模拟光驱动分子马达的旋转运动
"""
import matplotlib
matplotlib.use('Agg')
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, FancyArrowPatch, Wedge
import warnings
warnings.filterwarnings('ignore')
import os

output_dir = r'd:\\文档\\500仿真领域\\工程仿真\\多场耦合优化\\主题088\\output'
os.makedirs(output_dir, exist_ok=True)

plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

print("\n案例3:分子机器运动仿真")
print("=" * 60)

class MolecularMotor:
    """分子马达模拟器"""
    
    def __init__(self):
        """初始化分子马达系统"""
        # 定子参数 (环形轨道)
        self.stator_radius = 2.0  # nm
        self.n_stator_sites = 12  # 定子位点数
        
        # 转子参数 (三角形结构)
        self.rotor_arm_length = 1.5  # nm
        self.rotor_mass = 100.0  # amu
        self.rotor_inertia = self.rotor_mass * self.rotor_arm_length**2  # 转动惯量
        
        # 初始状态
        self.theta = 0.0  # 转子角度
        self.omega = 0.0  # 角速度
        
        # 驱动参数
        self.drive_frequency = 1.0  # GHz
        self.drive_amplitude = 0.5  # eV/nm
        
        # 相互作用参数
        self.epsilon_lj = 0.1  # LJ势阱深度
        self.sigma_lj = 0.3  # LJ特征长度
        self.k_spring = 10.0  # 弹簧常数
        
        # 记录数据
        self.theta_history = []
        self.omega_history = []
        self.energy_history = []
        self.torque_history = []
        
    def compute_stator_potential(self, theta):
        """计算定子产生的周期性势场"""
        # 余弦势场,n_stator_sites个势阱
        V = -self.epsilon_lj * np.cos(self.n_stator_sites * theta)
        return V
    
    def compute_stator_torque(self, theta):
        """计算定子产生的力矩"""
        # 力矩 = -dV/dtheta
        tau = -self.epsilon_lj * self.n_stator_sites * np.sin(self.n_stator_sites * theta)
        return tau
    
    def compute_drive_torque(self, t):
        """计算驱动力矩 (周期性驱动)"""
        # 通过改变电场方向驱动
        drive_phase = 2 * np.pi * self.drive_frequency * t
        tau_drive = self.drive_amplitude * np.sin(drive_phase)
        return tau_drive
    
    def compute_friction_torque(self):
        """计算摩擦力矩"""
        gamma = 0.1  # 摩擦系数
        tau_friction = -gamma * self.omega
        return tau_friction
    
    def step(self, dt, t):
        """时间步进"""
        # 计算总力矩
        tau_stator = self.compute_stator_torque(self.theta)
        tau_drive = self.compute_drive_torque(t)
        tau_friction = self.compute_friction_torque()
        
        tau_total = tau_stator + tau_drive + tau_friction
        
        # 更新角速度和角度
        alpha = tau_total / self.rotor_inertia  # 角加速度
        self.omega += alpha * dt
        self.theta += self.omega * dt
        
        # 保持角度在[0, 2π)
        self.theta = self.theta % (2 * np.pi)
        
        # 计算能量
        V_stator = self.compute_stator_potential(self.theta)
        K_rot = 0.5 * self.rotor_inertia * self.omega**2
        E_total = V_stator + K_rot
        
        # 记录
        self.theta_history.append(self.theta)
        self.omega_history.append(self.omega)
        self.energy_history.append(E_total)
        self.torque_history.append(tau_total)
        
        return E_total, tau_total
    
    def get_rotor_positions(self):
        """获取转子三个臂的位置"""
        positions = []
        for i in range(3):
            angle = self.theta + i * 2 * np.pi / 3
            x = self.rotor_arm_length * np.cos(angle)
            y = self.rotor_arm_length * np.sin(angle)
            positions.append([x, y])
        return np.array(positions)

# 运行模拟
print("\n初始化分子马达...")
motor = MolecularMotor()
print(f"定子半径: {motor.stator_radius} nm")
print(f"转子臂长: {motor.rotor_arm_length} nm")
print(f"驱动频率: {motor.drive_frequency} GHz")

# 模拟参数
total_time = 10.0  # ns
dt = 0.001  # ns
n_steps = int(total_time / dt)

print(f"\n运行模拟: {total_time} ns, {n_steps} 步")

for step in range(n_steps):
    t = step * dt
    motor.step(dt, t)
    
    if step % 10000 == 0:
        print(f"  t = {t:.2f} ns, theta = {motor.theta:.3f} rad, omega = {motor.omega:.3f} rad/ns")

# 转换为numpy数组
motor.theta_history = np.array(motor.theta_history)
motor.omega_history = np.array(motor.omega_history)
motor.energy_history = np.array(motor.energy_history)
motor.torque_history = np.array(motor.torque_history)
time_array = np.arange(len(motor.theta_history)) * dt

print(f"\n模拟完成!")
print(f"平均转速: {np.mean(np.abs(motor.omega_history)):.3f} rad/ns")
print(f"总转数: {motor.theta_history[-1] / (2*np.pi):.1f} 圈")

# 可视化结果
fig = plt.figure(figsize=(16, 12))

# 1. 分子马达结构示意图
ax1 = fig.add_subplot(2, 3, 1)
# 绘制定子
for i in range(motor.n_stator_sites):
    angle = 2 * np.pi * i / motor.n_stator_sites
    x = motor.stator_radius * np.cos(angle)
    y = motor.stator_radius * np.sin(angle)
    circle = Circle((x, y), 0.15, color='blue', alpha=0.6)
    ax1.add_patch(circle)

# 绘制转子
rotor_pos = motor.get_rotor_positions()
for pos in rotor_pos:
    circle = Circle(pos, 0.2, color='red', alpha=0.8)
    ax1.add_patch(circle)
# 连接线
ax1.plot(np.append(rotor_pos[:, 0], rotor_pos[0, 0]), 
         np.append(rotor_pos[:, 1], rotor_pos[0, 1]), 
         'r-', linewidth=2)

ax1.set_xlim(-3, 3)
ax1.set_ylim(-3, 3)
ax1.set_aspect('equal')
ax1.set_xlabel('X (nm)', fontsize=11)
ax1.set_ylabel('Y (nm)', fontsize=11)
ax1.set_title('Molecular Motor Structure', fontsize=12, fontweight='bold')

# 2. 角度演化
ax2 = fig.add_subplot(2, 3, 2)
# 展开角度(去除2π跳跃)
theta_unwrapped = np.unwrap(motor.theta_history)
ax2.plot(time_array, theta_unwrapped, 'b-', linewidth=1.5)
ax2.set_xlabel('Time (ns)', fontsize=11)
ax2.set_ylabel('Angle (rad)', fontsize=11)
ax2.set_title('Rotor Angle Evolution', fontsize=12, fontweight='bold')
ax2.grid(True, alpha=0.3)

# 3. 角速度演化
ax3 = fig.add_subplot(2, 3, 3)
ax3.plot(time_array, motor.omega_history, 'r-', linewidth=1.5, alpha=0.7)
# 平滑曲线
window = 1000
if len(motor.omega_history) > window:
    omega_smooth = np.convolve(motor.omega_history, np.ones(window)/window, mode='valid')
    ax3.plot(time_array[window-1:], omega_smooth, 'g-', linewidth=2, label='Smoothed')
ax3.set_xlabel('Time (ns)', fontsize=11)
ax3.set_ylabel('Angular Velocity (rad/ns)', fontsize=11)
ax3.set_title('Angular Velocity', fontsize=12, fontweight='bold')
ax3.grid(True, alpha=0.3)
ax3.legend()

# 4. 能量演化
ax4 = fig.add_subplot(2, 3, 4)
ax4.plot(time_array, motor.energy_history, 'purple', linewidth=1.5, alpha=0.7)
ax4.set_xlabel('Time (ns)', fontsize=11)
ax4.set_ylabel('Energy (eV)', fontsize=11)
ax4.set_title('Total Energy', fontsize=12, fontweight='bold')
ax4.grid(True, alpha=0.3)

# 5. 力矩分析
ax5 = fig.add_subplot(2, 3, 5)
ax5.plot(time_array, motor.torque_history, 'orange', linewidth=1, alpha=0.5)
# 计算平均力矩
window_torque = 5000
if len(motor.torque_history) > window_torque:
    torque_smooth = np.convolve(motor.torque_history, np.ones(window_torque)/window_torque, mode='valid')
    ax5.plot(time_array[window_torque-1:], torque_smooth, 'darkorange', linewidth=2, label='Average')
ax5.axhline(y=0, color='k', linestyle='--', linewidth=0.5)
ax5.set_xlabel('Time (ns)', fontsize=11)
ax5.set_ylabel('Torque (eV)', fontsize=11)
ax5.set_title('Applied Torque', fontsize=12, fontweight='bold')
ax5.grid(True, alpha=0.3)
ax5.legend()

# 6. 相空间轨迹
ax6 = fig.add_subplot(2, 3, 6)
ax6.plot(motor.theta_history, motor.omega_history, 'g.', markersize=1, alpha=0.3)
ax6.set_xlabel('Angle (rad)', fontsize=11)
ax6.set_ylabel('Angular Velocity (rad/ns)', fontsize=11)
ax6.set_title('Phase Space Trajectory', fontsize=12, fontweight='bold')
ax6.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig(f'{output_dir}/case3_molecular_motor.png', dpi=150, bbox_inches='tight')
plt.close()

print("\n✓ 案例3完成:分子机器运动仿真")
print(f"  结果保存在: {output_dir}/case3_molecular_motor.png")

案例4:石墨烯电子性质计算

石墨烯是由碳原子以sp²杂化形成的二维蜂窝状晶格,具有独特的电子性质。本案例使用紧束缚模型计算石墨烯的能带结构。

物理模型

  • 紧束缚近似:只考虑最近邻相互作用
  • 每个碳原子贡献一个p_z电子
  • 哈密顿量矩阵在k空间构建

紧束缚模型

H=−t∑<i,j>(ci†cj+h.c.)H = -t\sum_{<i,j>} (c_i^\dagger c_j + h.c.)H=t<i,j>(cicj+h.c.)

其中t≈2.7t \approx 2.7t2.7 eV为跃迁积分,ci†c_i^\daggercicjc_jcj为产生和湮灭算符。

Python实现

# -*- coding: utf-8 -*-
"""
案例4:石墨烯电子性质计算
使用紧束缚模型计算能带结构和态密度
"""
import matplotlib
matplotlib.use('Agg')
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import warnings
warnings.filterwarnings('ignore')
import os

output_dir = r'd:\\文档\\500仿真领域\\工程仿真\\多场耦合优化\\主题088\\output'
os.makedirs(output_dir, exist_ok=True)

plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

print("\n案例4:石墨烯电子性质计算")
print("=" * 60)

class GrapheneTightBinding:
    """石墨烯紧束缚模型"""
    
    def __init__(self, t=2.7, a=0.246):
        """
        初始化参数
        t: 最近邻跃迁积分 (eV)
        a: 晶格常数 (nm)
        """
        self.t = t
        self.a = a
        
        # 倒格子基矢
        self.b1 = 2 * np.pi / a * np.array([1, 1/np.sqrt(3)])
        self.b2 = 2 * np.pi / a * np.array([0, 2/np.sqrt(3)])
        
        # 高对称点
        self.Gamma = np.array([0, 0])
        self.K = 2 * np.pi / a * np.array([1/3, 1/np.sqrt(3)])
        self.M = 2 * np.pi / a * np.array([1/2, 1/(2*np.sqrt(3))])
        
    def hamiltonian(self, kx, ky):
        """
        构建k点哈密顿量
        对于石墨烯,每个原胞有2个原子(A和B子晶格)
        """
        # 最近邻矢量在实空间
        delta1 = self.a * np.array([0, 1/np.sqrt(3)])
        delta2 = self.a * np.array([-1/2, -1/(2*np.sqrt(3))])
        delta3 = self.a * np.array([1/2, -1/(2*np.sqrt(3))])
        
        # 跃迁项 f(k) = sum_j exp(i*k·delta_j)
        k_vec = np.array([kx, ky])
        f = np.exp(1j * np.dot(k_vec, delta1)) + \
            np.exp(1j * np.dot(k_vec, delta2)) + \
            np.exp(1j * np.dot(k_vec, delta3))
        
        # 2x2 哈密顿量矩阵
        H = np.array([[0, -self.t * f],
                      [-self.t * np.conj(f), 0]])
        
        return H
    
    def compute_bands(self, kx_array, ky_array):
        """计算能带"""
        E_plus = np.zeros((len(kx_array), len(ky_array)))
        E_minus = np.zeros((len(kx_array), len(ky_array)))
        
        for i, kx in enumerate(kx_array):
            for j, ky in enumerate(ky_array):
                H = self.hamiltonian(kx, ky)
                eigenvalues = np.linalg.eigvalsh(H)
                E_plus[i, j] = eigenvalues[1]
                E_minus[i, j] = eigenvalues[0]
        
        return E_plus, E_minus
    
    def band_structure_path(self, n_points=100):
        """计算高对称路径上的能带"""
        # 路径: Gamma -> K -> M -> Gamma
        path_segments = [
            (self.Gamma, self.K),
            (self.K, self.M),
            (self.M, self.Gamma)
        ]
        
        k_points = []
        k_distances = []
        energies_plus = []
        energies_minus = []
        
        total_dist = 0
        for start, end in path_segments:
            for i in range(n_points):
                alpha = i / (n_points - 1)
                k = (1 - alpha) * start + alpha * end
                k_points.append(k)
                
                H = self.hamiltonian(k[0], k[1])
                eigenvalues = np.linalg.eigvalsh(H)
                energies_plus.append(eigenvalues[1])
                energies_minus.append(eigenvalues[0])
                
                if i == 0 and len(k_distances) == 0:
                    k_distances.append(0)
                elif i > 0:
                    dk = np.linalg.norm(k - k_points[-2])
                    total_dist += dk
                    k_distances.append(total_dist)
        
        return np.array(k_distances), np.array(energies_plus), np.array(energies_minus)
    
    def density_of_states(self, n_k=100, n_E=200):
        """计算态密度"""
        # 在第一布里渊区采样
        kx_vals = np.linspace(-np.pi/self.a, np.pi/self.a, n_k)
        ky_vals = np.linspace(-np.pi/self.a, np.pi/self.a, n_k)
        
        energies = []
        for kx in kx_vals:
            for ky in ky_vals:
                H = self.hamiltonian(kx, ky)
                eigenvalues = np.linalg.eigvalsh(H)
                energies.extend(eigenvalues)
        
        energies = np.array(energies)
        
        # 直方图统计
        E_min, E_max = energies.min(), energies.max()
        E_bins = np.linspace(E_min, E_max, n_E)
        dos, _ = np.histogram(energies, bins=E_bins, density=True)
        E_centers = (E_bins[:-1] + E_bins[1:]) / 2
        
        return E_centers, dos

# 创建模型
print("\n初始化石墨烯紧束缚模型...")
graphene = GrapheneTightBinding(t=2.7, a=0.246)
print(f"跃迁积分 t = {graphene.t} eV")
print(f"晶格常数 a = {graphene.a} nm")

# 计算布里渊区能带
print("\n计算能带结构...")
kx_array = np.linspace(-np.pi/graphene.a, np.pi/graphene.a, 100)
ky_array = np.linspace(-np.pi/graphene.a, np.pi/graphene.a, 100)
KX, KY = np.meshgrid(kx_array, ky_array)

E_plus, E_minus = graphene.compute_bands(kx_array, ky_array)

# 高对称路径能带
print("计算高对称路径能带...")
k_path, E_plus_path, E_minus_path = graphene.band_structure_path(n_points=150)

# 态密度
print("计算态密度...")
E_dos, dos = graphene.density_of_states(n_k=80, n_E=150)

print("\n能带计算完成!")
print(f"导带底能量: {E_plus.min():.3f} eV")
print(f"价带顶能量: {E_minus.max():.3f} eV")
print(f"能隙: {E_plus.min() - E_minus.max():.3f} eV (应为0,Dirac点)")

# 可视化结果
fig = plt.figure(figsize=(16, 12))

# 1. 3D能带图 - 导带
ax1 = fig.add_subplot(2, 3, 1, projection='3d')
surf1 = ax1.plot_surface(KX, KY, E_plus, cmap='viridis', alpha=0.8)
ax1.set_xlabel('$k_x$ (nm$^{-1}$)', fontsize=10)
ax1.set_ylabel('$k_y$ (nm$^{-1}$)', fontsize=10)
ax1.set_zlabel('E (eV)', fontsize=10)
ax1.set_title('Conduction Band', fontsize=12, fontweight='bold')
fig.colorbar(surf1, ax=ax1, shrink=0.5)

# 2. 3D能带图 - 价带
ax2 = fig.add_subplot(2, 3, 2, projection='3d')
surf2 = ax2.plot_surface(KX, KY, E_minus, cmap='plasma', alpha=0.8)
ax2.set_xlabel('$k_x$ (nm$^{-1}$)', fontsize=10)
ax2.set_ylabel('$k_y$ (nm$^{-1}$)', fontsize=10)
ax2.set_zlabel('E (eV)', fontsize=10)
ax2.set_title('Valence Band', fontsize=12, fontweight='bold')
fig.colorbar(surf2, ax=ax2, shrink=0.5)

# 3. 高对称路径能带
ax3 = fig.add_subplot(2, 3, 3)
ax3.plot(k_path, E_plus_path, 'b-', linewidth=2, label='Conduction')
ax3.plot(k_path, E_minus_path, 'r-', linewidth=2, label='Valence')
ax3.axhline(y=0, color='k', linestyle='--', linewidth=0.5)
# 标记高对称点
n_per_segment = 100
ax3.axvline(x=k_path[n_per_segment-1], color='gray', linestyle=':', alpha=0.5)
ax3.axvline(x=k_path[2*n_per_segment-1], color='gray', linestyle=':', alpha=0.5)
ax3.text(k_path[0], E_minus_path.min()-0.3, 'Γ', fontsize=12, ha='center')
ax3.text(k_path[n_per_segment-1], E_minus_path.min()-0.3, 'K', fontsize=12, ha='center')
ax3.text(k_path[2*n_per_segment-1], E_minus_path.min()-0.3, 'M', fontsize=12, ha='center')
ax3.text(k_path[-1], E_minus_path.min()-0.3, 'Γ', fontsize=12, ha='center')
ax3.set_xlabel('k-path', fontsize=11)
ax3.set_ylabel('Energy (eV)', fontsize=11)
ax3.set_title('Band Structure', fontsize=12, fontweight='bold')
ax3.legend()
ax3.grid(True, alpha=0.3)

# 4. 态密度
ax4 = fig.add_subplot(2, 3, 4)
ax4.fill_between(E_dos, dos, alpha=0.5, color='green')
ax4.plot(E_dos, dos, 'g-', linewidth=2)
ax4.axvline(x=0, color='k', linestyle='--', linewidth=0.5, label='Fermi level')
ax4.set_xlabel('Energy (eV)', fontsize=11)
ax4.set_ylabel('DOS (a.u.)', fontsize=11)
ax4.set_title('Density of States', fontsize=12, fontweight='bold')
ax4.legend()
ax4.grid(True, alpha=0.3)

# 5. Dirac锥放大图
ax5 = fig.add_subplot(2, 3, 5)
# 在K点附近采样
K_point = graphene.K
kx_dirac = np.linspace(K_point[0]-0.5, K_point[0]+0.5, 80)
ky_dirac = np.linspace(K_point[1]-0.5, K_point[1]+0.5, 80)
KX_D, KY_D = np.meshgrid(kx_dirac, ky_dirac)

E_plus_D, E_minus_D = graphene.compute_bands(kx_dirac, ky_dirac)

# 绘制等高线
levels = np.linspace(-1, 1, 21)
contour = ax5.contour(KX_D - K_point[0], KY_D - K_point[1], E_plus_D, 
                      levels=levels, cmap='RdBu_r')
ax5.contour(KX_D - K_point[0], KY_D - K_point[1], E_minus_D, 
            levels=levels, cmap='RdBu_r')
ax5.set_xlabel('$k_x - K_x$ (nm$^{-1}$)', fontsize=11)
ax5.set_ylabel('$k_y - K_y$ (nm$^{-1}$)', fontsize=11)
ax5.set_title('Dirac Cone (Zoom near K)', fontsize=12, fontweight='bold')
ax5.set_aspect('equal')
plt.colorbar(contour, ax=ax5)

# 6. 费米速度计算
ax6 = fig.add_subplot(2, 3, 6)
# 沿K-Gamma方向计算色散
k_dir = np.linspace(0, 1.0, 100)
E_dirac = []
for dk in k_dir:
    k_point = graphene.K + dk * (graphene.Gamma - graphene.K)
    H = graphene.hamiltonian(k_point[0], k_point[1])
    eigenvalues = np.linalg.eigvalsh(H)
    E_dirac.append(eigenvalues)
E_dirac = np.array(E_dirac)

ax6.plot(k_dir, E_dirac[:, 0], 'ro-', markersize=3, linewidth=1, label='Valence')
ax6.plot(k_dir, E_dirac[:, 1], 'bo-', markersize=3, linewidth=1, label='Conduction')
# 线性拟合
linear_fit = np.polyfit(k_dir[:20], E_dirac[:20, 1], 1)
ax6.plot(k_dir[:30], np.polyval(linear_fit, k_dir[:30]), 'g--', linewidth=2, label=f'Linear fit, slope={linear_fit[0]:.2f}')
ax6.set_xlabel('|k - K| (a.u.)', fontsize=11)
ax6.set_ylabel('Energy (eV)', fontsize=11)
ax6.set_title('Linear Dispersion near Dirac Point', fontsize=12, fontweight='bold')
ax6.legend()
ax6.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig(f'{output_dir}/case4_graphene_bands.png', dpi=150, bbox_inches='tight')
plt.close()

print("\n✓ 案例4完成:石墨烯电子性质计算")
print(f"  结果保存在: {output_dir}/case4_graphene_bands.png")

案例5:纳米流体传热仿真

纳米流体是将纳米颗粒分散在基液中形成的悬浮液,具有优异的传热性能。本案例模拟纳米流体的有效热导率。

物理模型

  • 采用Maxwell-Garnett有效介质理论
  • 考虑颗粒-基液界面热阻
  • 布朗运动对传热的贡献

有效热导率模型

keffkf=kp+2kf+2ϕ(kp−kf)kp+2kf−ϕ(kp−kf)\frac{k_{eff}}{k_f} = \frac{k_p + 2k_f + 2\phi(k_p - k_f)}{k_p + 2k_f - \phi(k_p - k_f)}kfkeff=kp+2kfϕ(kpkf)kp+2kf+2ϕ(kpkf)

其中keffk_{eff}keff为有效热导率,kpk_pkpkfk_fkf分别为颗粒和基液的热导率,ϕ\phiϕ为体积分数。

Python实现

# -*- coding: utf-8 -*-
"""
案例5:纳米流体传热仿真
计算纳米流体的有效热导率和温度分布
"""
import matplotlib
matplotlib.use('Agg')
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
import warnings
warnings.filterwarnings('ignore')
import os

output_dir = r'd:\\文档\\500仿真领域\\工程仿真\\多场耦合优化\\主题088\\output'
os.makedirs(output_dir, exist_ok=True)

plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

print("\n案例5:纳米流体传热仿真")
print("=" * 60)

class NanofluidHeatTransfer:
    """纳米流体传热仿真器"""
    
    def __init__(self, k_f=0.6, k_p=40, rho_f=1000, rho_p=3900, 
                 cp_f=4180, cp_p=765, mu_f=0.001):
        """
        初始化纳米流体参数
        k_f: 基液热导率 (W/m·K)
        k_p: 颗粒热导率 (W/m·K)
        rho_f, rho_p: 密度 (kg/m³)
        cp_f, cp_p: 比热容 (J/kg·K)
        mu_f: 基液粘度 (Pa·s)
        """
        self.k_f = k_f
        self.k_p = k_p
        self.rho_f = rho_f
        self.rho_p = rho_p
        self.cp_f = cp_f
        self.cp_p = cp_p
        self.mu_f = mu_f
        
    def maxwell_garnett(self, phi):
        """Maxwell-Garnett有效热导率模型"""
        numerator = self.k_p + 2*self.k_f + 2*phi*(self.k_p - self.k_f)
        denominator = self.k_p + 2*self.k_f - phi*(self.k_p - self.k_f)
        k_eff = self.k_f * numerator / denominator
        return k_eff
    
    def hamilton_crosser(self, phi, n=3):
        """Hamilton-Crosser模型 (非球形颗粒)"""
        psi = self.k_p / self.k_f
        k_eff = self.k_f * (psi + (n-1) + (n-1)*phi*(psi-1)) / \
                (psi + (n-1) - phi*(psi-1))
        return k_eff
    
    def brownian_motion_contribution(self, phi, T=300, d_p=50e-9):
        """布朗运动对热导率的贡献"""
        k_B = 1.38e-23  # 玻尔兹曼常数
        # 简化模型
        k_brownian = 5 * k_B * T * phi * self.rho_p * self.cp_p / \
                     (2 * np.pi * self.mu_f * d_p)
        return k_brownian
    
    def effective_properties(self, phi):
        """计算纳米流体的有效物性"""
        # 密度
        rho_eff = (1 - phi) * self.rho_f + phi * self.rho_p
        
        # 比热容 (质量加权)
        cp_eff = ((1-phi)*self.rho_f*self.cp_f + phi*self.rho_p*self.cp_p) / rho_eff
        
        # 热导率
        k_eff = self.maxwell_garnett(phi)
        
        # 热扩散系数
        alpha_eff = k_eff / (rho_eff * cp_eff)
        
        return rho_eff, cp_eff, k_eff, alpha_eff
    
    def heat_conduction_1d(self, phi, L=0.01, T_hot=350, T_cold=300, nx=100):
        """
        一维稳态热传导
        L: 通道长度 (m)
        T_hot, T_cold: 热端和冷端温度 (K)
        """
        _, _, k_eff, _ = self.effective_properties(phi)
        
        x = np.linspace(0, L, nx)
        # 线性温度分布
        T = T_hot - (T_hot - T_cold) * x / L
        
        # 热流密度
        q = k_eff * (T_hot - T_cold) / L
        
        return x, T, q, k_eff
    
    def transient_cooling(self, phi, L=0.01, T_init=350, T_ambient=300, 
                         h=100, t_max=100, nt=1000):
        """
        瞬态冷却过程
        h: 对流换热系数 (W/m²·K)
        """
        rho, cp, k, alpha = self.effective_properties(phi)
        
        dx = L / 50
        dt = 0.1
        nx = int(L / dx) + 1
        nt = int(t_max / dt) + 1
        
        x = np.linspace(0, L, nx)
        T = np.ones(nx) * T_init
        T[0] = T_ambient  # 边界条件
        T[-1] = T_ambient
        
        T_history = [T.copy()]
        
        for n in range(1, nt):
            T_new = T.copy()
            for i in range(1, nx-1):
                # 有限差分
                T_new[i] = T[i] + alpha * dt / dx**2 * (T[i+1] - 2*T[i] + T[i-1])
            T = T_new
            
            if n % 100 == 0:
                T_history.append(T.copy())
        
        return x, T_history

# 创建纳米流体模型
print("\n初始化纳米流体模型...")
nanofluid = NanofluidHeatTransfer()
print(f"基液热导率: {nanofluid.k_f} W/m·K")
print(f"颗粒热导率: {nanofluid.k_p} W/m·K")

# 计算不同体积分数下的热导率
print("\n计算有效热导率...")
phi_range = np.linspace(0, 0.1, 50)  # 0-10%体积分数
k_maxwell = []
k_hamilton = []

for phi in phi_range:
    k_maxwell.append(nanofluid.maxwell_garnett(phi))
    k_hamilton.append(nanofluid.hamilton_crosser(phi, n=3))

k_maxwell = np.array(k_maxwell)
k_hamilton = np.array(k_hamilton)

# 一维稳态热传导
print("计算稳态温度分布...")
x_0, T_0, q_0, k_0 = nanofluid.heat_conduction_1d(phi=0)
x_5, T_5, q_5, k_5 = nanofluid.heat_conduction_1d(phi=0.05)
x_10, T_10, q_10, k_10 = nanofluid.heat_conduction_1d(phi=0.10)

print(f"纯基液热导率: {k_0:.3f} W/m·K")
print(f"5%纳米流体热导率: {k_5:.3f} W/m·K (提升 {(k_5/k_0-1)*100:.1f}%)")
print(f"10%纳米流体热导率: {k_10:.3f} W/m·K (提升 {(k_10/k_0-1)*100:.1f}%)")

# 瞬态冷却
print("\n计算瞬态冷却过程...")
x_trans, T_history = nanofluid.transient_cooling(phi=0.05, t_max=50)

# 可视化结果
fig = plt.figure(figsize=(16, 12))

# 1. 有效热导率 vs 体积分数
ax1 = fig.add_subplot(2, 3, 1)
ax1.plot(phi_range * 100, k_maxwell / nanofluid.k_f, 'b-', linewidth=2, label='Maxwell-Garnett')
ax1.plot(phi_range * 100, k_hamilton / nanofluid.k_f, 'r--', linewidth=2, label='Hamilton-Crosser')
ax1.set_xlabel('Volume Fraction (%)', fontsize=11)
ax1.set_ylabel('$k_{eff}/k_f$', fontsize=11)
ax1.set_title('Effective Thermal Conductivity', fontsize=12, fontweight='bold')
ax1.legend()
ax1.grid(True, alpha=0.3)

# 2. 稳态温度分布
ax2 = fig.add_subplot(2, 3, 2)
ax2.plot(x_0 * 1000, T_0, 'b-', linewidth=2, label=f'Pure fluid (k={k_0:.2f})')
ax2.plot(x_5 * 1000, T_5, 'r-', linewidth=2, label=f'5% nanofluid (k={k_5:.2f})')
ax2.plot(x_10 * 1000, T_10, 'g-', linewidth=2, label=f'10% nanofluid (k={k_10:.2f})')
ax2.set_xlabel('Position (mm)', fontsize=11)
ax2.set_ylabel('Temperature (K)', fontsize=11)
ax2.set_title('Steady-State Temperature', fontsize=12, fontweight='bold')
ax2.legend()
ax2.grid(True, alpha=0.3)

# 3. 热流密度对比
ax3 = fig.add_subplot(2, 3, 3)
phi_test = np.array([0, 0.02, 0.04, 0.06, 0.08, 0.10])
q_values = []
for phi in phi_test:
    _, _, q, _ = nanofluid.heat_conduction_1d(phi)
    q_values.append(q)
q_values = np.array(q_values)

ax3.bar(phi_test * 100, q_values / q_values[0], color='steelblue', edgecolor='black', alpha=0.7)
ax3.set_xlabel('Volume Fraction (%)', fontsize=11)
ax3.set_ylabel('Heat Flux / Base', fontsize=11)
ax3.set_title('Heat Transfer Enhancement', fontsize=12, fontweight='bold')
ax3.grid(True, alpha=0.3, axis='y')

# 4. 瞬态温度分布
ax4 = fig.add_subplot(2, 3, 4)
times = [0, 2, 5, 10, 20, len(T_history)-1]
colors = plt.cm.coolwarm(np.linspace(0, 1, len(times)))
for i, t_idx in enumerate(times):
    if t_idx < len(T_history):
        ax4.plot(x_trans * 1000, T_history[t_idx], color=colors[i], 
                linewidth=2, label=f't = {t_idx*0.1*100:.0f} s')
ax4.set_xlabel('Position (mm)', fontsize=11)
ax4.set_ylabel('Temperature (K)', fontsize=11)
ax4.set_title('Transient Cooling (5% nanofluid)', fontsize=12, fontweight='bold')
ax4.legend(fontsize=9)
ax4.grid(True, alpha=0.3)

# 5. 有效物性汇总
ax5 = fig.add_subplot(2, 3, 5)
phi_props = np.linspace(0, 0.1, 20)
rho_eff_list = []
cp_eff_list = []
alpha_eff_list = []

for phi in phi_props:
    rho, cp, k, alpha = nanofluid.effective_properties(phi)
    rho_eff_list.append(rho)
    cp_eff_list.append(cp)
    alpha_eff_list.append(alpha * 1e6)  # 放大显示

ax5_twin = ax5.twinx()
line1 = ax5.plot(phi_props * 100, rho_eff_list, 'b-', linewidth=2, label='Density')
line2 = ax5.plot(phi_props * 100, cp_eff_list, 'r-', linewidth=2, label='Specific Heat')
line3 = ax5_twin.plot(phi_props * 100, alpha_eff_list, 'g--', linewidth=2, label='Thermal Diffusivity (×10⁶)')

ax5.set_xlabel('Volume Fraction (%)', fontsize=11)
ax5.set_ylabel('ρ (kg/m³), cp (J/kg·K)', fontsize=11)
ax5_twin.set_ylabel('α (×10⁻⁶ m²/s)', fontsize=11, color='g')
ax5.set_title('Effective Properties', fontsize=12, fontweight='bold')
ax5.grid(True, alpha=0.3)

# 合并图例
lines = line1 + line2 + line3
labels = [l.get_label() for l in lines]
ax5.legend(lines, labels, loc='center right')

# 6. 纳米颗粒分布示意图
ax6 = fig.add_subplot(2, 3, 6)
# 绘制简化的纳米流体微观结构
np.random.seed(42)
n_particles = 30
box_size = 10
particle_positions = np.random.rand(n_particles, 2) * box_size
particle_radii = np.random.uniform(0.2, 0.4, n_particles)

for pos, radius in zip(particle_positions, particle_radii):
    circle = Circle(pos, radius, color='red', alpha=0.6, edgecolor='darkred')
    ax6.add_patch(circle)

ax6.set_xlim(0, box_size)
ax6.set_ylim(0, box_size)
ax6.set_aspect('equal')
ax6.set_xlabel('X (nm)', fontsize=11)
ax6.set_ylabel('Y (nm)', fontsize=11)
ax6.set_title('Nanoparticle Distribution', fontsize=12, fontweight='bold')

plt.tight_layout()
plt.savefig(f'{output_dir}/case5_nanofluid_heat.png', dpi=150, bbox_inches='tight')
plt.close()

print("\n✓ 案例5完成:纳米流体传热仿真")
print(f"  结果保存在: {output_dir}/case5_nanofluid_heat.png")

案例6:DNA分子动力学模拟

DNA是存储遗传信息的生物大分子,其结构和动力学对理解生命过程至关重要。本案例模拟DNA双螺旋的简化模型。

物理模型

  • 粗粒化模型:每个碱基对用一个珠子表示
  • 碱基对间通过谐振势连接
  • 考虑氢键相互作用
  • 溶剂效应通过随机力模拟

Python实现

# -*- coding: utf-8 -*-
"""
案例6:DNA分子动力学模拟
模拟DNA双螺旋的简化粗粒化模型
"""
import matplotlib
matplotlib.use('Agg')
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.patches import FancyArrowPatch
from mpl_toolkits.mplot3d import proj3d
import warnings
warnings.filterwarnings('ignore')
import os

output_dir = r'd:\\文档\\500仿真领域\\工程仿真\\多场耦合优化\\主题088\\output'
os.makedirs(output_dir, exist_ok=True)

plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

print("\n案例6:DNA分子动力学模拟")
print("=" * 60)

class DNAMolecularDynamics:
    """DNA分子动力学模拟器(粗粒化模型)"""
    
    def __init__(self, n_base_pairs=50):
        """
        初始化DNA
        n_base_pairs: 碱基对数量
        """
        self.N = n_base_pairs
        
        # DNA几何参数
        self.rise = 0.34  # 碱基对上升距离 (nm)
        self.twist = 36 * np.pi / 180  # 每步扭转角 (rad)
        self.radius = 1.0  # 螺旋半径 (nm)
        
        # 力场参数
        self.k_backbone = 100.0  # 骨架弹簧常数
        self.k_hbond = 50.0  # 氢键弹簧常数
        self.k_bending = 30.0  # 弯曲刚度
        self.k_torsion = 20.0  # 扭转刚度
        
        # 质量
        self.mass = 300.0  # amu (每个碱基对)
        
        # 初始化位置
        self.build_dna_structure()
        
        # 速度初始化
        self.velocities = np.zeros((self.N, 3))
        self.forces = np.zeros((self.N, 3))
        
        # 记录
        self.trajectory = []
        self.energy_history = []
        
    def build_dna_structure(self):
        """构建B-DNA双螺旋结构"""
        self.positions = np.zeros((self.N, 3))
        
        for i in range(self.N):
            theta = i * self.twist
            z = i * self.rise
            
            # 双螺旋位置
            self.positions[i, 0] = self.radius * np.cos(theta)
            self.positions[i, 1] = self.radius * np.sin(theta)
            self.positions[i, 2] = z
        
        # 保存初始结构
        self.initial_positions = self.positions.copy()
    
    def compute_forces(self):
        """计算力"""
        self.forces.fill(0)
        potential = 0
        
        # 1. 骨架连接力 (相邻碱基对)
        for i in range(self.N - 1):
            r_vec = self.positions[i+1] - self.positions[i]
            r = np.linalg.norm(r_vec)
            
            if r > 0:
                # 谐振势
                dr = r - self.rise
                f_mag = -self.k_backbone * dr
                f_vec = f_mag * r_vec / r
                
                self.forces[i] -= f_vec
                self.forces[i+1] += f_vec
                potential += 0.5 * self.k_backbone * dr**2
        
        # 2. 弯曲力 (三体相互作用)
        for i in range(1, self.N - 1):
            r1 = self.positions[i] - self.positions[i-1]
            r2 = self.positions[i+1] - self.positions[i]
            
            # 计算角度
            cos_angle = np.dot(r1, r2) / (np.linalg.norm(r1) * np.linalg.norm(r2))
            cos_angle = np.clip(cos_angle, -1, 1)
            angle = np.arccos(cos_angle)
            
            # 弯曲势能
            potential += 0.5 * self.k_bending * angle**2
        
        # 3. 扭转力 (恢复原始扭转)
        for i in range(self.N - 1):
            # 简化的扭转恢复力
            current_twist = np.arctan2(self.positions[i+1, 1], self.positions[i+1, 0]) - \
                           np.arctan2(self.positions[i, 1], self.positions[i, 0])
            twist_diff = current_twist - self.twist
            
            # 切向力
            tangent = np.array([-self.positions[i, 1], self.positions[i, 0], 0])
            tangent = tangent / (np.linalg.norm(tangent) + 1e-10)
            
            f_torsion = -self.k_torsion * twist_diff * tangent
            self.forces[i] += f_torsion
            self.forces[i+1] -= f_torsion
        
        # 4. 氢键力 (保持双链配对 - 简化为径向恢复力)
        for i in range(self.N):
            r_xy = np.array([self.positions[i, 0], self.positions[i, 1]])
            current_radius = np.linalg.norm(r_xy)
            
            if current_radius > 0:
                dr = current_radius - self.radius
                f_radial = -self.k_hbond * dr * r_xy / current_radius
                self.forces[i, 0] += f_radial[0]
                self.forces[i, 1] += f_radial[1]
                potential += 0.5 * self.k_hbond * dr**2
        
        return potential
    
    def velocity_verlet(self, dt):
        """速度Verlet积分"""
        self.positions += self.velocities * dt + 0.5 * self.forces / self.mass * dt**2
        
        forces_old = self.forces.copy()
        pe = self.compute_forces()
        
        self.velocities += 0.5 * (forces_old + self.forces) / self.mass * dt
        
        ke = 0.5 * self.mass * np.sum(self.velocities**2)
        
        return pe, ke
    
    def langevin_dynamics(self, dt, gamma=0.1, T=300):
        """朗之万动力学(包含溶剂效应)"""
        k_B = 8.617e-5  # eV/K
        
        # 确定性力
        pe = self.compute_forces()
        
        # 随机力 (白噪声)
        random_force = np.random.randn(self.N, 3) * np.sqrt(2 * gamma * k_B * T / dt)
        
        # 总力
        total_force = self.forces + random_force - gamma * self.velocities * self.mass
        
        # 更新
        self.velocities += total_force / self.mass * dt
        self.positions += self.velocities * dt
        
        ke = 0.5 * self.mass * np.sum(self.velocities**2)
        
        return pe, ke
    
    def compute_persistence_length(self):
        """计算持久长度"""
        # 计算切向量相关函数
        tangents = np.zeros((self.N - 1, 3))
        for i in range(self.N - 1):
            t = self.positions[i+1] - self.positions[i]
            tangents[i] = t / np.linalg.norm(t)
        
        # 相关函数 <t(s)·t(0)> = exp(-s/Lp)
        correlations = []
        distances = []
        
        for s in range(1, min(20, self.N//2)):
            corr = np.mean([np.dot(tangents[i], tangents[i+s]) for i in range(self.N-1-s)])
            correlations.append(corr)
            distances.append(s * self.rise)
        
        # 拟合指数衰减
        if len(correlations) > 2:
            log_corr = np.log(np.maximum(correlations, 0.01))
            fit = np.polyfit(distances, log_corr, 1)
            Lp = -1 / fit[0]  # 持久长度
        else:
            Lp = 50  # 默认值
        
        return Lp, distances, correlations
    
    def run_simulation(self, n_steps=5000, dt=0.001):
        """运行模拟"""
        print(f"\n运行DNA动力学模拟...")
        print(f"碱基对数: {self.N}")
        print(f"模拟步数: {n_steps}")
        
        sample_interval = 50
        
        for step in range(n_steps):
            pe, ke = self.langevin_dynamics(dt, gamma=0.5, T=300)
            
            if step % sample_interval == 0:
                self.trajectory.append(self.positions.copy())
                self.energy_history.append(pe + ke)
            
            if step % 1000 == 0:
                print(f"  Step {step}/{n_steps}, Energy = {pe+ke:.2f} eV")
        
        print(f"\n模拟完成!")
        return self.trajectory

# 运行模拟
print("\n初始化DNA结构...")
dna = DNAMolecularDynamics(n_base_pairs=40)
print(f"碱基对数量: {dna.N}")
print(f"螺旋半径: {dna.radius} nm")
print(f"每步上升: {dna.rise} nm")
print(f"每步扭转: {dna.twist * 180/np.pi:.1f}°")

trajectory = dna.run_simulation(n_steps=3000, dt=0.001)

# 计算持久长度
print("\n计算持久长度...")
Lp, distances, correlations = dna.compute_persistence_length()
print(f"持久长度: {Lp:.1f} nm")

# 可视化结果
fig = plt.figure(figsize=(16, 12))

# 1. DNA 3D结构 - 初始
ax1 = fig.add_subplot(2, 3, 1, projection='3d')
pos_init = dna.initial_positions
ax1.plot(pos_init[:, 0], pos_init[:, 1], pos_init[:, 2], 
         'b-', linewidth=3, label='Backbone')
ax1.scatter(pos_init[:, 0], pos_init[:, 1], pos_init[:, 2], 
           c=np.arange(dna.N), cmap='viridis', s=50)
ax1.set_xlabel('X (nm)', fontsize=10)
ax1.set_ylabel('Y (nm)', fontsize=10)
ax1.set_zlabel('Z (nm)', fontsize=10)
ax1.set_title('Initial DNA Structure', fontsize=12, fontweight='bold')

# 2. DNA 3D结构 - 最终
ax2 = fig.add_subplot(2, 3, 2, projection='3d')
pos_final = dna.positions
ax2.plot(pos_final[:, 0], pos_final[:, 1], pos_final[:, 2], 
         'r-', linewidth=3, label='Backbone')
ax2.scatter(pos_final[:, 0], pos_final[:, 1], pos_final[:, 2], 
           c=np.arange(dna.N), cmap='plasma', s=50)
ax2.set_xlabel('X (nm)', fontsize=10)
ax2.set_ylabel('Y (nm)', fontsize=10)
ax2.set_zlabel('Z (nm)', fontsize=10)
ax2.set_title('Final DNA Structure', fontsize=12, fontweight='bold')

# 3. 能量演化
ax3 = fig.add_subplot(2, 3, 3)
energy_array = np.array(dna.energy_history)
steps = np.arange(len(energy_array)) * 50
ax3.plot(steps, energy_array, 'g-', linewidth=1.5)
ax3.set_xlabel('Step', fontsize=11)
ax3.set_ylabel('Total Energy (eV)', fontsize=11)
ax3.set_title('Energy Evolution', fontsize=12, fontweight='bold')
ax3.grid(True, alpha=0.3)

# 4. 持久长度计算
ax4 = fig.add_subplot(2, 3, 4)
if len(distances) > 0:
    ax4.plot(distances, correlations, 'bo', markersize=6, label='Simulation')
    # 指数拟合
    fit_exp = np.exp(-np.array(distances) / Lp)
    ax4.plot(distances, fit_exp, 'r-', linewidth=2, label=f'Fit: Lp={Lp:.1f} nm')
ax4.set_xlabel('Distance (nm)', fontsize=11)
ax4.set_ylabel('Correlation', fontsize=11)
ax4.set_title('Tangent Correlation', fontsize=12, fontweight='bold')
ax4.legend()
ax4.grid(True, alpha=0.3)

# 5. 末端距分布
ax5 = fig.add_subplot(2, 3, 5)
end_to_end_distances = []
for pos in trajectory:
    r_end = pos[-1] - pos[0]
    end_to_end_distances.append(np.linalg.norm(r_end))

end_to_end_distances = np.array(end_to_end_distances)
ax5.hist(end_to_end_distances, bins=20, color='steelblue', edgecolor='black', alpha=0.7)
ax5.axvline(x=np.mean(end_to_end_distances), color='r', linestyle='--', 
           linewidth=2, label=f'Mean: {np.mean(end_to_end_distances):.1f} nm')
ax5.set_xlabel('End-to-End Distance (nm)', fontsize=11)
ax5.set_ylabel('Frequency', fontsize=11)
ax5.set_title('End-to-End Distance Distribution', fontsize=12, fontweight='bold')
ax5.legend()
ax5.grid(True, alpha=0.3, axis='y')

# 6. 螺旋参数演化
ax6 = fig.add_subplot(2, 3, 6)
# 计算每步的半径和扭转
radii = []
twists = []
for pos in trajectory[::10]:  # 每10帧采样
    # 平均半径
    r_xy = np.sqrt(pos[:, 0]**2 + pos[:, 1]**2)
    radii.append(np.mean(r_xy))
    
    # 平均扭转角
    angles = np.arctan2(pos[:, 1], pos[:, 0])
    twist_per_step = np.mean(np.diff(angles))
    twists.append(twist_per_step * 180 / np.pi)

frames = np.arange(len(radii)) * 10 * 50
ax6.plot(frames, radii, 'b-', linewidth=2, label='Radius')
ax6.axhline(y=dna.radius, color='b', linestyle='--', alpha=0.5)
ax6_twin = ax6.twinx()
ax6_twin.plot(frames, twists, 'r-', linewidth=2, label='Twist angle')
ax6_twin.axhline(y=dna.twist*180/np.pi, color='r', linestyle='--', alpha=0.5)

ax6.set_xlabel('Step', fontsize=11)
ax6.set_ylabel('Radius (nm)', fontsize=11, color='b')
ax6_twin.set_ylabel('Twist angle (°)', fontsize=11, color='r')
ax6.set_title('Helical Parameters', fontsize=12, fontweight='bold')
ax6.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig(f'{output_dir}/case6_dna_dynamics.png', dpi=150, bbox_inches='tight')
plt.close()

print("\n✓ 案例6完成:DNA分子动力学模拟")
print(f"  结果保存在: {output_dir}/case6_dna_dynamics.png")

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐