|
本帖最后由 granvia 于 2019-7-10 21:41 编辑
参考了32楼和21楼的两种算法(它们之间并不等价或包含),我觉得可以提出更一般性的算法,如下:
设所要寻找的正交超胞的基矢为:u = m1*a + n1*b,v = m2*a + n2*b,则根据 u.v = 0 可得:m1*m2 + n1*n2*s + (m1*n2 + m2*n1)*s*cos(t) = 0,其中 s = |b|/|a|,t为a与b夹角。这个超胞的面积是原来晶胞的(m1*n2-m2*n1)倍。
当m1 = m2 = M,n1 = N,n2 = -N时,得到32楼提出的解;当m1 = m, m2 = -m,n1 = 0, n2 = n时,得到21楼提出的解。 但显然,存在更多可能的(m1,m2,n1,n2)组合,满足上述方程。 在给定精度下,这个四参数的近似解(m1,m2,n1,n2)有可能比32楼的(M,N)和21楼(m,n)解给出更小的超胞。换句话说,利用这个更一般性的方程,可以得到给定精度下的最优解。在算法上可以枚举搜索所有的m1,m2,n1,n2的整数组合,在满足精度要求下,找到使得(m1*n2-m2*n1)为最小正值的组合。至于精度,可以定义一个误差函数为:
f = [ m1*m2 + n1*n2*s + (m1*n2 + m2*n1)*s*cos(t) ] / sqrt(m1^2 + n1^2*s^2 + 2*m1*n1*s*cos(t)) / sqrt( m2^2 + n2^2*s^2 + 2*m2*n2*s*cos(t) )
其中多出来的两个分母sqrt(...)是将u和v归一化的结果。据此,我们只需搜索所有满足 f <= err (精度)且使(m1*n2-m2*n1)为最小正值的(m1,m2,n1,n2)组合即可。
将这个算法应用于26楼的例子,结果如下(A表示超胞大小是原来晶胞的A倍):
当精度为0.1时,m1 = 1; m2 = 1; n1 = -2; n2 = 1; A = 3; f = -3.1E-02
当精度为0.01时,m1 = 0; m2 = 5; n1 = -1; n2 = 1; A = 5; f = 7.2E-03
当精度为0.001时,m1 = 1; m2 = 5; n1 = -4; n2 = 3; A = 23; f = 9.7E-04
当精度为0.0001时,m1 = 3; m2 = -5; n1 = 2; n2 = 17; A = 61; f = 5.4E-05
(。。。我们可以将精度任意提高下去。。。)
可见,以上算法给出的最优超胞都不是32楼或21楼能给出的解,因此更具有一般性。当精度要求不高(0.01)时,只需扩胞5倍就能可以得到近似模型了。
具体MATLAB代码如下(为简便起见,只打印出一种可能的最优解):
- function findOthroCell()
- % a=16.811 Angstrom, b=4.7281 Angstrom, c=9.886 Angstrom, beta=101.950, alpha=gamma=90 Deg.
- a = 16.811;
- b = 9.886;
- t = 101.950/180*pi;
- Err = 1e-4;
- Mmax = 10;
- Nmax = 10;
- s = b/a;
- st = s*cos(t);
- Amin = Inf;
- for m1 = 0 : Mmax
- for n1 = -Nmax : Nmax
- % a' = m1*a + n1*b != 0
- if( m1 == 0 && n1 == 0 )
- continue;
- end
-
- % Length of new basis vector a:
- len1 = sqrt( m1^2 + n1^2*s^2 + 2*m1*n1*st );
-
- for m2 = -Mmax : Mmax
- for n2 = -Nmax : Nmax
- % b' = m2*a + n2*b != 0
- if( m2 == 0 && n2 == 0 )
- continue;
- end
-
- % Length of new basis vector b:
- len2 = sqrt( m2^2 + n2^2*s^2 + 2*m2*n2*st );
-
- % Precision:
- f = (m1*m2 + n1*n2*s + (m1*n2 + m2*n1)*st)/len1/len2;
- if( abs(f) > Err )
- continue
- end
-
- A = m1*n2-m2*n1; % Area in units of original cell area
- if( A <= 0 )
- continue;
- end
- fprintf( 'm1 = %4i; m2 = %4i; n1 = %4i; n2 = %4i; ', ...
- m1, m2, n1, n2 );
- fprintf( ' err = %10.1E; A = %12.6f Amin = %12.6f', ...
- f, A, Amin );
- if( A < Amin )
- Amin = A;
- m1_opt = m1;
- n1_opt = n1;
- m2_opt = m2;
- n2_opt = n2;
- f_opt = f;
- fprintf( '(NEW Amin)' );
- end
- fprintf( '\n' );
- end
- end
- end
- end
- fprintf( 'Optimal supercell within error of %.1E:\n', Err );
- fprintf( 'm1 = %i; m2 = %i; n1 = %i; n2 = %i; A = %i; f = %.1E\n', ...
- m1_opt, m2_opt, n1_opt, n2_opt, Amin, f_opt );
- end
复制代码
|
|