誤ったintent・変数の初期化漏れ・短絡評価の誤用の修正、write文のクリティカルセクション化
Closes #567 (closed), #896 (closed), #897 (closed)
問題
#567 (closed) は、A64FX(富士通コンパイラ)で 4 つのテストが実行時エラーになるという報告である。原因は 3 つあり、いずれも x86 + gfortran では表面化しない。
- 出力制御の
outinfoを部分的にしか書かない手続きがintent(out)で受けている。!WRITEカードを読むと!OUTPUT_RES/!OUTPUT_VISの設定が未定義になり、出力項目数が 0 になって結果配列の参照が範囲外になる - 接触探索が OpenMP 並列領域の内側から
writeしている。富士通ランタイムはこれを recursive I/O として拒否し、実行を打ち切る setup_contact_output_variablesがpresent(expflag) .and. expflagと書いている。Fortran は.and.を短絡評価しないため、省略された引数を参照して、接触を含む静解析が最初の結果出力で落ちる
また #896 (closed) のとおり、入口の値が必要なのに intent(out) としている仮引数と、呼び出しを通じて書き込まれるのに intent(in) としている仮引数がある。intent(out) の仮引数は入口で未定義になるため、呼び出し元が入れた値に頼る使い方は規格上成り立たない。MPI 並列の接触消去の経路では、これが最初の求解での配列外参照として現れる。
同様に、#567 (closed) 以外の部分でも短絡評価の誤用と、並列領域から到達する入出力文がある。
結果として、 #897 (closed) のとおり、A64FX で -Nquickdbg を付けると 31 件のテストが未定義の値の参照で失敗する。
対応
#567 (closed) の修正(1〜4)に加え、全 Fortran ソースを走査して同じ種類の誤りを直した(5〜8)。#897 (closed) の原因は、6・7 の一部と 9・10 で直した。11 は、走査の途中で見つけた並列領域の private の漏れである。 9 の一部と 13〜15 は、#896 (closed)・#897 (closed) に挙げていない警告を拾って直したものである(下の補足)。
| # | コミット | 内容 |
|---|---|---|
| 1 | 84b214c7 | fstr_copy_outctrl と fstr_ctrl_get_outitem を intent(inout) にし、initOutInfo で actn を設定する |
| 2 | 0590e382 | 並列領域の内側にある接触ログの write 文を !$omp critical で囲む |
| 3 | 09f347cb | present() を単独で先に判定する(expflag、dtime) |
| 4 | a624fe38 | 入口の値が必要な仮引数を intent(inout) に、読むだけの aij を intent(in) にする |
| 5 | 318a771d | 短絡評価に頼っていた判定を、判定だけ先に行う形にする(ElementStress_Shell_MITC、resolve_lambda_cur、hecmw_saamg_blockdiag_setup)。呼び出し元のない append_int2name を削除する |
| 6 | 02684ed8 | 要素ループなどの並列領域から到達する入出力文を !$omp critical で囲む(止まらない警告、異常終了の直前のメッセージ、GetConnectorProperty の内部ファイルへの write) |
| 7 | db9a0799 | 呼び出し元の値に頼る intent(out) を直す(contact_if、hecmw_Ttvec 系の Y)。heat_mat_ass_conductivity では、hecmw_matvec が定義しない外部節点の行を右辺の更新から外す |
| 8 | dc589d07 | !CONTACT_INTERFERENCE を読むときに渡す contact_if の範囲を直す |
| 9 | e022d965 | 結果に影響しない未定義値の参照を直す(F-bar の Jratio、731 シェルの座標、heat_DFLUX_352 の HT ほか。下の補足) |
| 10 | c6f58eee | deriv_general_iso_tensor_func_3d で、dydx を 0 にしてから足し込む |
| 11 | 93e91c45 | JAD の対角ブロックの積の並列領域で、作業用の変数を PRIVATE に加える |
| 12 | 09fc3a63 | マスター面の近傍リストを、設定済みの範囲(1:n_neighbor)だけ比べる |
| 13 | d7d35e45 | 確保した反力 REACTION を 0 にする |
| 14 | a11a1d8e | 節点の熱ひずみに足し込む要素の熱ひずみ tdstrain を、要素の種類ごとに 0 にする |
| 15 | 82ce25d0 | 陰解法の動的解析で、監視節点の出力にサブステップ番号 sub_step を渡す |
コミット 10 は、Mohr-Coulomb の接線剛性に、呼び出し元が入れた弾性行列が余分に加わっていたのを直す。材料の応答は変わらないが、Newton 反復が収束判定で止まる位置が変わり、mohr_simple_shear の応力が変わるため、その参照解を更新した。 コミット 10 以外は、テストの数値を変えない。
12 は、#897 (closed) で原因が未確定だった is_known_master_in_segment の件である。近傍リスト neighbor は容量を倍々に確保し、先頭の n_neighbor 個だけを埋めるが、配列全体と比べて未設定の要素を読んでいた。同じ形の track_contact_position と track_contact_position_ss も直した。
補足:#896 (closed)・#897 (closed) に挙げていない修正
A64FX で -Nquickdbg を付けて修正後のブランチを実行し、富士通ランタイムが出した未定義値の警告(jwe0323i-w)を拾って、実行時エラーにならないものも含めて直した。
結果に届かないもの(9)
- make_principal: flag = ieor(flag, flag) で、設定前の flag を読んでいた
- fstr_static_post、fstr_dynamic_post: 要約の配列(Umax、Emax ほか)を、設定していない ndof・mdof より後ろの要素まで写していた
- fstr_ctrl_material の材料の読み取り: 確保した直後の fval・ival を局所配列に写していた。未設定の値は、読み取りか既定値で上書きされる
- updateContactMultiplier_Alag: 摩擦係数が 0 のとき、intent(out) の jump_ratio を設定せずに戻っていた
- hecmw_mpc_prepost の MPC の前後処理 4 か所: 通信時間の集計用の time_dumm を、設定せずに足し込み先として渡していた
結果に届くもの(13〜15)
- 13: fstr_setup_post が REACTION を確保したまま設定していなかった。非線形静解析はステップ 0 の結果を反復の前に書くので、REACTION_FORCE を出力すると未定義の値が入っていた
- 14: 節点の熱ひずみ(TH_NSTRAIN)に、熱ひずみを計算しない要素の種類(341 など)では未設定の tdstrain を足し込んでいた。これらの要素の分は 0 として扱う。2 次元では、足し込む前に tnstrain を 0 にしておらず、出力のたびに前の値が積み重なっていたので、3 次元と同じく 0 にした
- 15: 自動増分の導入でサブステップのループが do while に変わった後も、ループの添字だった i を渡しており、監視節点の出力の間引きと書き出すサブステップ番号が未定義の値で決まっていた