layout: post title: 碳纳米管的构建方法 categories:
看到一篇老的文献Helical and rotational symmetries of nanoscale graphitic tubules, PRB, 1993, 47, 5485, 介绍了纳米管的构建方法, 就研究了一下, 弄明白了, 记在这里, 顺便写了个在线的小工具, 方便使用.
如果你在使用过程中发现问题, 欢迎告知.
碳纳米管可由石墨烯沿某一方向卷曲而成, 卷曲方向可以利用石墨烯六角形中心来定义, 如下图
两个平面晶格矢量为 $\vec R_1$ 和 $\vec R_2$, 设卷曲矢量为 $\vec R=m \vec R_1+n \vec R_2$, 为简单起见, 设 $m > n$, 这样每种卷成的纳米管类型都可以利用 $(m,n)$ 来表征, 这称为纳米管的指标.
设六边形的边长, 即碳碳之间的键长为 $a$, 则两个晶格矢量和卷曲矢量分别为:
$$\alg \vec R_1 &=(\sqrt 3 a, 0), &|\vec R_1|&=\sqrt 3 a \ \vec R_2 &=({\sqrt 3 a \over 2}, {3a \over 2}), &|\vec R_2|&=\sqrt 3 a = \abs{\vec R_1} \ \vec R &=m \vec R_1+n \vec R_2=({2m+n\over 2}\sqrt 3 a, {3n a \over 2}), &|\vec R| &=\sqrt{3(m^2+n^2+mn)}a \ \ealg$$
由此可得到纳米管的半径
$$r={|\vec R| \over 2\p}={\sqrt{3(m^2+n^2+mn)}a \over 2\p}$$
两个碳原子对应的矢量分别为 $\vec d$ 与 $2\vec d$, 其中
$$\vec d={1\over3}(\vec R_1+\vec R_2)=({\sqrt 3 a \over 2}, {a \over 2}), \abs{\vec d}=a$$
为方便后面的计算, 这里给出任意两个卷曲矢量的点积与矢量积
$$\alg \vec R &=(m,n) \ \vec v &=(x,y) \ \vec R \cdot \vec v &=m x |\vec R_1|^2+ny|\vec R_2|^2+(my+nx) \vec R_1 \cdot \vec R_2 =3a^2[(m+{n\over2})x+(n+{m\over2})y] \ \abs{\vec R \times \vec v} &= (my-nx) |\vec R_1 \times \vec R_2| ={3\sqrt 3\over2}a^2(my-nx)\ \ealg$$
卷曲后, 第一个碳原子的位置可随意设置, 第二个碳原子相对第一个碳原子的旋转角度为
$$\f={2\p(\vec d \cdot \vec R) \over |\vec R|^2}= {m+n \over m^2+n^2+mn}\p$$
这可看作是将 $\vec d$ 在平行于 $\vec R$ 方向的长度, 长度即决定了卷曲后的旋转角度.
第二个碳原子相对第一个碳原子的平移量为
$$\D h={|\vec d \times \vec R| \over |\vec R|}={m-n \over 2\sqrt{m^2+n^2+mn} }a$$
这可看作是 $\vec d$ 在垂直于 $\vec R$ 方向上的长度.
纳米管的最高旋转轴为 $C_N$, 其中 $N$ 为 $m$ 和 $n$ 的最大公约数.
卷成纳米管后, 除具有 $C_N$ 旋转对称性外, 还具有螺旋轴, 此螺旋轴的确定可以利用面积相等法. 首先存在一个矢量 $\vec H=(p,q)$ 满足
$$|\vec H \times \vec R|=N|\vec R_1 \times \vec R_2|$$
由此, 可得到下面的关系式
$$qm-pn=\pm N$$
由于我们前面已经假定 $m \ge n \ge 0$, 所以上式取正号, 且 $p \ge 0$, 这样就可以确定出 $p,q$ 的值, 由此得到螺旋轴的旋进角和螺距
$$\alg h &= {|\vec H \times \vec R| \over |\vec R|} = {3N \over 2\sqrt{m^2+n^2+mn} } a\ \a &= {2\p (\vec H \cdot \vec R|) \over |\vec R|} = {p(2m+n)+q(m+2n) \over m^2+n^2+mn } \p \ealg$$
注意到, $h$ 与 $\vec H$ 的选取无关,
$$h={|\vec H \times \vec R| \over |\vec R|} = N {|\vec R_1 \times \vec R_2| \over |\vec R|}$$
要达到整个周期, 此螺旋轴需要旋转的次数需满足
$$2 k \p = N_{\text{rot} } N \a$$
其中 $k$ 为正整数.
这样我们就得到了所有需要的量了.
纳米管基本单元的高度 $$H=N_\text{rot} h$$
其中的原子数 $$2 N N_\text{rot}$$
更长的纳米管只需要沿z轴周期性平移即可.
说明:
下面是(6, 3)碳纳米管构建的示意图即结构图, 用于对比
为了能将此方法用于构建其他纳米管体系, 如C-N纳米管, MoS2纳米管, 可以将原先的C原子替换为其他任意的一组原子, 只要二者采用的同样的坐标系坐标即可.
对C-N纳米管, 只要将其中一个点阵碳原子改为氮原子就可以了, 因为基本结构是一样的.
对MoS2纳米管, 有点复杂. MoS2晶体具有层状结构, 每层中原子都处于平面六边形的顶点上, 但z方向的高度不同.
<figure><script>var Mol1=new ChemDoodle.TransformCanvas3D('Mol-1',502,376.5);Mol1.specs.shapes_color='#fff';Mol1.specs.backgroundColor='black';Mol1.specs.set3DRepresentation('Ball and Stick');Mol1.specs.projectionPerspective_3D=false;Mol1.specs.compass_display=true; /*//Mol1.specs.atoms_resolution_3D=15; //Mol1.specs.bonds_resolution_3D=15; //Mol1.specs.crystals_unitCellLineWidth=1.5;*/ Mol1.nextFrame=function(delta){var matrix=[];ChemDoodle.lib.mat4.identity(matrix);var change=delta*Math.PI/15000;ChemDoodle.lib.mat4.rotate(matrix,change,[1,0,0]);ChemDoodle.lib.mat4.rotate(matrix,change,[0,1,0]);ChemDoodle.lib.mat4.rotate(matrix,change,[0,0,1]);ChemDoodle.lib.mat4.multiply(this.rotationMatrix, matrix)}; Mol1.startAnimation=ChemDoodle._AnimatorCanvas.prototype.startAnimation;Mol1.stopAnimation=ChemDoodle._AnimatorCanvas.prototype.stopAnimation;Mol1.isRunning=ChemDoodle._AnimatorCanvas.prototype.isRunning;Mol1.dblclick=ChemDoodle.RotatorCanvas.prototype.dblclick;Mol1.timeout=5;Mol1.handle=null; var Fmol='105\nMoS2\nS 1.828 0.000 10.697\nS 1.828 0.000 13.867\nMo 0.914 1.583 12.273\nS 1.828 -6.332 10.697\nS 1.828 -6.332 13.867\nMo 0.914 -4.749 12.273\nS 4.570 -7.915 10.697\nS 4.570 -7.915 13.867\nMo 3.656 -6.332 12.273\nS 7.312 -9.498 10.697\nS 7.312 -9.498 13.867\nMo 6.398 -7.915 12.273\nS 10.053 -11.081 10.697\nS 10.053 -11.081 13.867\nMo 9.139 -9.498 12.273\nS 12.795 -12.664 10.697\nS 12.795 -12.664 13.867\nMo 11.881 -11.081 12.273\nS 1.828 -3.166 10.697\nS 1.828 -3.166 13.867\nMo 0.914 -1.583 12.273\nS 4.570 -4.749 10.697\nS 4.570 -4.749 13.867\nMo 3.656 -3.166 12.273\nS 7.312 -6.332 10.697\nS 7.312 -6.332 13.867\nMo 6.398 -4.749 12.273\nS 10.053 -7.915 10.697\nS 10.053 -7.915 13.867\nMo 9.139 -6.332 12.273\nS 12.795 -9.498 10.697\nS 12.795 -9.498 13.867\nMo 11.881 -7.915 12.273\nS 4.570 -1.583 10.697\nS 4.570 -1.583 13.867\nMo 3.656 -0.000 12.273\nS 7.312 -3.166 10.697\nS 7.312 -3.166 13.867\nMo 6.398 -1.583 12.273\nS 10.053 -4.749 10.697\nS 10.053 -4.749 13.867\nMo 9.139 -3.166 12.273\nS 12.795 -6.332 10.697\nS 12.795 -6.332 13.867\nMo 11.881 -4.749 12.273\nS 1.828 3.166 10.697\nS 1.828 3.166 13.867\nMo 0.914 4.749 12.273\nS 4.570 1.583 10.697\nS 4.570 1.583 13.867\nMo 3.656 3.166 12.273\nS 7.312 0.000 10.697\nS 7.312 0.000 13.867\nMo 6.398 1.583 12.273\nS 10.053 -1.583 10.697\nS 10.053 -1.583 13.867\nMo 9.139 -0.000 12.273\nS 12.795 -3.166 10.697\nS 12.795 -3.166 13.867\nMo 11.881 -1.583 12.273\nS 1.828 6.332 10.697\nS 1.828 6.332 13.867\nMo 0.914 7.915 12.273\nS 4.570 4.749 10.697\nS 4.570 4.749 13.867\nMo 3.656 6.332 12.273\nS 7.312 3.166 10.697\nS 7.312 3.166 13.867\nMo 6.398 4.749 12.273\nS 10.053 1.583 10.697\nS 10.053 1.583 13.867\nMo 9.139 3.166 12.273\nS 12.795 -0.000 10.697\nS 12.795 -0.000 13.867\nMo 11.881 1.583 12.273\nS 1.828 9.498 10.697\nS 1.828 9.498 13.867\nMo 0.914 11.081 12.273\nS 4.570 7.915 10.697\nS 4.570 7.915 13.867\nMo 3.656 9.498 12.273\nS 7.312 6.332 10.697\nS 7.312 6.332 13.867\nMo 6.398 7.915 12.273\nS 10.053 4.749 10.697\nS 10.053 4.749 13.867\nMo 9.139 6.332 12.273\nS 12.795 3.166 10.697\nS 12.795 3.166 13.867\nMo 11.881 4.749 12.273\nS 1.828 12.664 10.697\nS 1.828 12.664 13.867\nMo 0.914 14.247 12.273\nS 4.570 11.081 10.697\nS 4.570 11.081 13.867\nMo 3.656 12.664 12.273\nS 7.312 9.498 10.697\nS 7.312 9.498 13.867\nMo 6.398 11.081 12.273\nS 10.053 7.915 10.697\nS 10.053 7.915 13.867\nMo 9.139 9.498 12.273\nS 12.795 6.332 10.697\nS 12.795 6.332 13.867\nMo 11.881 7.915 12.273\n'; Mol1.loadMolecule(ChemDoodle.readXYZ(Fmol));Mol1.startAnimation();Mol1.stopAnimation();function setProj1(yesPers){Mol1.specs.projectionPerspective_3D=yesPers;Mol1.setupScene();Mol1.repaint()}function setModel1(model){Mol1.specs.set3DRepresentation(model);Mol1.setupScene();Mol1.repaint()}function setSpeed1(){Mol1.timeout=500-document.getElementById('spd1').value;Mol1.loadMolecule(ChemDoodle.readXYZ(Fmol));Mol1.startAnimation()}</script><br><span class='meta'>视图: <input type='radio' name='group2' onclick='setProj1(true)'>投影 <input type='radio' name='group2' onclick='setProj1(false)' checked=''>正交 速度: <input type='range' id='spd1' min='1' max='500' onchange='setSpeed1()'/><br>模型: <input type='radio' name='model' onclick='setModel1('Ball and Stick')' checked=''>球棍 <input type='radio' name='model' onclick='setModel1('van der Waals Spheres')'>范德华球 <input type='radio' name='model' onclick='setModel1('Stick')'>棍状 <input type='radio' name='model' onclick='setModel1('Wireframe')'>线框 <input type='radio' name='model' onclick='setModel1('Line')'>线型 <input type='checkbox' onclick='Mol1.specs.atoms_displayLabels_3D=this.checked;Mol1.repaint()'>名称<br>左键: 转动 滚轮: 缩放 双击: 自动旋转开关 Alt+左键: 移动</span><br><figurecaption>Fig.1</figurecaption></figure>MoS2的晶格参数a=3.160 Å(即Mo-Mo键长), 2z=3.172 Å(z方向S-S距离), 由此, 可以得到六边形边长为 a/sqrt(3)=3.16/sqrt(3)=1.8244 Å, 以Mo原子为基准(0, 0, 0)时, 两个S原子的相对坐标为(0, 0, z), (0, 0, -z). 故此, 两个点阵点为
Mo 0 0 0
以及
S 0 0 -1.586
S 0 0 1.586
参考
类型指标:m <input type="box" id="wid" value="6" style="width:60px;"/> n <input type="box" id="hig" value="3" style="width:60px;"/> <br/> 基本单元数:<input type="box" id="cell" value="1" style="width:60px;"/> 六边形边长/C-C键长(Å):<input type="box" id="rcc" value="1.4" style="width:60px;"/> <br/> 径向位置随机(Å):X方向:<input type="box" id="ranX" value="0" style="width:60px;"/> Y方向:<input type="box" id="ranY" value="0" style="width:60px;"/> <br/>
<table><tr> <td> 第一点阵点原子坐标<br/><textarea id="xyzP1" style="width:140px; height:150px; resize: none">C 0 0 0</textarea></td> <td> 第二点阵点原子坐标<br/><textarea id="xyzP2" style="width:140px; height:150px; resize: none">C 0 0 0</textarea></td> </tr></table><input type="button" value="创建" onClick="genCoor()" style="width:100px; height:30px" /> <br/>
纳米管半径(Å):<input type="box" id="Radius" value="" style="width:60px;"/> 纳米管高度(Å):<input type="box" id="Height" value="" style="width:60px;"/> 纳米管总原子数:<input type="box" id="Ntot" value="" style="width:60px;"/> <br/> 基本单元高度(Å):<input type="box" id="Hcell" value="" style="width:60px;"/> 基本单元原子数:<input type="box" id="Natm" value="" style="width:60px;"/> <br/> 第二原子偏移(Å):<input type="box" id="Trs" value="" style="width:60px;"/> 第二原子转角(π):<input type="box" id="Phi" value="" style="width:60px;"/><br/> 螺旋轴螺距(Å):<input type="box" id="Sh" value="" style="width:60px;"/> 螺旋轴旋进角(π):<input type="box" id="Sa" value="" style="width:60px;"/> 旋转次数:<input type="box" id="Nrot" value="" style="width:60px;"/> <br/> (m, n):<input type="box" id="mn" value="" style="width:60px;"/> (p, q):<input type="box" id="pq" value="" style="width:60px;"/> gcd(m, n):<input type="box" id="Ngcd" value="" style="width:60px;"/> qm-pn:<input type="box" id="qmpn" value="" style="width:60px;"/> <br/>
<table><tr> <td> XYZ文件<br/><textarea id="xyzCoor" style="width:400px; height:500px; resize: none"></textarea></td> <td> <figure><figurecaption>结构</figurecaption><br/> <script> var Mol=new ChemDoodle.TransformCanvas3D('Mol-2', 400,500); Mol.specs.backgroundColor='black'; Mol.specs.set3DRepresentation('Ball and Stick'); Mol.specs.projectionPerspective_3D = false; Mol.loadMolecule(ChemDoodle.readXYZ("", 2)); </script></td> </tr></table><script> var $=function(id){return document.getElementById(id)}; function norm(s){return s.replace(/^\s*\n*/,'').replace(/\s*\n*$/,'').replace(/\s+[\n|$]/g,'\n')} function genCoor() { var Pi=Math.PI, TwoPi=2*Pi, Rad=180./Pi, i=0, j=0, k=0, tmp, txt, X0, Y0 var m=parseInt($("wid").value), n=parseInt($("hig").value), a=parseFloat($("rcc").value), Ncell=parseFloat($("cell").value), Xran=parseFloat($("ranX").value), Yran=parseFloat($("ranY").value) var Sp1=[], Xp1=[], Yp1=[], Zp1=[], Sp2=[], Xp2=[], Yp2=[], Zp2=[] txt=norm($('xyzP1').value).split('\n'); Np1=txt.length for(i=0; i<Np1; i++) { tmp=txt[i].split(/\s+/) Sp1[i]=tmp[0]; Yp1[i]=tmp[1] Zp1[i]=tmp[2]; Xp1[i]=tmp[3] } txt=norm($('xyzP2').value).split('\n'); Np2=txt.length for(i=0; i<Np2; i++) { tmp=txt[i].split(/\s+/) Sp2[i]=tmp[0]; Yp2[i]=tmp[1] Zp2[i]=tmp[2]; Xp2[i]=tmp[3] } if(m<n) { i=m; m=n; n=i } var Rtmp=m*m+n*n+m*n, R=Math.sqrt(3*Rtmp)*a/TwoPi, Phi=(m+n)*Pi/Rtmp, Trs=(m-n)*a/(2*Math.sqrt(Rtmp)) var Ngcd=gcd(m,n) var theta = TwoPi/Ngcd var p=0, q=0 while((Ngcd+p*n)%m != 0) { p++ } var q = (Ngcd+p*n)/m var h = 3*Ngcd*a/(2*Math.sqrt(Rtmp)), alpha = Pi*(p*(2*m+n)+q*(m+2*n))/Rtmp var Nrot=0 if(n==0 || m==n) Nrot = 2 else { k = 1 while((2*k*Rtmp)%(Ngcd*(p*(2*m+n)+q*(m+2*n)))!=0) { k++ } Nrot=(2*k*Rtmp)/(Ngcd*(p*(2*m+n)+q*(m+2*n))) } var Hcell = Nrot*h, Natm = Nrot * (Np1+Np2) * Ngcd, Ntot = Natm * Ncell $("Radius").value = R $("Height").value= Ncell*Hcell $("Ntot").value=Ntot $("Hcell").value=Hcell $("Natm").value=Natm i=gcd(m+n, Rtmp); $("Phi").value= (m+n)/i+"/"+Rtmp/i $("Trs").value= Trs $("mn").value="("+m+", "+n+")" $("pq").value="("+p+", "+q+")" $("Ngcd").value=Ngcd $("qmpn").value=q*m-p*n $("Sh").value=h i=gcd(p*(2*m+n)+q*(m+2*n), Rtmp); $("Sa").value=(p*(2*m+n)+q*(m+2*n))/i+"/"+Rtmp/i $("Nrot").value=Nrot var ii, Iatm, Satm=[], Xatm=[], Yatm=[], Zatm=[] for(i=0; i<Ncell; i++) { for(j=0; j<Nrot; j++) { for(k=0; k<Ngcd; k++) { Iatm=Natm*i+(Np1+Np2)*Ngcd*j+(Np1+Np2)*k+1 tmp=k*theta+(j+i*Nrot)*alpha for(ii=0; ii<Np1; ii++) { X1=R+parseFloat(Xp1[ii]) Y1= parseFloat(Yp1[ii]) Satm[Iatm+ii] = Sp1[ii] Xatm[Iatm+ii] = X1*Math.cos(-tmp)-Y1*Math.sin(-tmp) Yatm[Iatm+ii] = X1*Math.sin(-tmp)+Y1*Math.cos(-tmp) Zatm[Iatm+ii] = parseFloat(Zp1[ii])+i*Hcell+j*h } X1 = R*Math.cos(-tmp) Y1 = R*Math.sin(-tmp) for(ii=0; ii<Np2; ii++) { X1=R+parseFloat(Xp2[ii]) Y1= parseFloat(Yp2[ii]) X2 = X1*Math.cos(-tmp)-Y1*Math.sin(-tmp) Y2 = X1*Math.sin(-tmp)+Y1*Math.cos(-tmp) Satm[Iatm+Np1+ii]=Sp2[ii] Xatm[Iatm+Np1+ii] = X2*Math.cos(Phi) + Y2*Math.sin(Phi) Yatm[Iatm+Np1+ii] =-X2*Math.sin(Phi) + Y2*Math.cos(Phi) Zatm[Iatm+Np1+ii] = parseFloat(Zp2[ii])+i*Hcell+j*h + Trs } } } } var Fmol=printf('%f\nType: (%f,%f) R: %10.6f Box: %10.6f %10.6f %10.6f\n', Ntot, m, n, a, 2*R, 2*R, Ncell*Hcell) for(i=1; i<=Ntot; i++) { X0 = Xatm[i]; Y0 = Yatm[i] if(Xran) X0 += Math.random()*Xran if(Yran) Y0 += Math.random()*Yran Fmol += printf('%-3s %12.6f %12.6f %12.6f\n', Satm[i], X0, Y0, Zatm[i]) } $("xyzCoor").value=Fmol Mol.loadMolecule(ChemDoodle.readXYZ(Fmol, 2)); } function gcd(a, b) { // http://zh.wikipedia.org/wiki/辗转相除法 var tmp=0 while(b!=0) { tmp=b; b=a%b; a=tmp } return a } function printf(){ var map = { s: function(str, fmt) { fmt*=1; var m=Array(Math.max(Math.abs(fmt)-str.length+1,0)).join(' '); return fmt>0 ? m+str : str+m}, f: function(str, fmt) { fmt=fmt.split('.'); str=parseFloat(str).toFixed(fmt[1]); var m=Array(Math.max(Math.abs(fmt[0])-str.length+1, 0)).join(' ') return fmt[0]>0 ? m+str : str+m } } var args = Array.prototype.slice.call(arguments).slice(), fmt, type return args.shift().toString().replace(/%(-*\d*\.*\d*)([sf])/g, function(_, fmt, type){ if(!args.length) throw new Error('Too few elements') return map[type](args.shift(), fmt); }); } </script>