
!$OMP DO REDUCTION(+:ZFORC2)ZFORC2が足し上げ対象となる変数。この1行がなかったために、毎回計算す るたびに異なった結果(力の値)を与えていました。
REAL TOTAL CHARGE = 80.0026633146275827 IN XCFFT本当の総電子数は80個/ユニットセルですが何故か、0.0026633146275827 とゴミのような余計な部分が出てきます。もし正しく総電子数が求まるなら、 以下のような値になります。
REAL TOTAL CHARGE = 80.0000000000007 IN XCFFTゴミ(誤差)部分は無視出来るほど小さな値になります。この問題は、これ までとは異なる数値演算ライブラリのFFTルーチンを利用した場合に起こりま した。当初は、これに全く気付きませんでした。それは総電子数にゴミがある のに、全エネルギーなど他の値に問題が生じなかった(総電子数が正しく出る 場合と値が完全に一致する)ためです。こんなに電子数の値に違いがあるのに、 何で全エネルギー等が一致するのが最初不思議でした(後述。←現在でも完全 に裏付けは取れていない)。で、結局原因と思われる部分として以下のルーチ ンが浮かび上がりました。このルーチンの一番外側のIF文の中にあるIF文、 "IF ( MOD(I,IFX2).NE.0 ) THEN"ですが、これはFFTにおけるメッシュに関係 するもので、筆者が元々使用していたFTTルーチン(MFFT)では、3次元複素フー リエ変換において、メッシュ数:IFX2が2n-1でした(nは適当な正の整数)。 FFTとして使用するメッシュは、2n-2個分必要で、それより一つメッシュが多 い仕様でした。従って、2n+1番目のFFT用の配列は、実際の物理量の計算には 関わらない部分なので、総電子数計算の際に相当する部分の電荷密度の値 (CHGB1(I ← IFX2))をゼロとしました。ただ、以下のルーチンでは問題があ ります。一番外側のIF判定は、CHGB1がゼロ以下の場合という制限を与えてい ます。従って、そうでない場合、次のIF判定である、"IF ( MOD(I,IFX2).NE.0 ) THEN"が意味を持ちません。
ICCCC=0
DO 20 I=1,KSUM
IF( CHGB1(I).LE.0.0D0 ) THEN
IF ( MOD(I,IFX2).NE.0 ) THEN
IF ( CHGB1(I).LE.-1.0D-5 ) THEN
WRITE(6,610) I,CHGB1(I)
610 FORMAT(1H ,'**WARNING CHG.DEN<0.0 AT ',
& I5,2D15.7,'***')
ICCCC=ICCCC+1
END IF
CHGB1(I) = 1.D-40
ELSE
CHGB1(I) = 1.D-40
END IF
END IF
20 CONTINUE
S = 0.D0
DO 1010 I=1,KSUM
S = S+CHGB1(I)
1010 CONTINUE
S=S*VCEL - SCHGPC
IF (MOD(ITER,10).EQ.0) THEN
WRITE (6,*) 'REAL TOTAL CHARGE = ',S,' IN XCFFT'
END IF
この問題の解決は、以下のようにルーチンを変更することによって達成され
ます。
ICCCC=0
DO 20 I=1,KSUM
IF( CHGB1(I).LE.0.0D0 ) THEN
IF ( CHGB1(I).LE.-1.0D-5 ) THEN
WRITE(6,610) I,CHGB1(I)
610 FORMAT(1H ,'**WARNING CHG.DEN<0.0 AT ',
& I5,2D15.7,'***')
ICCCC=ICCCC+1
END IF
CHGB1(I) = 1.D-40
END IF
IF ( MOD(I,IFX2).EQ.0 ) THEN
CHGB1(I) = 1.D-40
END IF
20 CONTINUE
S = 0.D0
DO 1010 I=1,KSUM
S = S+CHGB1(I)
1010 CONTINUE
S=S*VCEL - SCHGPC
IF (MOD(ITER,10).EQ.0) THEN
WRITE (6,*) 'REAL TOTAL CHARGE = ',S,' IN XCFFT'
END IF
以上にあるように、2n+1であることを判定するIF文(深紅色部分)を独立さ
せてやれば、総電子数の値に現れるゴミ数値の問題は起こらなくなります。
25.9099482945 0.0000000000 0.0000000000
0.0000000000 4.7796946433 0.0000000000
0.0000000000 2.3898473216 4.1393369833
0 COORDINATES 0:NORMALIZED 1:CARTESIAN
0.2500000000 0.0000000000 0.0000000000
0.7500000000 0.0000000000 0.0000000000
0.0000557124 0.3333333333 0.3333333333
-0.0000557124 0.6666666667 0.6666666667
0.4999442876 0.3333333333 0.3333333333
0.5000557124 0.6666666667 0.6666666667
0.2500000000 0.3333333333 0.3333333333
0.7500000000 0.6666666667 0.6666666667
となります。上記は既に構造最適化を終了しています。" 0 COORDINATES
0:NORMALIZED 1:CARTESIAN "の行以降が原子座標で、最初の6行が炭素(6個)、
最後の7、8行がホウ素(2個)です(以下同じ)。" 0 COORDINATES
0:NORMALIZED 1:CARTESIAN "行の上にある数値は、格子座標です。座標は、筆
者の計算では(z,x,y)となっています。従って、一番左側の数値がc軸(=z軸)
のものです。また、"0.6666666667 0.6666666667"というような表現も一般的
でありません。通常は、"0.6666666667 0.3333333333"などと表現します。
0.2500000000 0.0000000000 0.0000000000
0.2500000000 0.3333333333 0.3333333333
0.7500000000 0.0000000000 0.0000000000
0.7500000000 0.6666666667 0.6666666667
0.0000000000 0.3333333333 0.3333333333
0.5000000000 0.3333333333 0.3333333333
0.0000000000 0.6666666667 0.6666666667
0.5000000000 0.6666666667 0.6666666667
を考え、あるコード(←筆者のものでない)で結晶対称性を判定をしたとこ
ろ、187番(P6m2←本当は数字6の上にバーが付く)という解答でした。と
ころが、筆者のバンド計算プログラムコードで187番の結晶対称性として計
算させようとすると、結晶対称性判定部分で止まってしまいました。筆者のコー
ドは結晶対称性の処理に不完全なところがあり、他の対称性では上記座標でも
計算が通ってしまうのですが、この場合、計算結果が明らかにおかしなものと
なります。この問題に際して、当初は結晶対称性に関してのオペレーター(演
算子)の設定が筆者のコード上で間違っているのではないかと、検証、検討を
試みました。とにかく、判定を通るように強引な設定で計算を走らせてみたり
とか、187番の対称性は、P6/mmm対称性からインバージョン(反転)を除い
たものなので、P6/mmmで強引に計算させてみたりしましたが、どれもうまく行
きませんでした。
(1) 元の原子座標
0.2500000000 0.0000000000 0.0000000000
0.2500000000 0.3333333333 0.3333333333
0.7500000000 0.0000000000 0.0000000000
0.7500000000 0.6666666667 0.6666666667
0.0000000000 0.3333333333 0.3333333333
0.5000000000 0.3333333333 0.3333333333
0.0000000000 0.6666666667 0.6666666667
0.5000000000 0.6666666667 0.6666666667
(2) x,y座標を、0.3333333333だけずらす。
0.2500000000 0.3333333333 0.3333333333
0.2500000000 0.6666666667 0.6666666667
0.7500000000 0.3333333333 0.3333333333
0.7500000000 0.0000000000 0.0000000000
0.0000000000 0.6666666667 0.6666666667
0.5000000000 0.6666666667 0.6666666667
0.0000000000 0.0000000000 0.0000000000
0.5000000000 0.0000000000 0.0000000000
(3) z座標を、0.25だけずらす。
0.5000000000 0.3333333333 0.3333333333
0.5000000000 0.6666666667 0.6666666667
0.0000000000 0.3333333333 0.3333333333
0.0000000000 0.0000000000 0.0000000000
0.2500000000 0.6666666667 0.6666666667
0.7500000000 0.6666666667 0.6666666667
0.2500000000 0.0000000000 0.0000000000
0.7500000000 0.0000000000 0.0000000000
(4) 単なる並べ替え。
0.0000000000 0.3333333333 0.3333333333
0.0000000000 0.0000000000 0.0000000000
0.5000000000 0.3333333333 0.3333333333
0.5000000000 0.6666666667 0.6666666667
0.2500000000 0.6666666667 0.6666666667
0.7500000000 0.6666666667 0.6666666667
0.2500000000 0.0000000000 0.0000000000
0.7500000000 0.0000000000 0.0000000000
(5) 単なる並べ替え。
0.0000000000 0.0000000000 0.0000000000
0.0000000000 0.3333333333 0.3333333333
0.5000000000 0.3333333333 0.3333333333
0.5000000000 0.6666666667 0.6666666667
0.2500000000 0.6666666667 0.6666666667
0.7500000000 0.6666666667 0.6666666667
0.2500000000 0.0000000000 0.0000000000
0.7500000000 0.0000000000 0.0000000000
上記の最後の原子座標と、最初の原子座標は等価なものです。ただ、最後の
もの(5)では、座標(0,0,0)に炭素原子が置かれているようになっています。対
称性に関してのオペレーターは、対象となる原子座標の配置による影響を受け
るため、正しい配置にしておかないと、判定に失敗したり、正しい計算が出来
ないということがこれで分かりました(←もっと早く認識すべきだった)。
DO 500 II=1,KTYP
ETOT1 = ETOT1 + FLOAT(IATOM(II))*PAI*ACHG(II)
& * ( AC(II,1)/BC(II,1) + AC(II,2)/BC(II,2) )/UNIVOL
TOTCH=TOTCH + FLOAT(IATOM(II))*ACHG(II)
C
IF (ITER.EQ.0) THEN
IF (NLSPD(II).EQ.1) THEN
READ(16,*) MESHR,NMES,DX,RAD,VD,VDNL
DO 1210 N=1,MESHR
VDD(N,II)=VD(N)
VDDNL(N,II)=VDNL(N)
1210 CONTINUE
ELSE
DO 1212 N=1,MESHR
VDD(N,II) =0.0D0
VDDNL(N,II)=0.0D0
1212 CONTINUE
END IF
ELSE
DO 1211 N=1,MESHR
VD(N)=VDD(N,II)
VDNL(N)=VDDNL(N,II)
1211 CONTINUE
END IF
C
S=0.0D0
DO 1200 N=1,MESHR
S=S + OMO(N)*VDNL(N)*(RAD(N)**3)
1200 CONTINUE
色(深紅)のついた配列VDNLですが、実は
これが正しくゼロ初期化できないことがバグの原因でした。と初期化をきちんとすれば問題は解決します。
DO 1212 N=1,MESHR VDD(N,II) =0.0D0 VDDNL(N,II)=0.0D0 VDNL(N) =0.0D0 1212 CONTINUE
READ(20,*) KVZ(NNN),KVY(NNN),KVX(NNN),KQWGT(NNN)
本来は、KVX(NNN),KVY(NNN),KVZ(NNN)というk点座標の並びを、READ文で読
み込む時の配列の並びを、KVZ(NNN),KVY(NNN),KVX(NNN)として、KVX(NNN)→
KVZ(NNN)、KVZ(NNN)→KVX(NNN)となるようにしました。
READ(61,*) KVZ(NNN),KVY(NNN),KVX(NNN),KQWGT(NNN)
としてしまいました。これは変換を2度行なっている(つまり、x→z→x)
ことであり、元に戻していることに他なりません。
READ(61,*) KVX(NNN),KVY(NNN),KVZ(NNN),KQWGT(NNN)
とすると、比較すべき正しい結果と、計算結果の一致を見ることができまし
た。
13.1338124721 0.0000000000 0.0000000000
0.0000000000 5.1692358601 0.0000000000
0.0000000000 2.5846179299 4.4766895732
のように与えています。これに対応する逆空間での格子座標は、
0.478398 0.000000 0.000000 0.000000 1.215496 -0.701767 0.000000 0.000000 1.403534です。バグの説明のところでも述べましたが、x座標がc軸となっています。 ここでy、z座標の取り方に、上記とは異なる取り方があります。それは実空間 格子座標では、
13.1338124721 0.0000000000 0.0000000000
0.0000000000 2.5846179299 -4.4766895732
0.0000000000 2.5846179299 4.4766895732
という取り方です。これに対応する逆空間格子座標は、
0.478398 0.000000 0.000000 0.000000 1.215496 -0.701767 0.000000 1.215496 0.701767となります。基のk点の取り方が、整数表示になっていたので、上記逆空間 格子座標を使って、目的のk点座標を求めることが出来ます。以下に、座標を 変換している部分を示します。
C
READ(60,*) KVX(NNN),KVY(NNN),KVZ(NNN),KQWGT(NNN) ←読み込み(整数)
C
KQSUM = KQSUM + KQWGT(NNN)
C
VX(NNN) = DFLOAT(KVX(NNN))/24.0D0 ←実数化
VY(NNN) = DFLOAT(KVY(NNN))/24.0D0
VZ(NNN) = DFLOAT(KVZ(NNN))/24.0D0
QWGT(NNN) = DFLOAT(KQWGT(NNN))/DFLOAT(KKX*KKY*KKZ)
C
C R22 = RLTV(2,2)
C R23 = RLTV(2,3)
C R32 = RLTV(3,2)
C R33 = RLTV(3,3)
R22 = RLTV(2,2) ←座標変換1
R23 = RLTV(2,2)
R32 = RLTV(3,2)
R33 = -RLTV(3,2)
WRITE (6,*) "R22 = ",RLTV(2,2)
WRITE (6,*) "R23 = ",RLTV(2,3)
WRITE (6,*) "R32 = ",RLTV(3,2)
WRITE (6,*) "R33 = ",RLTV(3,3)
C
Q(1) = VX(NNN) ←座標変換2
Q(2) = VY(NNN)
Q(3) = VZ(NNN)
QX=RLTV(1,1)*Q(1)+RLTV(1,2)*Q(2)+RLTV(1,3)*Q(3)
QY=RLTV(2,1)*Q(1)+R22*Q(2)+R23*Q(3)
QZ=RLTV(3,1)*Q(1)+R32*Q(2)+R33*Q(3)
VX(NNN) = QX
VY(NNN) = QY
VZ(NNN) = QZ
C
QSUM = QSUM + QWGT(NNN)
C
C WRITE(6,*) KNUM,VX(NNN),VY(NNN),VZ(NNN),QWGT(NNN)
C WRITE(6,402) KNUM+1,VX(NNN),VY(NNN),VZ(NNN),QWGT(NNN)
WRITE(6,*) KVX(NNN),KVY(NNN),KVZ(NNN),KQWGT(NNN)
WRITE(6,402) KNUM,VX(NNN),VY(NNN),VZ(NNN),QWGT(NNN)
402 FORMAT((I4,4(F15.9,2X)))
400 CONTINUE
上記ルーチンは、あまりというかほとんど洗練されていません(2/13、
2003)。
C-----KBZTYP=1 : WHOLE B.Z. , 2 : SIMPLE CUBIC IR.B.Z. C----- 3 : BCC IR.B.Z. , 4 : FCC IR.B.Z. C----- 5 : DIAMOND STRUCTURE IR.B.Z. C----- 6 : HEXAGONAL STRUCTURE IR.B.Z. C----- 7 : P6/MMM(ALB2) STRUCTURE IR.B.Z. C----- 8 : TETRAGONAL STRUCTURE IR.B.Z FOR BETA-TIN C----- 9 : A-PBO2 STRUCTURE IR.B.Z FOR SIO2 C----- 10 : TETRAGONAL STRUCTURE IR.B.Z FOR RUTILE C----- 11 : ORTHOROMBIC, CACL2 TYPE C----- 12 : FCO IR.B.Z. C----- 13 : PERPVSKITE(ORTHO) IR.B.Z.これに新たに、Wurtzite型構造(六方晶型、P63mc)を加えるに あたってちょっと困りました。もう既に0以上の番号(番号0は対称性を考慮し ない表面系用)が埋まっていて、HCP構造のところに、この新たな対称性のた めの番号を配することができなかったのです。そこで仕方なく以下のような番 号付けをしました。
C-----KBZTYP=1 : WHOLE B.Z. , 2 : SIMPLE CUBIC IR.B.Z. C----- 3 : BCC IR.B.Z. , 4 : FCC IR.B.Z. C----- 5 : DIAMOND STRUCTURE IR.B.Z. C----- 6 : HEXAGONAL STRUCTURE IR.B.Z. C----- -6 : WURTZITE STRUCTURE IR.B.Z. C----- 7 : P6/MMM(ALB2) STRUCTURE IR.B.Z. C----- 8 : TETRAGONAL STRUCTURE IR.B.Z FOR BETA-TIN C----- 9 : A-PBO2 STRUCTURE IR.B.Z FOR SIO2 C----- 10 : TETRAGONAL STRUCTURE IR.B.Z FOR RUTILE C----- 11 : ORTHOROMBIC, CACL2 TYPE C----- 12 : FCO IR.B.Z. C----- 13 : PERPVSKITE(ORTHO) IR.B.Z.何と、”-6”という負の番号を強引に定義したのです。間違い(バグ)の原 因は、番号が負の整数値だったことです。プログラム内で、IF判定で各対称性 に対応した計算を行なっている時、これまでは対称性を考慮しない場合(番号、 0,1)と、対称性を考慮する場合(番号2以上)というようになっていたので、 IF判定で、IF (KBZTYP.GE.2)或いは、IF (KBZTYP.LE.1)という部分がプログラ ム内に何箇所かありました。筆者は、この部分への対応を忘れてしまったので す。
TOTAL SUMM 1 = -3.391163378869085E-004
2 = 1.273323054860103E-003
3 = 1.716355131468628E-004
4 = -4.301059916385391E-004
5 = 1.596389500226893E-004
6 = 4.345718045303151E-004
TOTAL SUMM OP1 = -3.391163378869083E-004
2 = 1.129377263005734E-021
3 = -1.411721578757167E-020
4 = 2.232906445887955E-006
5 = -1.129377263005734E-021
6 = 2.232906445888011E-006
と、今回の場合の同様の結果、
TOTAL SUMM 1 = 1.523900247301507E-004
2 = 1.641143043416956E-005
3 = 1.089318435141048E-005
4 = 2.612009135650878E-004
5 = 1.295694267740399E-004
6 = 2.076013932175158E-004
との比較でした。見てお分かりの通り、後者では、”TOTAL SUMM OP”の計
算結果部分が抜けています。この最後の部分の結果は、それまで得られたスト
レスの値に対称オペレーターをかけて、対称性をきちんと考慮した結果を与え
るもので、この結果の部分が表示されていないということは、最後に行なわれ
る対称オペレーターをかける計算が行なわれていないことを意味します。
TOTAL SUMM OP1 = 8.363462325643757E-004 <-- ここ
2 = 1.129377263005734E-021
3 = -1.129377263005734E-021
4 = -5.152418845876215E-004 <-- ここ
5 = 1.044673968280304E-020
6 = -5.152418845876215E-004 <-- ここ
(中略)
TOTAL ENERGY FOR 401-TH ITERATION= -51.5028059 -0.5150281D+02
MIXING RATE = 0.500000000000000
ITER=401 ET(H)= 0.1493166D-06 ET(M)= 0.004061 DC= 0.3162807D-06
(ケース2)
TOTAL SUMM OP1 = -3.459023787458713E-003 <-- ここ
2 = 0.000000000000000E+000
3 = 1.807003620809174E-020
4 = 1.641161644709054E-003 <-- ここ
5 = -2.258754526011467E-020
6 = 1.641161644709055E-003 <-- ここ
(中略)
TOTAL ENERGY FOR 401-TH ITERATION= -51.5028059 -0.5150281D+02
MIXING RATE = 0.500000000000000
ITER=401 ET(H)= 0.1493166D-06 ET(M)= 0.004061 DC= 0.3162807D-06
ケース1とケース2で、”ここ”で示した値(ユニットセルにかかる圧力
〔ストレス〕)の値が異なっています。一方、全エネルギー(TOTAL ENERGY)
の値は一致しています。上記には示されていませんが、力の値も一致します。
値が異なるのはストレス部分のみです。上記2つの場合での計算条件の違いは、
ケース1では電子状態のみの計算を行ない、最後にストレスの値を計算し、そ
れを表示させる。ケース2は、セルに関しての構造最適化を行なう過程で、最
初に電子状態計算を行なわせ、セルの構造最適化を始める直前でのストレスの
値を計算表示させるものでした。いずれも上記の場合では、401回目(イタ
レーション)での値です。3c3 < 0.500000000000000 0.000000000000000E+000 0.000000000000000E+000 --- > 0.500000000000000 0.000000000000000E+000 10.0000000000000 15c15 < 400 400 400 1 401 0 --- > 400 2000 40 1 2000 0 45,46c45,46 < IOVE = 400 < IMDI = 400 --- > IOVE = 40 > IMDI = 2000 50,51c50,51 < ISTOP = 401 < ISTMD = 401 --- > ISTOP = 2000 > ISTMD = 2000 72c72 < DTIMUC = 0.000000000000000E+000 --- > DTIMUC = 10.0000000000000 2855c2855 < CALL FORCE --- > CALL FORZFB 2901,2906c2901,2906 (↓ストレスの計算途中の値) < SIGNL 4 1 = -0.275069507467294 < 2 = 1.189155365786973E-003 < 3 = 2.122295586945811E-004 < 4 = -0.274503255358969 < 5 = 1.073767340287859E-003 < 6 = -0.275494497853064 --- > SIGNL 4 1 = -0.279364877487318 > 2 = 3.965559338907192E-003 > 3 = 2.529826782671025E-003 > 4 = -0.268815066930155 > 5 = -3.305458596529087E-004 > 6 = -0.276869879223285 (以下略)上記(diffコマンドによる差の表示結果)で、(主に前半部分の)計算条件 の違いによる違いは別として、二つのことが指摘できます。
DO 1000 IA=1,KATM
IF (NLSPD(KFTYPE(IA)).EQ.1) THEN
LNUM = 4
ELSE
LNUM = 9
END IF
DO 1003 L=1,LNUM
!XOCL SPREAD NOBARRIER DO /IP
DO 1001 IK=1,KV3
DO 1002 IBAN=NBD1,NBD2
ZFC(IBAN,IK,IA,L) =DCMPLX(0.0D0,0.0D0)
1002 CONTINUE
1001 CONTINUE
!XOCL END SPREAD
1003 CONTINUE
1000 CONTINUE
C!XOCL END PARALLEL
C VPP-PARALLEL START
C!XOCL PARALLEL REGION
!XOCL SPREAD NOBARRIER DO /IP
DO 2100 IK=1,KV3
DO 2110 IA=1,KATM
CS=1.0D0/(WS(KFTYPE(IA))*UNIVOL)
CP=1.0D0/(WP(KFTYPE(IA))*UNIVOL)
CWL(1)=CS
CWL(2)=CP
CWL(3)=CP
CWL(4)=CP
C
IF (NLSPD(KFTYPE(IA)).EQ.1) THEN
LNUM = 4
ELSE
LNUM = 9
CD=1.0D0/(WD(KFTYPE(IA))*UNIVOL)
CWL(5)=CD
CWL(6)=CD
CWL(7)=CD
CWL(8)=CD
CWL(9)=CD
(正)CWL(10)=CDを付加
END IF
DO 3222 L=1,LNUM
DO 3200 IBAN=NBD1,NBD2
C 1991 11/28 I ---> I1
DO 3510 I=1,IBA(IK)
I1 = NBASE(I,IK)
L1 = IG1(I1)+KX1
L2 = IG2(I1)+KY1
L3 = IG3(I1)+KZ1
ZTMP=ZZZ(I,IBAN,IK)*DCONJG( ZFM2( I1 ,IA ) )
ZFC(IBAN,IK,IA,L)=ZFC(IBAN,IK,IA,L)+
& ZTMP*SSS(I,IK,KFTYPE(IA),L)
3510 CONTINUE
ZFC(IBAN,IK,IA,L)=CWL(L)*ZFC(IBAN,IK,IA,L)
3200 CONTINUE
3222 CONTINUE
C
2110 CONTINUE
2100 CONTINUE
配列SSS()が非局所擬ポテンシャル項に関するもので、通常の電子状態の計
算では、l=2(d軌道)まで計算する場合、s、p、d合わせて9つ(LNUM
= 9)までの計算が必要となります。実は、本プログラムではストレスの計算
でのd軌道部分からの寄与として、LNUM = 10に相当する部分の計算が必要で
した(深紅色で示した部分)。これを忘れた
ためストレス部分の計算結果が一致しない事態となった訳です。勿論、LNUM =
10として計算をし直すと、結果は一致するようになりました。total chrage = 81.0000000025603スラブの中心から、真空層の中心(系の半分に相当)までの総電子数
TOTAL CHRGE(FIX) = 40.6109851973210上記値を見ると、総電子数が、40.5になっていませんでした。最初、この程 度は誤差として許容できるのではと思ったのですが、系全体で積分すると正し く、総電子数は81(誤差:0.0000000025603)になるのに、積分領域を半分 にすると、0.1109851973210もの誤差が生じるのは、やはりおかしいというこ とで、原因を追求することにしました。
TOTAL CHRGE(FIX) = 40.3890148052776となりました。これは、先の結果、
TOTAL CHRGE(FIX) = 40.6109851973210と比べると、丁度両方を足すと、ほぼ正確な総電子数81になることが判明 しました。
TOTC = TOTC + CHG(I,J,K)
としていました。これは数値積分における、台形公式になっていません。台
形公式として積分するには、
TOTC = TOTC + (CHG(I,J,K) +CHG(I+1,J,K) )*0.5D0
としないといけません。このため積分計算の精度が悪いものになっていまし
た。この場合、系全体での積分では、電荷密度分布がスラブの中心から左右で
完全に対称になっているため、ちょうど右半分の区間の積分と左半分の区間の
積分の和が、上記の台形公式と等価となっているため正確な値が得られていま
した。この前のOpenMP絡みの[バグ]以来、並列計算は行なっ ていなかったのですが、計算速度向上のため、しばらくぶりに計算を行なって みました。そうしたところ、計算結果がオリジナルの結果(OpenMPなしの単一 CPU動作による結果)と一致しないことが判明しました。
まず、OpenMPによる並列動作結果を以下に示します。
SUB-NAME = KBMSD ----------------- TIME = 0.000000 OCCUP2 : WIDTH= 5.000000000000000E-003 ---------- THE FERMI ENERGY =-0.3609612356673470D-01 81.000000 SUB-NAME = FERMI ----------------- TIME = 0.000000 CALL FORCE SUB-NAME = FORCE ----------------- TIME = 0.000000 SUB-NAME = CHAVER ----------------- TIME = 0.000000 SUB-NAME = XCFFT ----------------- TIME = 0.000000 SUB-NAME = FORLOC ----------------- TIME = 0.000000 MINUS CHG ICCCC = 0 TOTAL ENERGY FOR 1-TH ITERATION= -95.1142476 -0.9511425D+02 SUB-NAME = ENERGY ----------------- TIME = 0.000000 ITER= 1 ET(H)= 0.1000000D+06 ET(M)=********** DC= 0.5504872D-01 SUB-NAME = CONV2 ----------------- TIME = 0.000000 READ 2 --- REINIT OR NOT READ 2 --- REINIT OR NOT 0 EVOUT ITER = 1 MINUS CHG ICCCC = 7 DTIME = 2.00000000000000 SUB-NAME = C3FFT ----------------- TIME = 0.000000 SUB-NAME = MSD ----------------- TIME = 0.000000 ---------- THE FERMI ENERGY =-0.8970905953935529D-01 81.000000 SUB-NAME = FERMI ----------------- TIME = 0.000000 CALL FORZFB SUB-NAME = FORCE ----------------- TIME = 0.000000 SUB-NAME = CHAVER ----------------- TIME = 0.000000 SUB-NAME = XCFFT ----------------- TIME = 0.000000 SUB-NAME = FORLOC ----------------- TIME = 0.000000 MINUS CHG ICCCC = 13 TOTAL ENERGY FOR 2-TH ITERATION=-103.3155412 -0.1033155D+03 SUB-NAME = ENERGY ----------------- TIME = 0.000000 ITER= 2 ET(H)= 0.8201294D+01 ET(M)=********** DC= 0.5515755D-01 SUB-NAME = CONV2 ----------------- TIME = 0.000000 MINUS CHG ICCCC = 7 ---------- THE FERMI ENERGY =-0.4685106501394076D-01 81.000000 CALL FORZFB MINUS CHG ICCCC = 23 TOTAL ENERGY FOR 3-TH ITERATION= -99.3989027 -0.9939890D+02 >> ETOOLD.LT.ETONEW << ETONEW-ETTOOLD= 3.91663855637013 ITER= 3 ET(H)= 0.1000000D+01 ET(M)=********** DC= 0.5920008D-01 MINUS CHG ICCCC = 7 ---------- THE FERMI ENERGY =-0.2932751999252538D-01 81.000000 CALL FORZFB次に、正しい(オリジナル)結果を示します。
SUB-NAME = KBMSD ----------------- TIME = 0.000000 OCCUP2 : WIDTH= 5.000000000000000E-003 ---------- THE FERMI ENERGY =-0.3609612356673101D-01 81.000000 SUB-NAME = FERMI ----------------- TIME = 0.000000 CALL FORCE SUB-NAME = FORCE ----------------- TIME = 0.000000 SUB-NAME = CHAVER ----------------- TIME = 0.000000 SUB-NAME = XCFFT ----------------- TIME = 0.000000 SUB-NAME = FORLOC ----------------- TIME = 0.000000 MINUS CHG ICCCC = 0 TOTAL ENERGY FOR 1-TH ITERATION= -83.4446440 -0.8344464D+02 SUB-NAME = ENERGY ----------------- TIME = 0.000000 ITER= 1 ET(H)= 0.1000000D+06 ET(M)=********** DC= 0.5504872D-01 SUB-NAME = CONV2 ----------------- TIME = 0.000000 READ 2 --- REINIT OR NOT READ 2 --- REINIT OR NOT 0 EVOUT ITER = 1 MINUS CHG ICCCC = 7 DTIME = 2.00000000000000 SUB-NAME = C3FFT ----------------- TIME = 0.000000 SUB-NAME = MSD ----------------- TIME = 0.000000 ---------- THE FERMI ENERGY =-0.8970905953933028D-01 81.000000 SUB-NAME = FERMI ----------------- TIME = 0.000000 CALL FORZFB SUB-NAME = FORCE ----------------- TIME = 0.000000 SUB-NAME = CHAVER ----------------- TIME = 0.000000 SUB-NAME = XCFFT ----------------- TIME = 0.000000 SUB-NAME = FORLOC ----------------- TIME = 0.000000 MINUS CHG ICCCC = 13 TOTAL ENERGY FOR 2-TH ITERATION= -91.6459376 -0.9164594D+02 SUB-NAME = ENERGY ----------------- TIME = 0.000000 ITER= 2 ET(H)= 0.8201294D+01 ET(M)=********** DC= 0.5515755D-01 SUB-NAME = CONV2 ----------------- TIME = 0.000000 MINUS CHG ICCCC = 7 ---------- THE FERMI ENERGY =-0.4685106501392522D-01 81.000000 CALL FORZFB MINUS CHG ICCCC = 23 TOTAL ENERGY FOR 3-TH ITERATION= -87.7292991 -0.8772930D+02 >> ETOOLD.LT.ETONEW << ETONEW-ETTOOLD= 3.91663855636882 ITER= 3 ET(H)= 0.1000000D+01 ET(M)=********** DC= 0.5920008D-01 MINUS CHG ICCCC = 7 ---------- THE FERMI ENERGY =-0.2932751999250589D-01 81.000000 CALL FORZFB(説明)
以前の[バグ]が解決した時点では、オリジナルの結果 との比較を怠っていました。並列計算で、1CPUのみの実行結果と、多CP U(2ないし4)での実行結果との比較(これらの結果は一致)したことで、” よし”としていました。この点で詰めが甘かったと言えます。
不一致の原因究明の作業過程で浮かび上がった事実は、
この判断は完全な誤りで、よくよく並列計算の結果と、オリジナルの結果を 比べてみると、その後のイタレーションでもフェルミエネルギーの値は誤差を 除いて完全に一致していました。これは、非常に重要なことで、普通数イタレー ション計算を経た後で、全エネルギーが一致しないのに、フェルミエネルギー だけが一致することはありえません。そこで、各イタレーションでの全エネル ギーの値とフェルミエネルギーの値を以下に示したいと思います。 まず、OpenMPによる並列計算の場合を示します。
TOTAL ENERGY FOR 1-TH ITERATION= -95.1142476 -0.9511425D+02 TOTAL ENERGY FOR 2-TH ITERATION=-103.3155412 -0.1033155D+03 TOTAL ENERGY FOR 3-TH ITERATION= -99.3989027 -0.9939890D+02 TOTAL ENERGY FOR 4-TH ITERATION= -97.7885536 -0.9778855D+02 TOTAL ENERGY FOR 5-TH ITERATION= -97.6782727 -0.9767827D+02 1-TH ----- THE FERMI ENERGY =-0.3609612356673470D-01 81.000000 2-TH ----- THE FERMI ENERGY =-0.8970905953935529D-01 81.000000 3-TH ----- THE FERMI ENERGY =-0.4685106501394076D-01 81.000000 4-TH ----- THE FERMI ENERGY =-0.2932751999252538D-01 81.000000 5-TH ----- THE FERMI ENERGY =-0.1644041912340696D-01 81.000000 6-TH ----- THE FERMI ENERGY =-0.6217050465534285D-02 81.000000次に、オリジナルの場合を示します。
TOTAL ENERGY FOR 1-TH ITERATION= -83.4446440 -0.8344464D+02 TOTAL ENERGY FOR 2-TH ITERATION= -91.6459376 -0.9164594D+02 TOTAL ENERGY FOR 3-TH ITERATION= -87.7292991 -0.8772930D+02 TOTAL ENERGY FOR 4-TH ITERATION= -86.1189500 -0.8611895D+02 TOTAL ENERGY FOR 5-TH ITERATION= -86.0086691 -0.8600867D+02 1-TH ----- THE FERMI ENERGY =-0.3609612356673101D-01 81.000000 2-TH ----- THE FERMI ENERGY =-0.8970905953933028D-01 81.000000 3-TH ----- THE FERMI ENERGY =-0.4685106501392522D-01 81.000000 4-TH ----- THE FERMI ENERGY =-0.2932751999250589D-01 81.000000 5-TH ----- THE FERMI ENERGY =-0.1644041912338591D-01 81.000000 6-TH ----- THE FERMI ENERGY =-0.6217050465513631D-02 81.000000以上を比較してみると、確かに、小数点以下の非常に小さな部分を除けば、 フェルミエネルギーの値は一致し、全エネルギーの値は異なっています。前述 のように全エネルギーが異なる場合、バンド構造そのものも異なるはずで、フェ ルミエネルギーは一致しないはずなのに、実際は一致しています。この場合考 えられるのが、バンド計算そのもの(セルフコンシステントな計算過程:つま りイタレーション)には影響しない部分で不一致が起こっていることが考えら れます。そこで、OpenMPによる並列計算とオリジナルな計算での各イタレーショ ンでの全エネルギーの値の差をとってみると、それはイタレーション回数に関 係なく、11.6696036(絶対値)という一定値であることが分かりました。
(原因究明)
この、11.6696036という値は、調べてみると、部分内殻補正で使用していた
補正項の値であることが判明しました。この補正項は、バンド計算の最初で設
定されるもので、値そのものは全エネルギーの計算の時に、全エネルギーの値
に足し込まれるだけで、バンド計算そのものの結果には全く影響を与えないも
のです。前回の[バグ]の時にデバッグ中に、この計算部
分がバグの原因ではと削除しておいたのを完全に忘れていました。元に戻さず
に計算を行なったため、全エネルギーの値が一致しないように見え、並列計算
に深刻なバグがあるのではと慌てた次第です。
実際は、バグとしてはそう深刻なものではなく、ほんの数行の修正(今回の 場合は削除した部分の追加)で、問題を解決することができました。問題は、 むしろバグを直したと思って、2、3ヶ月もほったらかしておくと、何をした かを忘れてしまうことです。作業記録をきちんと残し、やり残したことや、無 用な変更、削除を元に戻しておくことを怠らないよう(うっかり忘れないよう) にし、その時できることは、その時に完結させておく(記録も残す)ようにし ましょう。
筆者のプログラムで、部分内殻補正の計算を行なう場合、扱う物質や系によっ てストレスの値が発散する(異常に大きな数になる)ことがありました。ただ、 扱っていた系が表面系だったり(普通、表面系ではユニットセルにかかる圧力 〔ストレス〕は使わない。表面ストレスを求めようという場合は別だが)、そ の時点でストレスは必要なかったりで、さして気に止めていませんでした。
しかし、やはりしっくりこないこともあり、原因を突き止めることにしまし た。経験上バルク系では、ストレスが異常に起こることはほとんどなかったの ですが、最近テストとして計算していたバルク系で、ストレス値が10 18もの値になる事態に遭遇していたので、これをデバッグしてみること にしました。以下に、異常なストレス値が出る場合の出力結果を示します。
TOTAL STR 1 1 = -0.106726751049972
2 = 1.114843552513939E-003
3 = 3.786085519029700E-004
4 = -0.107180229756837
5 = -6.187637920119319E-006
6 = -0.107625292219891
REAL TOTAL CHARGE = 8.00229133076466 IN XSTPC
ICOUNT = 2244 XSTPC END
STMQ,SS1,SSX,ZXXX(1) = 4.499630388065659E-003 0.000000000000000E+000
7.977901970862270E+020 (-1.118441627010112E+022,379875.028700487)
ZCHG(1),ZRHPC(1),ZVXC(1),ZRRPC(1),ZEXC(1) =
(6.713436944043497E-002,0.000000000000000E+000)
(4.196147755972463E-003,0.000000000000000E+000)
(-0.279550593402226,0.000000000000000E+000)
(0.000000000000000E+000,0.000000000000000E+000)
(-0.216469172365056,0.000000000000000E+000)
TOTAL STR 2 1 = 7.977901970862270E+020
2 = 0.000000000000000E+000
3 = 0.000000000000000E+000
4 = 7.977901970862274E+020
5 = 0.000000000000000E+000
6 = 7.977901970862264E+020
ZVX,ZEX = -8.052755104079717E+020 -3.244955581708985E-002
STM1(XY)= 1.128607285201954E-002 -0.163484318525950
STU,V,W = 0.126066049507907 -5.284113835626290E-004
-8.052755104079717E+020
STOT = -8.052755104079717E+020
TOTAL STR 3 1 = -8.052755104079578E+020
2 = 5.204170427930421E-018
3 = 2.981555974335137E-018
4 = -8.052755104079581E+020
5 = 5.175371307723775E-019
6 = -8.052755104079573E+020
SIGNL 1 1 = 0.221485143478849
2 = 0.000000000000000E+000
3 = 0.000000000000000E+000
4 = 0.221485143478849
5 = 0.000000000000000E+000
6 = 0.221485143478849
SIGNL 2 1 = -3.008891331718425E-002
2 = -4.277013915213738E-005
3 = -1.448585533509181E-005
4 = -3.008246681184892E-002
5 = 6.375125928747571E-007
6 = -3.007457410262290E-002
SIGNL 3 1 = -6.993430363272542E-002
2 = 9.378111455720368E-004
3 = 3.224221320190277E-004
4 = -7.021242131084532E-002
5 = 3.474492615092482E-006
6 = -7.048630456989730E-002
SIGNL 4 1 = -0.135626705862546
2 = 9.203622245516506E-004
3 = 3.093997338064650E-004
4 = -0.136006849184124
5 = -1.467699662472126E-005
6 = -0.136396710849138
SIGNL 5 1 = 0.135041992087479
2 = -2.647062024157973E-003
3 = -9.026027297115934E-004
4 = 0.136016126412455
5 = 9.309930437597757E-006
6 = 0.136972147395874
SIGEWA 1 = 5.254142857619389E-002
SIGEWA 2 = 7.470500746495105E-018
SIGEWA 3 = -4.548484389417145E-018
SIGEWA 4 = 5.254142857619389E-002
SIGEWA 5 = 1.892189202705232E-018
SIGEWA 6 = 5.254142857619388E-002
SIGNL 1 = 0.120877212753873
SIGNL 2 = -8.316587931864228E-004
SIGNL 3 = -2.852667192211925E-004
SIGNL 4 = 0.121199532584486
SIGNL 5 = -1.255060979156260E-006
SIGNL 6 = 0.121499701353065
TOTAL STR 4 1 = 0.000000000000000E+000
2 = -8.316587931864153E-004
3 = -2.852667192211971E-004
4 = 0.000000000000000E+000
5 = -1.255060979154368E-006
6 = 0.000000000000000E+000
ETOT1,TOTCH = 0.316363262756181 8.00000000000000
TOTAL STR 5 1 = 0.000000000000000E+000
2 = 0.000000000000000E+000
3 = 0.000000000000000E+000
4 = 0.000000000000000E+000
5 = 0.000000000000000E+000
6 = 0.000000000000000E+000
TOTAL SUMM 1 = -7.485313321730875E+018
2 = 2.831847593275287E-004
3 = 9.334183268177589E-005
4 = -7.485313321730745E+018
5 = -7.442698899273169E-006
6 = -7.485313321731027E+018
TOTAL SUMM OP1 = -7.485313321730884E+018
2 = 7.058607893785836E-023
3 = 0.000000000000000E+000
4 = -7.485313321730884E+018
5 = -2.258754526011467E-021
6 = -7.485313321730885E+018
CALL FORLOC AND MD
NOW MD SET EPP 11
EPP(1,1) = 1.00000000000000 0.000000000000000E+000
EPP(1,2) = 0.000000000000000E+000 0.000000000000000E+000
EPP(1,3) = 0.000000000000000E+000 0.000000000000000E+000
EPP(2,1) = 0.000000000000000E+000 0.000000000000000E+000
EPP(2,2) = 1.00000000000000 0.000000000000000E+000
EPP(2,3) = 0.000000000000000E+000 0.000000000000000E+000
EPP(3,1) = 0.000000000000000E+000 0.000000000000000E+000
EPP(3,2) = 0.000000000000000E+000 0.000000000000000E+000
EPP(3,3) = 1.00000000000000 0.000000000000000E+000
TOTAL ENERGY FOR 11-TH ITERATION= -32.4511839 -0.3245118D+02
MIXING RATE = 0.800000000000000
ITER= 11 ET(H)= 0.1239419D-01 ET(M)=337.122064 DC= 0.1087433D-01
もうデバッグ用の計算になっているので、11回イタレーションを進めた段
階でプログラムを止めています(計算は収束していない)。深紅色(CRIMSON)
で表示されている部分が異常に大きな値をしめしているストレス値です。もと
もとデバッグも考慮して、各計算途中段階でのストレスの値を出力するように
していました(上記ではデバッグ用に新たに出力させたものもある)。この結
果から、かなり早い段階(”TOTAL STR 2 1 = ”と
表示されたところ)で、値が異常になっていることが分かります。筆者がまず最初に注目したのは、この”TOTAL STR 2 1 = ”の段階の表示部分で、これらの変数(配列変数)は最初の値(つま りA(1)とかB(1))しか表示していないことでした。筆者のバンド計算プログラ ムでは、逆格子ベクトルは大きさ順に並べるので、最初の配列変数の値(例 ZCHG(1))は、G=0での値となります。G=0では発散項などが生じる場合 があり、扱いに特別な考慮が必要な場合があり、ストレスの計算でも変数の1 番目は別途計算する場合があり、それがTOTAL STR 2 1の部分だった訳です。
この段階で値がおかしいので、さらに詳しく値を表示させることにし、
STMQ,SS1,SSX,ZXXX(1) = 4.499630388065659E-003 0.000000000000000E+000 7.977901970862270E+020 (-1.118441627010112E+022,379875.028700487) ZCHG(1),ZRHPC(1),ZVXC(1),ZRRPC(1),ZEXC(1) = (6.713436944043497E-002,0.000000000000000E+000) (4.196147755972463E-003,0.000000000000000E+000) (-0.279550593402226,0.000000000000000E+000) (0.000000000000000E+000,0.000000000000000E+000) (-0.216469172365056,0.000000000000000E+000)という結果を得ました。この計算結果から逆格子空間での電荷密度、部分内 殻電荷密度、交換相関項の値(ZCHG(1),ZRHPC(1),ZVXC(1),ZRRPC(1),ZEXC(1)) には異常はなく、SSX、そしてZXXX(1)の値に問題があることが分かります。
特に問題となるのが、ZXXX(1)で、これと連動してSSXという値もおかしくな ります。ストレス値の異常の根本原因は、変数ZXXXにありそうだということで、 今度はZXXX(1)だけでなく、ZXXXの全ての値を表示させてみました。結果とし てZXXXは全ての値が異常(発散している)であることが分かりました。
ZXXXは、部分内殻補正導入によって生じる、新たなストレス項(交換相関項 が関わる)を計算するための変数で、それは以下の実空間での交換相関項に関 しての計算、
C -- X ------------
DO 1020 I=1,KSUM
RS=CO2*( 1.0D0/CHGB1(I) )**THIRD
RH1 = -0.458D0*CO3/RS-(0.44D0*CO3*RS + 3.432D0)/
& (RS+7.8D0)**2
RH2 = -0.458D0/RS-0.44D0/(RS+7.8D0)
C
RHV(I)=RH1 - RH2
ZV1D(I)=ZRX(I)*(RHV(I))/CHGB1(I)
1020 CONTINUE
の、変数ZV1Dをフーリエ変換(実空間→逆空間をフーリエ変換と定義)した
ものがZXXXとなります。問題なのは、深紅色で示した、1/CHGB1(I)の部分で、CHGB1(I)は実空間での電荷密
度です。実空間の電荷密度は、逆格子空間で計算された電荷密度ZCHGを逆フー
リエ変換して求めます。部分内殻補正を考慮した場合は、ZCHG+ZRHPCと部分内
殻補正電荷密度がZCHGに加わります。普通、実空間電荷密度が負の値になるこ
とはありえないのですが、場合によっては負の値になってしまうことがありま
す。それは系が表面系で、真空領域がある場合(どうしてもフーリエ変換等の
過程で誤差が入り込む)や、今回の部分内殻補正を考慮した場合です。部分内
殻補正用の電荷密度を加えて、(逆)フーリエ変換する間に、何らかの誤差が
入り込んで電荷密度が負になる場合があります(どういう兼ね合いでそうなる
かは更に原因調査中)。そして実空間での電荷密度(部分内殻補正電荷密度込み)CHGB1が負の値に なった場合、CHGB1の値を10-40にする処理をしていました。この ため今回の場合、1/CHGB1が発散してしまう事態となった訳です。分母の項は、 この発散を打ち消す程の値にならないことも判明しました。分母の項は RS=CO2*( 1.0D0/CHGB1(I) )**THIRDの逆数 のオーダーなのですが、このTHIRDが1/ 3のため、分母はCHGB1の1/3乗のオーダーで、1/CHGB1をかけることにより発散してしまいます。
対処の仕方は、RCHGB(I) = 1.0D0/CHGB1(I)という変数を定義し、CHGB1が負 の値になった場合、RCHGBはゼロになるようにしておきます。そして、
C ZV1D(I)=ZRX(I)*(RHV(I))/CHGB1(I) <-- 2/18, 2000
ZV1D(I)=ZRX(I)*(RHV(I))*RCHGB(I)
とすれば、ZXXX(ZV1Dをフーリエ変換)の発散を防ぐことができます。
問題はサブルーチンPCC
内の配列変数CHGPCです。この変数は、サブルーチンPCC内で定義されてい
る局所的な配列変数で、READ文により読み込まれた部分内殻補正用電荷密度の
総電荷数が格納されます。問題は、この読み込みは最初のイタレーションでし
か行なわれないのですが、CHGPCはその後のイタレーションでも使用されます。
普通、その場合は、サブルーチンの引数としてCHGPCは
メインプログラム側へ引き継がれるようになっていなければならないのに、
実際は、SUBROUTINE PCC(KTPCC,RHPC,SCHGPC,EPC,PCM)と、CHGPCは()内の引
数の中に存在しません。
このため、最初のイタレーション以降、CHGPC内の値は不定となってしまい、 正しい値が保持される保証は全くありませんでした。実際に調べてみると CHGPCの値は、DEC(現COMPAQ)のAlphaマシン、富士通のVPP(並 列計算)では最初のイタレーションの値が正しく保持されていました。但しこ れは非常に好運だったと言えます。また、CHGPC自身も他のサブルーチンで使 用されておらず(されていたら引数を受け渡していたはず)、たとえ間違った 値になったとしても深刻な問題を起こす変数ではありませんでした。逆にこの ため、この問題点に気付くのが遅れたとも言えます。
問題発見の端諸は、旧DECのSMPマシン上でOpenMPプログラムのテスト 中に、並列計算が途中で止まってしまい、止まる箇所がサブルーチンPC Cであったことです。詳しく問題原因を調査した結果、上記のバグが判明 しました。並列計算が止まる原因もCHGPCの値が、OpenMPによる並列計算では 保持されず(VPPでの並列計算では保持【単なる偶然?】、但し全ての場合 はチェックしていない)、これが元でプログラムが異常終了してしまったよう です。CHGPCをメインルーチンに引き渡すようにすると並列計算は問題なく行 なえるようになりました。
今回のバグは結果として軽微(OpenMPによる並列計算では障害があったが)
でしたが、まかり間違えば大きなバグに繋がる可能性があります。局所変数、
大域変数の定義、動作等のチェックはちゃんとするようにしましょう。コンパ
イラによってはオプション等で引数等のチェックは可能ですが、サブルーチン
内で定義された(配列)変数が局所的か大域的かまでは普通判断できません
(人が見るしかない)。
(4/27、2009追記)今年度、スーパーコンピュータ更新に伴い、本格
的なOpenMP化作業を始めた。情けないことに再び、CHGPCに関する同じ間違い
を犯してしまう。CHGPCに関して上記と同じ修正を行なうことで問題は解決す
る。9年経っても進歩なし。そして過去の教訓が全く生かされていな
い(←強く反省すべき点)。
(12/1、2011追追記)再び同じ間違いをやらかす。悲しい。上記(4/
27、2009)に関する修正が行なわれていいないプログラム(コード)が
まだ残っており、実行中にエラーで計算が止まってしまった。早速、修正を施
すが、全くもってなってない話(←改めて強く反省)。
C FORCE2 AND PRESSURE ADDITION SSN(KNG1)
DO 161 IA=1,KATM
DO 162 I=1,KG
FX = GX(I)
FY = GY(I)
FZ = GZ(I)
ZFORT =CDEXP(-ZI*(CATX(IA)*FX+CATY(IA)*FY+CATZ(IA)*FZ))
ZFTMP =ZFORT *PSC(I,KFTYPE(IA))*DCONJG(ZCHG(I))
ZFORC2(IA,1)=ZFORC2(IA,1)+GX(I)*ZFTMP
ZFORC2(IA,2)=ZFORC2(IA,2)+GY(I)*ZFTMP
ZFORC2(IA,3)=ZFORC2(IA,3)+GZ(I)*ZFTMP
162 CONTINUE
IF (KTPCC(KFTYPE(IA)).EQ.1) THEN
DO 1000 N=1,6
ZFPC(N)=DCMPLX(0.0D0,0.0D0)
1000 CONTINUE
DO 200 I=1,KG
ZFORT =CDEXP(-ZI*(CATX(IA)*FX+CATY(IA)*FY+CATZ(IA)*FZ))
ZFTMP =ZFORT *RHPCG(I,KFTYPE(IA))*DCONJG(ZVXC(I))
ZFPC(1)=ZFPC(1)+GX(I)*ZFTMP
ZFPC(2)=ZFPC(2)+GY(I)*ZFTMP
ZFPC(3)=ZFPC(3)+GZ(I)*ZFTMP
ZFTMP =ZFORT *RHPCG(I,KFTYPE(IA))*DCONJG(ZVXCPC(I))
ZFPC(4)=ZFPC(4)+GX(I)*ZFTMP
ZFPC(5)=ZFPC(5)+GY(I)*ZFTMP
ZFPC(6)=ZFPC(6)+GZ(I)*ZFTMP
200 CONTINUE
としていました。問題は、DO 162ループ内のFX、FY、FZです。
これはフォームファクターを計算するための変数なのですが、これがDO 2
00ループ内で定義されていません。DO 161とDO 200は完全に独立
したループで、DO 200ループではFX、FY、FZを再定義しなければ
ならないのに、それを怠っていました。これでは正しい計算ができるはずがあ
りません。修正は、
C FORCE2 AND PRESSURE ADDITION SSN(KNG1)
DO 161 IA=1,KATM
DO 162 I=1,KG
FX = GX(I)
FY = GY(I)
FZ = GZ(I)
ZFORT =CDEXP(-ZI*(CATX(IA)*FX+CATY(IA)*FY+CATZ(IA)*FZ))
ZFTMP =ZFORT *PSC(I,KFTYPE(IA))*DCONJG(ZCHG(I))
ZFORC2(IA,1)=ZFORC2(IA,1)+GX(I)*ZFTMP
ZFORC2(IA,2)=ZFORC2(IA,2)+GY(I)*ZFTMP
ZFORC2(IA,3)=ZFORC2(IA,3)+GZ(I)*ZFTMP
162 CONTINUE
IF (KTPCC(KFTYPE(IA)).EQ.1) THEN
DO 1000 N=1,6
ZFPC(N)=DCMPLX(0.0D0,0.0D0)
1000 CONTINUE
DO 200 I=1,KG
FX = GX(I)
FY = GY(I)
FZ = GZ(I)
ZFORT =CDEXP(-ZI*(CATX(IA)*FX+CATY(IA)*FY+CATZ(IA)*FZ))
ZFTMP =ZFORT *RHPCG(I,KFTYPE(IA))*DCONJG(ZVXC(I))
ZFPC(1)=ZFPC(1)+GX(I)*ZFTMP
ZFPC(2)=ZFPC(2)+GY(I)*ZFTMP
ZFPC(3)=ZFPC(3)+GZ(I)*ZFTMP
ZFTMP =ZFORT *RHPCG(I,KFTYPE(IA))*DCONJG(ZVXCPC(I))
ZFPC(4)=ZFPC(4)+GX(I)*ZFTMP
ZFPC(5)=ZFPC(5)+GY(I)*ZFTMP
ZFPC(6)=ZFPC(6)+GZ(I)*ZFTMP
200 CONTINUE
です。DO 200ループ内でFX、FY、FZを再定義します。このルー
プはPCC(部分内殻補正)に関しての
力の計算を行なっている部分です。もし、ZFORTの計算で、
ZFORT =CDEXP(-ZI*(CATX(IA)*GX(I)+CATY(IA)*GY(I)+CATZ(IA)*GZ(I)))
としていたら、この間違いはなかったのですが、わざわざFX、FY、FZ
に代入してZFORTを計算するのには、確か意味がありました(多分、ベクトル
計算の上でこのようにした方が、計算上有利だったように憶えているのですが
確かではありません。現在調査中)。調べてみると、古いバージョンのプログラムでは変数ZFORTが、配列変数ZFORT(I)になっていたことが分かりました。以下にそれを示します。
C FORCE2 AND PRESSURE ADDITION SSN(KNG1) Old version
DO 161 IA=1,KATM
DO 162 I=1,KG
FX = GX(I)
FY = GY(I)
FZ = GZ(I)
ZFORT(I) =CDEXP(-ZI*(CATX(IA)*FX+CATY(IA)*FY+CATZ(IA)*FZ))
ZFTMP =ZFORT(I) *PSC(I,KFTYPE(IA))*DCONJG(ZCHG(I))
C*****ZFTMP =ZFORM(I,IA)*PSC(I,KFTYPE(IA))*DCONJG(ZCHG(I))
ZFORC2(IA,1)=ZFORC2(IA,1)+GX(I)*ZFTMP
ZFORC2(IA,2)=ZFORC2(IA,2)+GY(I)*ZFTMP
ZFORC2(IA,3)=ZFORC2(IA,3)+GZ(I)*ZFTMP
162 CONTINUE
IF (KTPCC(KFTYPE(IA)).EQ.1) THEN
DO 1000 N=1,6
ZFPC(N)=DCMPLX(0.0D0,0.0D0)
1000 CONTINUE
DO 200 I=1,KG
ZFTMP =ZFORT(I) *RHPCG(I,KFTYPE(IA))*DCONJG(ZVXC(I))
C***** ZFTMP =ZFORM(I,IA)*RHPCG(I,KFTYPE(IA))*DCONJG(ZVXC(I))
ZFPC(1)=ZFPC(1)+GX(I)*ZFTMP
ZFPC(2)=ZFPC(2)+GY(I)*ZFTMP
ZFPC(3)=ZFPC(3)+GZ(I)*ZFTMP
ZFTMP =ZFORT(I) *RHPCG(I,KFTYPE(IA))*DCONJG(ZVXCPC(I))
C***** ZFTMP =ZFORM(I,IA)*RHPCG(I,KFTYPE(IA))*DCONJG(ZVXCPC(I))
ZFPC(4)=ZFPC(4)+GX(I)*ZFTMP
ZFPC(5)=ZFPC(5)+GY(I)*ZFTMP
ZFPC(6)=ZFPC(6)+GZ(I)*ZFTMP
200 CONTINUE
DO 162もDO 200ループも変数IA(ユニットセル内の原子数に関し
て)のDO 161ループの内側にあるので、ZFORT(I)(で十分)となります。
注釈でのZFORT(I,IA)から、更に古いプログラムでは変数I(逆格子数)及びIA
(原子数)の配列であることが分かります。これから、ZFORT(I)からZFORTへ
の変更は、ベクトル化云々より、メモリを節約するためだったと考えられます。
そのための作業過程(ZFORT(I)→ZFORT)で、FX、FY、FZの再定義を忘
れたため、このようなバグが生じてしまいました。以前(数年前)から、PCCに関しての力には、虚数の力が出てきたり、対 称性から考えてありえない力が出てきたりしていました。筆者は、それを負の 電荷密度(PCCを導入すると動径方向の実空間電荷をフーリエ変換し、再度 実空間電荷に逆フーリエする過程で出てくる)によるものだと解釈していまし た。実際それによる影響もあるのですが、もっと重大で深刻な問題が潜んでい ました。PCC版を導入してから数年以上経つ今の今まで全く気付きんません でした。
このバグ発見の経緯は、GGA導入(ま
だ内容はできていません。→一応出来ていますがまだ未完成〔4/21、20
10〕)に向けて、どうも力の挙動がおかしいと思い、以前からPCCを考慮
していた計算でも力に賦に落ちないところがあったので、まずPCCのみ考慮
したバージョンで、簡単な系でテストをしていたら、バグに気付いた次第です。
テストは、Alを仮想的なBCC構造として、立方体のユニットセルを考え、
その中に二つのAl原子を置いて、111方向にそれを近付けたり、遠ざけた場
合(対称性からは近付けたことと同じ)での力の値を調べました。この場合、
Al原子は111方向上にあれば、どのような位置同士であっても、111方向
に同じ大きさの力(方向は互いに反対)を受けます。PCCを考慮しない場合
は、そうなるのですが、PCC版ではそうなりませんでした。
これは何か、GGA導入以前にPCCによる力の計算に深刻な問題があると 判断し、更にしろいろテストしていく内にバグを発見しました。バグそのもの はさして複雑でも、見つけ難いものでもなく、非常に単純なものでした。しか しながら、これによる影響は大変深刻です。少なくとも、これまで行なってき たPCC考慮版の計算で、構造最適化を施したものの信頼性が(完全に駄目で はないにしろ)大分落ちてしまいます。更に、現在保有するプログラムを全て、 修正しなければなりません。この作業は見落としなく、全てのプログラム(い ろいろなマシンに分散して存在)を修正する作業は大変なものです。
(4/22、1999)現在、修正作業を行なっています。プログラムはい ろいろなディレクトリに散らばって存在するので、作業はやはり大変です。
今回の教訓としては、以前のリポートでも書いているのですが、”おかしい”、” 何か釈然としない”、”計算結果がどうもしっくりいかない”と思ったら甘い 解釈はしないで、徹底的に調べてみるというものです。
以下のルーチンの部分に間違いがありました。
DO 2000 JBAN=1,KEG
DO 2010 IBAN=1,KEG
IF (IBAN.EQ.JBAN) THEN
DO 2100 J=1,IIBA
DO 2110 I=1,IIBA
I1=NBASE(I,NNN)
J1=NBASE(J,NNN)
CALL HPDF(HP,HD,HF,VP,VD,VF
& ,IA,NSEK,I,J)
Z(IBAN,JBAN)=Z(IBAN,JBAN) + EKO(IBAN,NNN)
& + DCONJG(ZZZ(I,IBAN,NNN))*RAA(I,NNN)*QC(I,J)*RAA(J,NNN)
& *HP*ZZZ(J,IBAN,NNN)*PC
& *ZFM2(I1,IA)*DCONJG(ZFM2(J1,IA))
2110 CONTINUE
2100 CONTINUE
2010 CONTINUE
2000 CONTINUE
上記ルーチンで、IBAN,JBANはバンド(インデックス)に関してのループ、
I,Jは平面波数に関してのループで、EKOはバンド計算におけるエネルギー固有
値です。そしてこのEKOを配列変数Zに足し込んでいるのですが、既に分った人
もいると思いますが、このEKOの位置に問題があります。このルーチンでは、
バンド数×バンド数の行列Zを作り、それを最終的に対角化(固有値問題、Zに
対する固有値〔先のバンド計算による固有値とは別物〕を求める)することを
目的としていました。対角項にはバンド計算によるエネルギー固有値も和の一
部として含んでいます。ところが、実際対角化して得られた固有値は、とんでもなく大きな値になっ てしまいました。原因を突きとめるため、上記ルーチンのHPの値をゼロにして みましたが、状況は変わりませんでした。更に、以下のようにルーチンを変更 しても状況は依然変わりませんでした。
DO 2000 JBAN=1,KEG
DO 2010 IBAN=1,KEG
IF (IBAN.EQ.JBAN) THEN
DO 2100 J=1,IIBA
DO 2110 I=1,IIBA
I1=NBASE(I,NNN)
J1=NBASE(J,NNN)
C CALL HPDF(HP,HD,HF,VP,VD,VF
C & ,IA,NSEK,I,J)
Z(IBAN,JBAN)=Z(IBAN,JBAN) + EKO(IBAN,NNN)
2110 CONTINUE
2100 CONTINUE
2010 CONTINUE
2000 CONTINUE
この段階でどうしてだろうと頭を抱えそうになったのですが、他のループで
ZにEKOの値のみを代入して(上記ルーチンは動かなくする)対角化すると正し
い結果が出ました。そのルーチンは、
DO 272 I=1,KEG2
DO 273 J=1,KEG2
Z(J,I)=CMPLX(0.0,0.0)
IF (I.EQ.J) THEN
Z(J,I)=EKO(I,NNN)
END IF
273 CONTINUE
272 CONTINUE
としていました。ようやくこのルーチンと、先のルーチンを比較して筆者は
間違いに気付きました。問題は、
DO 2100 J=1,IIBA
DO 2110 I=1,IIBA
I1=NBASE(I,NNN)
J1=NBASE(J,NNN)
C CALL HPDF(HP,HD,HF,VP,VD,VF
C & ,IA,NSEK,I,J)
Z(IBAN,JBAN)=Z(IBAN,JBAN) + EKO(IBAN,NNN)
2110 CONTINUE
2100 CONTINUE
で、平面波数の2重ループ内において、エネルギー固有値EKOを足していま
した。つまりバンド×バンドに関しての行列の1つの対角要素に平面波数×平
面波数分のEKOの和が代入されていた訳です。これでは対角化による固有値が
とんでもなく大きな値(発散してもおかしくなかった)になるのも当然です。
この段階になるまで気付けなかったのがちょっと情けないです。ただ、この手の和をとるとき、とるべき変数の位置を間違えるのは、よく犯 す間違いの典型例と言えます。間違い方としては、上記のように和をとる必要 のないループにその変数を置いてしまう場合と、和ととるべきループ以外の場 所にその変数を置いてしまう場合などです。前者では、大抵その変数は、その 和のループ内では定数和と同等となり、非常に大きな絶対値(大き過ぎれば発 散してエラーになる。今回は発散するまでには至らなかった)になって後々悪 さをします。
このように、和をとる時の変数位置の間違いは筆者も過去何度も経験してい るのですが、またやってしまいました。変数の位置のチェックは怠らないよう にしましょう。
新しい系の計算をしようとして、擬ポテンシャル、初期設定用座標データな どを用意して、テスト計算していたら間違っちゃいました。
最初、テスト計算で計算が4、5回イタレーションを回した段階で破綻(全 エネルギー発散)しました。この時点では、よくあることだと思い、初期設定 (波動関数更新の時間刻み、電荷密度混合比、バンド幅など)を変えて再度試 してみましたが、症状が一向に変わりませんでした。
この計算では、2種類の原子から成る系を計算していたのですが、これを1 種類のより分かりやすいものに替えて、比較のための計算を行なってみました。 これはデバッグの仕方ページの項目4に該 当します。結果として、1種類での計算は破綻せずに、うまくいく(少なくと も4、5回程度での全エネルギー発散はない)ことが判明しました。
そこで、再度入力データ(擬ポテンシャル、入力座標、配列宣言部分、ファ イル入出力指定箇所など)を調べ直しました。そして、見つけてしまいました。 擬ポテンシャルデータに問題があったことが判明しました。
この擬ポテンシャルデータは、前の計算で使い回していた擬ポテンシャルデー タに新たに必要な擬ポテンシャルのデータを付加して再使用していました。筆 者は元のデータには1種類の擬ポテンシャルデータしか入っていないと思って いました。ところが実際は、元のデータには2種類のデータが格納されていま した。それでも前の計算では、最初の1種類目のデータしか読み込まないよう になっていたので(1種類の系の計算をしている、そのまた前の計算で2種類 の系での計算をしていました)、その段階では2種類分あることを認識してい たのですが、そのままにしていました。そして今回、新たに擬ポテンシャルデー タを付加する時には、すっかりそのことを忘れていました。このため、新たな 計算では、2種類めの擬ポテンシャルデータは新たに付加した正しいものでは なく、元からあった全然異なる擬ポテンシャルデータが読み込まれてバンド計 算が行なわれてしまった訳です。
これでは、計算がうまく行くはずがありません。
本日の教訓は、”入力データのチェックはしつこいほどちゃんとしよう。” です。
表面系の計算で、格子振動の計算をする必要があり、初めて格子振動(フォ
ノン)の計算をしてみたところ、いきなり失敗してしまいました。
原因は、格子振動を求めるために与えた、原子位置のずれのオーダーを間違
えたためでした。
筆者は、以下の入力データの座標部分の元データを、
1000 0.9500 0.1000D-07 6.5000 0
65.8112000000 0.0000000000 0.0000000000
0.0000000000 5.8169400000 0.0000000000
0.0000000000 0.0000000000 5.8169400000
0 COORDINATES 0:NORMALIZED 1:CARTESIAN
0.0061633466 0.0000000000 0.0000000000
0.0663263417 0.5000000000 0.5000000000
0.1273274737 0.0000000000 0.0000000000
0.1885776509 0.5000000000 0.5000000000
0.2499996946 0.0000000000 0.0000000000
0.3114217229 0.5000000000 0.5000000000
0.3726719932 0.0000000000 0.0000000000
0.4336731733 0.5000000000 0.5000000000
0.4938364117 0.0000000000 0.0000000000
0.0022391446 0.5000000000 0.5000000000
0.0652380151 0.0000000000 0.0000000000
0.1266380629 0.5000000000 0.5000000000
0.1883738854 0.0000000000 0.0000000000
0.2499996696 0.5000000000 0.5000000000
0.3116255713 0.0000000000 0.0000000000
0.3733614129 0.5000000000 0.5000000000
0.4347616726 0.0000000000 0.0000000000
0.4977604284 0.5000000000 0.5000000000
次のように変更しました。
1000 0.9500 0.1000D-07 6.5000 0
65.8112000000 0.0000000000 0.0000000000
0.0000000000 5.8169400000 0.0000000000
0.0000000000 0.0000000000 5.8169400000
0 COORDINATES 0:NORMALIZED 1:CARTESIAN
0.0061633466 0.0000000000 0.0000000000
0.0663263417 0.5000000000 0.5000000000
0.1273274737 0.0000000000 0.0000000000
0.1885776509 0.5000000000 0.5000000000
0.2499996946 0.0000000000 0.0000000000
0.3114217229 0.5000000000 0.5000000000
0.3726719932 0.0000000000 0.0000000000
0.4336731733 0.5000000000 0.5000000000
0.4938364117 0.0000000000 0.0000000000
0.0122391446 0.5000000000 0.5000000000
0.0652380151 0.0000000000 0.0000000000
0.1266380629 0.5000000000 0.5000000000
0.1883738854 0.0000000000 0.0000000000
0.2499996696 0.5000000000 0.5000000000
0.3116255713 0.0000000000 0.0000000000
0.3733614129 0.5000000000 0.5000000000
0.4347616726 0.0000000000 0.0000000000
0.4877604284 0.5000000000 0.5000000000
赤色で示したデータの値を0.01ずらし(た値は深紅色で表示)ました。これ
はスラブモデルにおいて、表、裏の各表面のトップレイヤーの原子を構造最適
化で得られた平衡位置からずらしていることを意味しています。そして、この
段階で大きな間違いを犯していました。ここでの0.01を筆者は十分に小さなず
れと思っていました。しかし実際は全然小さなものではありませんでした。
因みに格子振動の計算のための参考論文として、M. T. Yin and M. L. Cohen, Phys. Rev B26, 3259(1982)を挙げておきます(特に3264 頁)。そこには原子位置のずれの大きさは、0.01から0.1Aとありました。筆者 は、先の0.01のずれを、0.01 a.u.(大体0.005A)と誤認してしまいました。 これは重大な過ちで、ここでの0.01は、表面のスーパーセルの長さ65.8112 a.u.に対する0.01だったのです。つまり実際のずれは、0.658112 a.u.(大体 0.35A)にもなっていました。更に筆者は、同じようにして0.02ずらした場合 (0.7Aものずれ)の計算を行なっていました。いくつかの表面系の計算をして いて、系によっては0.02ずらすと、計算が破綻(収束しない)している場合も ありました(この破綻をみて、どうもおかいしと思って、よくよく考えると気 付いた次第です)。
今日の教訓は、”データ入力は慎重に行ない、十分その意味するところも把 握し、何度も検討(検証)ておくべきである。”です。
格子振動の計算もまだ初めたばかりで、正直まだ本当にこれで正しく求めら れかも、今後検証していかなければならない。
筆者は単純な入力データの間違いで、これまで計算した大事な結果の1/3 を台無しにしてしまいました。
(経緯)
遷移金属の計算で、PCC版の擬ポテ
ンシャルの多くにゴーストバンドがあることが判明、これを修正すべく新たに
PCCを考慮した遷移金属擬ポテンしゃルを作成しました。ほとんどのものは、
局所部分(Vcore(r))の修正だけで済みました。これは遷移金属ではs、p、
dを非局所とし、Vcore(r)(BHS論文
で定義されている通りのもの)を記述するパラメーターを、例えば
1.0,0.5,0.5だったのを0.5,0.5,0.5にするものでした。
これを遷移金属炭化物表面の計算をしている途中で気が付き、擬ポテンシャ ルを修正、バルクの計算までは正しく修正したデータを使用していたのですが、 肝心な表面計算用の入力データを修正するのを忘れてしまいました。実は明日 (8/5)セミナーがあり、この遷移金属炭化物表面の話をするのですが、完 全に真っ青な状態です。
間違いは、0.5とすべき数値を、元の1.0(旧ポテンシャル用)のままで計算 してしまったことです。普通、入力データを間違えると、計算が破綻したり、 収束しなかったり、明らかに間違った結果が得られるのですが、今回はもっと もらしい結果が出てきたので、かなりの時間問題に気付きませんでした(間違 いもあまりに単純だったこともある)。気付いたときは正に「後の祭り」状態 でした(放心状態)。ただ、後になって結果を良く見てみると確かに若干変な ところがありました(事前に気付けるほどではない)。
今日の教訓は、「データはくどいほどチェックすべきである。」「誤り、間 違いは単純なほど気付きにくく、そして致命的。」です。
(補足、追加、8/17、1998)
この一件に関して、住友電工の澤村先生から指摘(
感謝)がありました。それは、擬ポテンシャル内に、その元素名、価
電子数、作成時のパラメータ(切断半径、Vcore(r)のパラメータ)及び作成方
法、条件の簡単な説明、使っている単位系、などなどの情報を埋め込んでおけ
ば良いというものです。
こうすれば、バンド計算時に、バンド計算として設定した計算条件と、擬ポ テンシャル内の内部情報を比較してチェックするようにしておけば、もし互い の情報に矛盾があれば、すぐに修正して計算をやり直せます(計算の正確性が 増す)。これは単純な間違いや、一体何の計算をしているか分からなくなる事 態を回避するために、大変有効だと考えられます。
(更に補足、8/18、1998)
何と、まだ間違いがありました。それは価電子数の指定のところで、例えば、
Nbは5価(4dに4電子、5sに1電子)として擬ポテンシャルを作ったのに、
バンド計算では4価として計算しているというものです(それでも計算がちゃ
んと収束しているから怖い)。これも大変単純な間違いであり、改めて、上記
擬ポテンシャルの内部情報埋め込みの必要性を認識する次第です。
(またまた補足、9/3、1998)
上記の「更に補足」に関連して、各原子の価電子数が分かると、計算すべき
系の総電子数が分かります。スピンを考えなければ、1バンドに2個の電子が
入り(詰められ)、バンド計算において必要なバンド数が大体分かります。この大体
の意味ですが、バンド数が必要な数より少ないと、計算は普通破綻し
てしまいますが、ではどのくらい余計にとっておく必要があるかが問題になり
ます。
ダイヤモンド(バルク、ダイヤモンド構造でユニットセル内部に4個の場合) のようにギャップの大きな非金属系では、扱うバンド数=系の全電子数/2と しても良いのですが、これは非常に限定された話で、大抵の(特に金属的な) 系では、扱うバンド数=全電子数/2という訳にはいかないです。
系が金属的なバンド構造になる場合、ある程度多めにバンドをとっておく必
要があります。例えば、Ta(5価)、C(4価)がそれぞれ9個づつから成る
系(表面系)では、合計で81個の電子が存在し、最低でも41バンドが必要
となります。
この場合、全電子数が81なので、考えるまでもなく系は金属的にならざる
おえなくなっています。では、それぞれ10個ずつで90電子としたらどうな
るのでしょうか?。これは即答はできません。計算してみないことには分かり
ません。これは難しい問題で、本当にこの表面系が金属的になっているかどう
かは、Ta、Cを9個づつでは判定できません。検討の必
要あり。ただし、TiとCの同じ表面系では、Tiは4価なので、全電子数
は72個となり、全てのバンドは詰まっていることになりますが、構造最適化
した場合のこの系の電子状態は金属的となります。
実際の計算では、41バンドでは不足で、より上のバンドまで考慮する必要 があります。ではどこまでとる必要があるかですが。これはあまりはっきりし ません。以前、扱う系によっては大分上の方のバンドまで考慮に入れないとい けないという論文(詳細は失念、いわゆるカー・パリネロ的な電子状態計算過 程で必要なのか、部分対角化の時に特に必要であるのかも不明)を目にしたこ とがあります。筆者も、経験的にバンドは、 十分に余裕をもって多めに取る必要があると判断しています。どのくらいかと いうと、これも場合場合によるのですが、先のTaとCから成る系(表面系)で は、 どうも44バンド程度では駄目(どうも力の計算がおかしくなる)で、 51バンド位は必要なようです。但し、45、46、47、、、と全ての場合 でチェックしていないので、どこからが安全、不安の境界であるのかは不明で す。また系が金属的か絶縁体か、バルクか表面かなどによっても、バンド数の 取り方は変わってしまいます(どこが第一原理な のだろう^^;)。
従って、事前に擬ポテンシャルに価電子数の情報を盛り込んでおけば、実際 のバンド計算で(最低)必要なバンド数がわかる訳で、バンド計算時にバンド 数に問題があれば(少ない過ぎる、足りないかもしれないなどと)警告するよ うにできます(更に、実際は状況によりますが上記のような理由により、ある 程度多めのバンド数で計算を行なう必要があります)。
(またまた補足、8/20、1998)
擬ポテンシャルデータ内に埋め込む情報について列挙してみましょう。
プログラムの拡張を行なっていて、ヨウ素のfcc構造でのテスト計算を行なっ ていて、予想された結果が得られず(格子定数がおかしい)思案していました。 行なった拡張部分は、最初、
C PBE
RGGAEX(I)= (EXPBE + ECPBE)
VGGAEX(I)= (VXUPPBE + VCUPPBE) + (VXDNPBE + VCDNPBE)
というものでした。もうこれを見て何を拡張しようとしているかお分かりの
方々もいるかと思います。そうです、J. P. Perdew先生のPBEコードの導入を行なおうとしていた訳 です。PBEの詳細は参考文献を見て ください。また、Rutgers大学のKieron Burke先生のサイト[ページ]からPBEソー スコードの入手が可能です(取り扱いについては、付随するドキュメント等の 使用上の注意、指示に従って下さい)。
で、上のソースリスト部分は、PBEで計算されたLDA+GGA(PBE) の結果(EXPBE:交換エネルギー、ECPBE:相関エネルギー、VXUPPBE:スピン アップ交換ポテンシャル、VCUPPBE:スピンアップ相関ポテンシャル、VXDNPBE: スピンダウン交換ポテンシャル、VCDNPBE:スピンダウン相関ポテンシャル) を、こちらのプログラム側で対応する変数(RGGAEX:交換相関エネルギー、 VGGAEX:交換相関ポテンシャル)に代入しています。
この場合、PBEは最初からスピンがアップ、ダウンの別を考慮した形になっ ていたのですが、こちらの計算では取り敢えず最初はパラの状態で考えること にしました。つまりスピンアップ側の電荷密度=スピンダウン側の電荷密度= 全体の電荷密度/2として、計算を行ないました。いろいろ曲折はあったもの の、どうにかうまくいっているのではないかと思えるところまできたのですが、 どうしてもPBE(LDAにしても)の計算での格子定数が正しく出ませんで した。
どうしようもないと思っていたのですが、同僚の新井さんに相談してみると
いとも簡単に問題点を指摘されてしまいました。
問題は、ポテンシャル代入部分、
VGGAEX(I)= (VXUPPBE + VCUPPBE) + (VXDNPBE + VCDNPBE)
で、アップとダウン両方足し込んでは駄目だと言われました。つまり、
VGGAEX(I)= (VXUPPBE + VCUPPBE)
または、
VGGAEX(I)= (VXDNPBE + VCDNPBE)
だけ(どちらか一方)で良いということです。これは、全電荷密度をP、アッ プ側をPU、ダウン側をPDとして、パラ(常磁性)では、
P = PU + PD
PU = PD = P/2
V(up) = V(down) = V
V(up)*PU + V(down)*PD = [V(up)*P + V(down)*P)]/2
= 0.5*2*V*P = V*P = V(up)*P = V(down)*P
となるため、スピンを考えない時の交換相関ポテンシャルは、アップ側、ダ ウン側の一方だけで良いということになります。
ここでの問題は、筆者の知識(勉強)不足であり、教訓はデバッグの常套手段にもあるように、人に相談(議論)す ることはデバッグにとって非常に重要であるということです(新井さんに感謝)。
GGA(PBE)に関しては、[拡]張編にて おいおい話ていく予定です。
Pdの擬ポテンシャルは現在、格子定数が実験値より2.6%も長くなってしまっ ています。これを改善しようとして、切断半径や原子での電子配置などを変更 して、新たにPdの擬ポテンシャルを構築してみました。
そして格子定数が3.89Aと実験値とどんピシャリな擬ポテンシャルを作成す ることに成功しました。バンド構造(pngファ イル、9KB)も表示してみてゴーストバンドは存在しないように見えました。
ただちょっと一番上のバンドが平たいなとは思い、ちょっと引っかかるもの が残りました。しかし、この時格子定数が思った以上に良く出ていたことに気 を取られ、これのもつもっと深い問題を見逃してしまいました。
そして新しいPdの擬ポテンシャルができ、これを今度配布するCD-Rにも収録しようとしてましたが、どうも バンド構造をみる毎に、一番上の部分的に平たくなっているバンドが気になり、 一応もう少し調べてみることにしました。
そして、より上のバンド(pngファイル、 9KB)まで描いてみました。困ったことに出てきてしまったのです。ゴースト バンドが、、、
呆れるほどはっきりとした、(奇麗な?)ゴーストバンドがフェルミエネル ギーの上5eV付近にあるじゃないですか(ショック!)。前のバンドは、6バンド分しか表示しなかったため、 一番上の6バンド目が丁度ゴーストになっているのですが、これは上の表示し ていない7番目のバンドと重なっていて、平たい明らかにゴーストと分かる部 分を、その7番目のバンドが担っていました。そのため、6番目の一部のみが 平たくなっているだけで、最初このバンドの持っている致命的な問題に気付き ませんでした。
更に、ゴーストバンドがフェルミエネルギーより上だったのが発見を遅らせ ました。フェルミエネルギーより上だったため、あまり(と言うよりほとんど) 格子定数に悪い影響を及ぼしませんでした。ゴーストさえなければこの擬ポテ ンシャルは非常に良いものであったかもしれません。
ゴーストバンドがフェルミエネルギーよりずっと上(数Ry以上)に出てく るのなら全く問題無しとしてしまうこともできますが、5eVでは小さ過ぎます。 単独ならば良いかもしれませんが、化合物や表面(とそれに原子が吸着する問 題なら尚更)系ではゴーストの存在による悪影響が顕在化する可能性が高いで す。従って、この新しい擬ポテンシャルは使えません。
今日の教訓は、非常に良い(都合の良い)結果だけに着目して、悪い部分や、 より厳密なチェックを怠る(ポテンシャル作成時にログデル位は見ておくべき だった。ただみなくても7バンド分表示させればゴーストの存在は明白だった) ことは、研究上非常に危険であるということです。
因みにゴーストの無い正しいバンド 構造(pngファイル、9KB)を示します。これも6バンド分しか表示してい ませんが、表示している中で一番上のバンドは、ゴーストのある場合と異なり、 両端が平たくなっていません。当然、その上にもゴーストバンドは(ずっと上 は不明ですが)ありません(但し、この場合は格子定数が良くない)。
あるプログラム(自作ではなく、公開されている他の人のもの)をDEC上で 動かそうとして、コンパイルは全く問題なく終了したのに、いきなり実行させ ると、
forrtl: error: floating divide by zero IOT trap
で止まってしまいました。メッセージから筆者は単純なゼロ割りで止まって いるのだと判断しました(実は違った)。
但し、これは自分が作ったプログラムではなかったので、一体どこの箇所で 止まっているのか即座には見当できませんでした。更に、DECのマシン上では、 この時エラーで止まった箇所が示されていません。デバッガーにかければエラー 箇所が分かるだろうと思ったのですが、f77 -g でコンパイルし、デバッガー にかけると、何か訳の分からないメッセージが沢山出るのですが、肝心なエラー 箇所の表示がなく、この段階で筆者は大変困ってしまいました。デバッガー (gdb)が表示したメッセージは、
Program received signal SIGFPE, Arithmetic exception. 0x3ff808404f4 in __dpml_signal () at ref_cp/alpha_osf_exception.c:317 ref_cp/alpha_osf_exception.c:317: No such file or directory. (gdb)ですが、筆者には何を言っているのかさっぱり分かりません。そこで、デバッ ガーによる問題解決の道を諦め、別の手で行くことにしました。まずデバッグ に関する常套手段を基本路線とします。但 し、これは人の作ったプログラムで、この場合1、の正しい結果を与える標準 的な状況が存在しません(これはテスト用のプログラムで、入力データはプロ グラム内部で全て設定するようになっており、その場合の正しい出力結果に関 しての情報は分かっていました)。
デバッガーが駄目で、コンパイラのオプションを変えても駄目なので、やは り、プログラム内に多数のチェックポイント(WRITE文)を置いて、しらみ潰 しに探すしかないと思っていたのですが、その前に6、の他のシステムで試し てみようと思い、他のワークステーション(SUN、HPなど)で試してみたとこ ろ、SUNやHPでは正しく動作することが分か りました。ただ正しく動く場合、何のエラーメッセージも出てこないので、こ れではDECの場合のエラーは、どうして、そしてどこで起こっているのかわか りません。ただ、これは言語仕様、コンパイラの仕様、実行時の判断の細かい ところの差によるのではないかと推定できました。
更に思案する内にSUNのマシンにはSUN標準のフォートランコンパイラと、富 士通のフォートラン90コンパイラの二つがインストールしてあり、まだ富士 通の方は試していないので、これを試してみることにしました。そして、SUN の標準のコンパイラでは正しく稼働したのですが、富士通のコンパイラでは正 しく稼働しないことが判明しました。更に幸運なことにDECの場合とは異なる エラーメッセージが出てきました。
そのエラーメッセージは、
jwe0266i-e In dx1**dx2 (dx1,dx2:real*8),dx1.eq.0.0 .and. dx2.le.0.0 (dx2=-0.3333333333330000d+00).と言うもので、エラーの発生したサブルーチンとその発生箇所(何行目か) もはっきり示されていました。このエラーの意味は、dx1**dx2(dx1をdx2乗) する時、dx1の値はゼロで、dx2の値が負になっているというものです(富士通 製のコンパイラで、日本語のマニュアルも助けになった)。これは、(もう数 学というより算数は忘れたの自信がないです)1/(dx1**|dx2|)になっていて、 確かにDECのエラーメッセージの言う通りゼロ割りなのですが、正直もっと親 切な表現にして欲しいです(エラー箇所が出てこないのは、やはりおかいしい)。
結局この富士通フォートランでコンパイル、実行した時のエラーメッセージ で原因はすぐに分かりました。それは、
A = ((1.0D0 + Z1)**Z2 - (1.0D0 - Z1)**Z2) :Z2は負の定数
なっている部分で、Z1が1.0D0または-1.0D0の場合、0**Z2, Z2 < 0という状 況に陥り、エラーになっていることが判明しました。そこで、場合分けして、 Z1が-1.0D0または1.0D0の時にゼロ割りにならないように書き換えると問題な く稼働するようになりました。
ここでの問題は、SUN、HPでは動いたものが、DEC、富士通のフォートランで は動かないことです。多分、ゼロ割りの時のエラー処理等の制限が甘い、厳し いの差と思われるのですが、何とかして欲しいものです。
前のバグ(4)に関しては、まだ納得していない部分もあり、現在もパラメー ター文に関しての調査を不定期的に続行中です。
さて、今回のバグは、サブルーチンDIAGON
において、新しい対角化のサブルーチンを導入しようとして遭遇したバグです。
この新しいサブルーチンは、文献「Fortran77による数値計算ソフトウェア」、
渡辺力、名取亮、小国力監修、丸善刊の、エルミート行列対角化ルーチン
EIGCH(当然、これは公開できません)です。
まず筆者が、この書籍に添付されていたフロッピーから、EIGCHを引っ張っ
てきて、計算プログラム本体revpe_d.fにくっつけ、DIAGON
側でCALLするようにしました。
ところが、計算されて出てくる値(全エネルギー)は、全く正しくないもの
でした。
原因は、サブルーチンのCALL EIGCH(----)で使っていた、引き渡し用の変数 の設定を間違ったためでした。
このサブルーチンの正しいCALLは以下のようになります。
CALL EIGCH(ZZZ,IIBA,KNG11,-KGB,KGB,EPS,WWE,LW,EG,ZVN,ICON) 正
CALL EIGCH(ZZZ,IIBA,IIBA,-IIBA,IIBA,EPS,WWE,LW,EG,ZVN,ICON) 誤
ここで、ZZZが対角化すべき配列(エルミート行列)、IIBAは平面波数(k
点毎に異なる値になる)、EPSは打ちきり誤差、WWE、LWは作業用配列、EGがエ
ネルギー固有値用配列、ZVNが固有ベクトル(波動関数)用の配列、ICONがエ
ラーコードとなります。間違いは、3番目の変数IIBAです。文献の中での説明には、ちゃんと配列 ZZZの行数とあります。そこを筆者は何を間違 えたのか、可変な変数IIBA(k点に関するループ内で値が変わる)を引き渡し てしまっています。このため、配列のメモリーか何かが壊れた(?)ため、全 エネルギーがおかしくなったと考えられます。
この3番目の変数をIIBAから、正しい定義による変数KNG11にすると、ちゃ んと正しい結果を与えることがわかりました(4、5番目の変数はIIBAでも KGBでも大勢に影響ありません。但し、配列の定義部分も連動して変えておく 必要があります)。
今日の教訓としては、サブルーチンで引き渡している変数の定義、説明はちゃんと読んで、理解しておかなけれ ばならないことです。変な思い込みで、適当なことをやるとろくなこ とになりません。
筆者は、このバグに気付くのに3日もかかりまし た^^;;)。
最近、新しいDECのサーバーマシンが導入され、最新のOSと最新のフォー
トランコンパイラがインストールされていました。バージョンはそれぞれ、OS
が4.0A、フォートランコンパイラ(FORTRAN77仕様)が4.0でした。
ところが、自分のプログラムが、このバージョン4.0のフォートランコンパ
イラでは、正常に動作しないことが分かりました。コンパイルは無事に成功し、
エラー表示も警告以上のものは出てきません(エラーの出方そのものも、従来
正しく動いておた場合と全く同じものでした)。
そして、実行用オブジェクトを実行させると、思いもしないところで止まっ てしまいました。エラーはsegmentation faultと いうもので、最も何を言っているのかさっぱりわからないエラー表示の代表格 と言えるものです。このエラー表示が出たときは、メモリ領域を壊して(何ら かの不正を行なっている)いることが経験的に多いです。メモリーを壊すのは、 大抵配列の領域外を参照しようとした場合など、配列に関わる扱いのところで 壊し易いです。
しかし、この場合は従来のバージョン3.8以前では、このようなエラーでプ ログラムが停止することは全くありませんでした。更にDEC以外の機種でも 一応問題なく動いています(富士通VPP、富士通PC用フォートラン、HP、 NECのSX4など)。では原因は一体何なのでしょうか?、DEC側のコン パイラのバグも疑ってみましたが、問題はやはり筆者のプログラムにあること が(DEC側の指摘により)わかりました。
問題は、パラメーター文で、設定(定義)した変数を、サブルーチンの引数 として渡しており、引き渡されたサブルーチン側では、変数の名前が変わって いて、更に、それに値を代入して演算を行なっていました。DEC側によると、 新しいコンパイラーでは、チェックが厳しくなっており、このように実質的に パラメーター文に代入を行なっているような場合には、エラーとして検出され るようになり、segmentation faultエラーで、プログラムが止まったと言われ ました。
この状況を分かりやすくプログラム的に示すと以下の ようになります。
MAIN PROGRAM IMPLICIT REAL(A-H,O-Z) PARAMETER (KNVX=8) ------- CALL SUB1(KNVX) ------- STOP END C SUBROUTINE SUB1(NKX) IMPLICIT REAL(A-H,O-Z) ------- CALL SUB2(NKX) ------- END C SUBROUTINE SUB2(NKX) IMPLICIT REAL(A-H,O-Z) ------- NKX = NKXH + NKXH <--- エラー ------- END確かに、この場合おお元はパラメーター文で定義されています。但し、この 変数はサブルーチンに渡される段階で、変数名が変えられています(そして、 そのサブルーチン上でパラメーター文で定義されている訳ではない)。本当に 厳密なFORTRAN77の仕様が、このような扱いを禁止しているのか、少々疑問も あるので、現在これに関して調査中です。
DECのフォートランコンパイラも古いバージョンでは、このエラーは引っ かからなかったのですが、新しいコンパイラではエラーになるようになってし まいました。DEC側の言い分としては、コンパイラの解釈がより厳密になっ たとしていますが、ユーザー側からみると(この解 釈が正しいとしても) 「ありがた迷惑」 のような気がします。
このエラーに対する回避手段として、以下のものが考えられます。
MAIN PROGRAM IMPLICIT REAL(A-H,O-Z) PARAMETER (KNVX=8) ------- CALL SUB1(KNVX) ------- STOP END C SUBROUTINE SUB1(NKX) IMPLICIT REAL(A-H,O-Z) ------- CALL SUB2(NKX) ------- END C SUBROUTINE SUB2(NNKX) IMPLICIT REAL(A-H,O-Z) ------- NKX = NNKX <--- NNKXには代入などの演算は行なわない NKX = NKXH + NKXH ------- ENDこれは、DECの最新のフォートランコンパイラでも正しく動作することを 確認しました。
或いは、
MAIN PROGRAM IMPLICIT REAL(A-H,O-Z) PARAMETER (KNVX=8) NKX = KNVX <--- 変更点 ------- CALL SUB1(NKX) ------- STOP END C SUBROUTINE SUB1(NKX) IMPLICIT REAL(A-H,O-Z) ------- CALL SUB2(NKX) ------- END C SUBROUTINE SUB2(NKX) IMPLICIT REAL(A-H,O-Z) ------- NKX = NKXH + NKXH ------- ENDでも問題ないはずです(これはまだ動作確認をしていません)。
f77 -r8 -O5 sample.f
では正しい結果を与えますが、
f77 -r8 -O4 sample.f
では、実行中segmentation faultエラーで 止まってしまうことが判明しました。コンパイル時にはこれに関係しそうなエ ラーメッセージは出てきません。また、最適化オプション-O2,-O3,-O4の場合はsegmentation faultエラーで止 まりますが、オプション-O0,-O1,-O5の場合 は正しく動くことが確認できました。ここで、注目されるのは、最も最適化し た場合の、-O5では正しく動いてしまうこと です(普通、最適化の度合いを上げれば、エラーで止まることが多くなるのに、 今回はその逆になっています)。
この場合、今後も-O5のオプションによる最適化状態で、より実際的な計算 を継続していって良いものかどうか不安です(まだ試していませんが、より大 規模な計算になると-O5オプションでは動かなくなる可能性があります)。当 然、より古いバージョンのDECフォートランコンパイラではこのようなこと は起きません。
同じく、-g0,-g1,-g2(デバッグモードに関してのオプション)では正しく
動きますが、-g3オプションでは動きません。動かない場合に対して、デバッ
ガーを使ってみましたが、訳のわからない(どうみてもエラーでない)箇所で
止まっています。どうやら、メモリー領域か何かを壊していて、見当違いなと
ころでエラーになっている(バグとしては最悪のパター
ン)ようです。
後の解決方法(処方)でも事情は全く同じで、-O5では動きますが、-O4では
動きません。
どうもやっぱり、DECの新しいバージョンのコンパイラの方にも何か問題 がありそうで、本当の原因究明と根本的な解決のための調査が必要(でも時間がない)と考えられます。
正直な話(2/9、1998現在)、次のコンパイラのバージョンアップで
の改善を期待していた(今までうっちゃってあった^^;)のですが、DECが
何とコンパックに身売りすることになってしまいました。Degital UNIXの将来
に一抹の不安を憶えます。
(6/30、1998)現在、DECのフォートランコンパイラのver4.0で
駄目でしたが、最近、最新のバージョンver5.0でもやはり駄目であることが判
明しました。どうもコンパイラの仕様そのものが、上記のような記述を認めないという方針になってしまったようです。せ
めてオプションで回避できるようにしてくれたらと思う次第です。
このバグの問題は、もともとパラメーター文で定義されていた変数に対して、 設定変更(代入)を行なおうとしたためなのですが、これにはサブルーチン (SUB1、SUB2)が後から付け足されたもので、もともとメインプログラムと整 合性があまりなかったことにあります。それをプログラムの拡張のために無理 にくっつけた感があります。改めて、プログラムの設計や拡張は十分に練って 行なう必要があることを認識しました(そうでないと、後々面倒になる場合が あることを思い知る)。
まず問題となった部分(計算結果)を以下に示します。
TOTAL SUMM OP1 = 5.930788159663123e-04
2 = 0.0000000000000000e+00
3 = 0.0000000000000000e+00
4 = -1.251707515445920e-03
5 = 0.0000000000000000e+00
6 = 8.736301364726182e-04
これは正方格子におけるGaのストレスの値です。1番目、4番目、6番目の
値がそれぞれx方向、y方向、z方向に対応しています。この値を見てすぐに
おかしいと思ったら、貴方はするどいです。扱った系が正方格子(正確には体心正方格子、bct)なので、明らかに上 の3つのストレスの値の2つは値が同じでなければなりません。ところが3つ とも異なる値になっています。明らかにこの計算結果は間違っています。
この間違いは、ある条件設定の場合に起こります。そうでない場合は、以下 のように正しい値が出てきます。
TOTAL SUMM OP1 = -3.386523218593673E-003
2 = 0.000000000000000E+000
3 = 0.000000000000000E+000
4 = -3.430875185404469E-003
5 = 0.000000000000000E+000
6 = -3.430875185401056E-003
対称性から、y方向の値とz方向の値が(計算誤差を除いて)一致していま
す。では、どのような条件の時に値がおかしくなるかと言うと、ストレスを使
ってユニットセルの形についての構造最適化を行なう場合であることがわかり
ました。単に、電子状態のみの計算で、最後にストレスの計算を行なう場合は
上のように正しい値を返しました。最初、筆者はこれをVPP上で計算していたので、間違った先入観に因われ、 原因は並列化部分ではないかという方針で、デバッグを行ないましたが、全く 原因を見つけられませんでした。
しかし、土、日(3/22、3/23)と休んでいる時に、家でもう一回正 しく出ている場合と正しく出ていない場合の計算出力結果を比較検討してみる ことを思い立ちました。そして、昨日(火曜日、3/25)に以下の違いに気 付きました。
間違っている方
---------- THE FERMI ENERGY = 0.9234210201451082d-01 26.000000
CALL FORZFB
REAL TOTAL CHARGE = 25.99999999997447 IN XCFFT
TOTAL ENERGY FOR 100-TH ITERATION=-131.9255525 -0.1319256d+03
ITER=100 ET(H)= 0.2962622d-07 ET(M)= 0.000806 DC= 0.3412940d-06
---------- THE FERMI ENERGY = 0.9234210813638645d-01 26.000000
TOTAL STR 1 1 = -0.3181689275022663
2 = 6.268243606208947e-04
3 = 6.268243606208876e-04
4 = -0.3180186954074477
5 = -6.008948961606797e-05
6 = -0.3180186954074479
正しい方
---------- THE FERMI ENERGY = 0.2661819904309356D+00 26.000000
CALL FORZFB
REAL TOTAL CHARGE = 25.9999999999665 IN XCFFT
TOTAL ENERGY FOR 100-TH ITERATION=-131.8150778 -0.1318151D+03
ITER=100 ET(H)= 0.4234662D-06 ET(M)= 0.011518 DC= 0.5330057D-06
---------- THE FERMI ENERGY = 0.2661826508252645D+00 26.000000
TOTAL STR 1 1 = -0.526384186291203
2 = 1.794706243030863E-003
3 = 1.794706243030874E-003
4 = -0.526410035928503
5 = -4.039471827445321E-005
6 = -0.526410035928507
100回目まで電子状態の計算のみを行ない、101回目にストレスの計算
を行なうのですが、良く見ると、赤色(色の出ない場合は御容赦下さい)で示
した部分、つまりサブルーチンFORCE(またはFORZFB)を呼び出し
ている部分が正しい方と間違っている方で異なることがわかります。この場合、FORCEを呼び出すのが正しいのです。FORZFBでは正し いストレスの計算が出来ません。間違った方はこのFORZFBを呼び出し、 ストレスの値が正しくなくなってしまているのです(FORCEでは後で計算 するストレスのサブルーチンで必要な配列変数の計算を行なっているが、FO RZFBではそれを行なっていないため)。
そして、この違いを生ずる根本的な原因は メインプログラム部分にあります。
IF (MOD(ITER,IMDI).EQ.IRES) THEN
IF (ITER.EQ.1 .OR. ITER.GT.IMD) THEN
WRITE (6,*) 'CALL FORCE'
CALL FORCE(IREC8)
ELSE
CALL FORZFB
END IF
ELSE
WRITE (6,*) 'CALL FORZFB'
CALL FORZFB
END IF
上の赤い部分(赤くなってない人ごめんなさい^^;)の制御変数、IMDIによ
る条件判定に重大な問題があります。この変数は、原子間に働く力によるユニッ
トセル内の原子の構造の最適化用のもので、ストレス用ではありません。従っ
て20回おきにストレスの計算をするように設定(CONTL.DATで設定)しても、その制御変数
はIOVEであるため、ストレスの計算のために必要なサブルーチンFORCEは
いつまでたっても呼び出されません。これでは正しいストレスの計算はできま
せん。解決策としては、いまのところ2つ考えられます。(案1)上の条件判定部 分を以下のように変更する。
IF (MOD(ITER,IMDI).EQ.IRES .OR. MOD(ITER,IOVE).EQ.IRES) THEN
この方法はまだ試していませんが、プログラムそのものを修正するので、根
本的な解決策と言えます。一方、(案2)はCONTL.DATを以下のようにします。
0 1.0D0 0.0D0 5.0D0 0.7D0 0.005D0 300.0D0 -0.0034D0 0.0D0 0.0D0 -0.0034D0 0.0D0 -0.0034D0 0 0 2 0 12 100 20 20 1 200 0 200 0 0実は、このbct-Gaの系は対称性からユニットセル内部の原子は動きません。 従って原子間の働く力を計算する必要がありません。そこで上のデータの最後 から2番目の行を 100 20 1 200 0 200 0としてい たのです。これでサブルーチンは201回目(実際の計算は200回で終るよ うになっている)にならないと呼び出されません。そこで、上のように原子間 に働く力とストレスによるユニットセルの最適化も20回毎に計算するように すれば良い訳です。但し、この系では原子は動かないので、原子のための動力 学用の時間刻みをゼロに設定してあります。
この方法は、プログラムを修正しないで、入力データの変更だけで対応でき るので、作業が簡単ではありますが、ユニットセル内の原子の最適化操作(刻 み時間をゼロにしたので、原子は動かないし、この系では対称性から力そのも のが出てこない)を行なうので、若干計算に無駄が生じます。
ここでの重大な問題は、これはバグと言うより、プ
ログラム設計、仕様上の重大な欠陥であり、これをこのプログラムを作った当
の本人が認識できなかったことにあります(バグが仕様になっているとも、仕
様がバグになっているとも言える)。
まさ
にしようもないプログラムと言えます。
プログラムを改良中に、あるDOループ内の配列変数を、他のDOループ内
に移動(複写でも同じようにバグるはず)して、コンパイルは何の問題もなく
終了したのに、いざ実行してみると計算結果が明らかにおかしくなってしまい
ました。
原因は簡単で、移動(または複写)した配列AがDO 100 K=1、10
0というループ内にあったのに、移動(複写)先のDOループの変数がKでは
なくNだったためです。
DO 100 K = 1,100
A(K) = A(K) + 1.0DO
100 CONTINUE
を、
DO 200 N = 1,100
A(K) = A(K) + 1.0D0
200 CONTINUE
としてしまいました。これではちゃんと動きません。ここでの問題は、同じ
繰り返し数で扱うDOループの制御変数(KやN)が統一されていないことで
す。行き当たりばったり的に作ったプログラムは、特にこのような単純な間違
いで足元をすくわれてしまいます。