こんにちは(@t_kun_kamakiri)。

FrontISTRはソースコードが公開されているので、自分で書き換えてコンパイルできます。とはいえ、いきなり難しい改造をすると「コンパイルのやり方が悪いのか、書き換えが悪いのか」が分からなくなりがちです。

そこでこの記事では、いちばん簡単な練習として 「print文を1つ差し込んで、コンパイルが成功したことを画面に出す」 をやってみます。あわせて、変数を定義して $a+b=c$($a=1, b=2$)を計算し、答えの3を表示させます。これができれば、FrontISTRの「書き換え → コンパイル → 実行」の一周を体験できます。

本記事の概要
  • FrontISTRのソースに1か所だけ print文を差し込む
  • 変数を定義して $a+b=c$ を計算し、結果を表示する
  • コンパイル(ビルド)して実行し、コンパイル成功1 + 2 = 3 が出るのを確認する

FrontISTR 5.9 / WSL2環境に構築

この記事は、まず「編集する」「コンパイルする」「FrontISTRの設定ファイル」「コマンドを実行する」をとおして「書き換え → コンパイル → 実行」を一周します。そのあとの 詳しい解説 で、各操作が何をしているのかを1つずつ掘り下げる構成です。

使った環境

今回コンパイルした環境は次のとおりです。

項目内容
OSUbuntu 24.04(WSL2)
コンパイラGNU Fortran 13.3.0
ビルドツールCMake 3.28.3
FrontISTRバージョン5.9(Gitコミット 7f48eae0

FrontISTRのソースは、次の場所にあるものとします。

このパスは、FrontISTRソースの /home/kamakiri/src/FrontISTR を起点とした相対パスです。フォルダ構成の中での位置は、次のようになっています。

fistr1/ がFrontISTR本体、hecmw1/ がそれを支える土台ライブラリ(HEC-MW)です。今回さわるのは fistr1/src/main/ の中の1ファイルだけです。なお build_test/ は最初から存在するわけではなく、あとのコンパイルで作られる作業用フォルダです(ここでは位置関係を示すために一緒に描いています)。

ここで、よく似た名前が2つ出てきます。混同しやすいので先に整理しておきます。

名前何か綴り
fistr_main.f90書き換えるファイルi が入る(fistr)
fstr_mainそのファイルの中にあるサブルーチンi が入らない(fstr)

以降でも、末尾が .f90 ならファイル、そうでなければサブルーチンを指します。

編集する

ファイル fistr1/src/main/fistr_main.f90 を開き、その中の fstr_main サブルーチン(37行目あたりから始まります)の先頭に、2か所を書き足します。差し込む場所は「初期化が終わったあたり(hecmw_comm_get_size の直後)」です。

変数の宣言とprint文の追加

integer の宣言や if( myrank == 0 )print の文法は、後半の「編集したコードの詳しい解説」で1つずつ説明します。ここではこのまま書き足せば大丈夫です。

コンパイルする

はじめての場合(設定してからビルド):

最初の cmake -S . -B build_test ... は、ビルドの準備です。どのコンパイラを使うか、どの機能を使う/使わないか(-DWITH_MPI=OFF など)を決めて、build_test というフォルダに設定を書き出します。ここではまだコンパイルは始まりません。

上記コマンドを実行すると以下のようにログが出ると思います。

エラーが出ていないか確認します。

次の cmake --build build_test -j2 で、実際にコンパイルして実行ファイル fistr1 を作ります。初回は全部をコンパイルするので、少し時間がかかります。

一度ビルドしたあとは、ソースを直すたびに次だけでOKです。変更した部分だけコンパイルし直すので、すぐ終わります。

上記コマンド実行時は以下のようなログが出ます。

FrontISTRの設定ファイル

ここからはテスト的にFrontISTRの設定ファイルを用意します。
先ほど追加したprint文が計算ログに出てくるかを確認するために、ダミーの設定ファイルを作成します。

解析条件 FistrModel.cnt:

ブロック意味
!NODE節点の座標。ここでは4点で四面体を作る
!ELEMENT, TYPE=341四面体1次要素(341)を1個定義(1, 1, 2, 3, 4 = 要素1が節点1・2・3・4からなる)
!NGROUP, NGRP=fix / force固定する節点グループ(1〜3)/荷重をかける節点グループ(4)
!MATERIAL / !SECTION材料の値と、それを要素グループ body に割り当てる指定
ブロック意味
!SOLUTION,TYPE=STATIC静解析を行う
!BOUNDARYfix グループ(節点1〜3)を x・y・z 方向に固定(fix, 1, 1 は自由度1=x を固定の意味)
!CLOADforce グループ(節点4)の x方向に 100 N の集中荷重
!MATERIAL !ELASTICヤング率 130000 MPa、ポアソン比 0.27。!DENSITY 密度、!EXPANSION_COEFF 線膨張係数
!SOLVER,METHOD=DIRECT連立方程式を直接法で解く

単位系は mm-ton-s です(両ファイルの先頭にも # コメントで書いています)。

単位
長さmm
N
応力・ヤング率MPa(= N/mm²)
密度ton/mm³
時間s
温度℃(線膨張係数は 1/℃)

なお、材料の値を .cnt.msh の両方に書いた場合は、.cnt の値が優先されます。FrontISTRはメッシュ側の材料を先に読み込み、そのあと .cnt!MATERIAL を同じ材料名(ここでは FC300)で照合して上書きするためです。今回はどちらも同じ値(E=130000 MPa など)にそろえています。

設定ファイルをEasyISTRで確認してみます。

固定条件は以下の3点をfixという名前のグループで設定しています。

荷重設定は以下の点をX方向100N設定しています。

コマンドを実行する

確認用モデルのフォルダへ移動して、作った fistr1 を実行します。

1行目は、FrontISTRの入力ファイルがある解析フォルダへ移動しています。FrontISTRは通常、実行時の現在地から hecmw_ctrl.dat を探し、そこに書かれたメッシュや制御ファイルを読み込みます。そのため、解析設定ファイルのある 007_compile_test(※ここは任意) へ移動します。

2行目で、その場所から、別フォルダにあるコンパイル済みFrontISTRを起動しています。このパスは ~(ホームフォルダ)を使って ~/src/FrontISTR/build_test/fistr1/fistr1 と書いても同じです。手入力では ~ が短くて便利ですが、この記事ではどのフォルダを使ったか分かるよう絶対パスで書いています。

実行すると、計算のログの中に、書き足した表示が出てきます(### STAGE ... は後半の「fstr_main() の全体像」で足したものです。まだ足していなければ Hello 〜 の部分だけが出ます)。

コンパイル成功a + b = c -> 1 + 2 = 3 が表示され、最後まで計算が進んで FrontISTR Completed !! で終わっています。これで、

  1. ソースを書き換える
  2. コンパイルする
  3. 実行して結果を確認する

という一周ができました。自分の書き換えが、ちゃんと実行ファイルに反映されていることも確認できます。

ちなみに今回の計算ケースで計算した結果をParaViewで確認するとこんな感じです。

特に意味のある解析結果ではありません。

fistr1(パスなし)とフルパスの違い

上では、わざわざ長いパスを打って実行しました。

たとえばfistr1(パスなし)コマンドで実行すると動くのはインストール済みの版です。

この時点では、fistr1とだけ入力すると、既にビルドしたインストール済みの版が実行されます。本記事でコンパイルした書き換え版は、まだインストール先に反映されていません。

build_testの書き換え版をインストールする

このコマンドは、build_test に作成されたインストール設定を読み、コンパイル済みの build_test/fistr1/fistr1 を含む必要ファイルを /home/kamakiri/local/frontistr の下へ配置します。既に /home/kamakiri/local/frontistr/bin/fistr1 がある場合は、その実行ファイルが書き換えた版に更新されます。

これで ~/local/frontistr/bin/fistr1 が書き換えた版に置き換わり、以後は fistr1 と打つだけで本記事で書き足した表示が出ます。うまく置き換わったかは fistr1 -vbuild:date: で確認できます。

ただし1つ注意があります。インストールすると ~/local/frontistr/bin/fistr1 が上書きされるので、このシステムで fistr1 を使う他の作業も、すべて書き換えた版に切り替わります(計算結果は変わりませんが、書き足した表示が混ざります)。他の作業に影響させたくない場合は、インストールせず、これまでどおりフルパスで実行するか、別名を付けて使い分けます。たとえば次のようにエイリアスを作れば、fistr1(元の版)はそのままで、fistr1c で書き換えた版を呼べます。

この骨格の読み方は次のとおりです。

  • module m_fstr_mainend module m_fstr_main … ファイル全体が1つの「モジュール」で包まれています。モジュールは、関連する変数と処理をひとまとめにする箱のようなものです。
  • use ...(冒頭) … 他のモジュールで定義された変数や処理を借りてくる宣言です。これで krealhecmw_initmyrank などをこのファイルの中で使えます。
  • type(...) :: hecMESH など … メッシュや行列といった、複数のサブルーチンで共有する大きなデータをここでまとめて宣言しています。save は、処理が終わっても中身を保持する指定です。
  • contains … これ以降が、このモジュールが持つサブルーチンの定義です。fstr_main はこの contains の直後、先頭にあります。
  • fstr_main 以外のサブルーチンfstr_init(初期化)や fstr_static_analysis(静解析)などです。fstr_main がこれらを順に呼び出して解析を進めます。役割は後述の「fstr_main() の全体像」で改めて扱うので、ここでは「こういう部品が並んでいる」とだけ分かれば十分です。

今回さわるのは、この中の fstr_main の先頭部分だけです。

詳しい解説

変数の宣言

「編集する」で変数宣言として書き足したのは、次の1行でした。

このあたりは、「fstr_main という処理の定義」と「その中で使う変数の宣言」に分かれます。順に見ていきます。

subroutine fstr_main()

subroutine は、Fortranでひとまとまりの処理を定義するキーワードです。fstr_main がその処理名です。

ざっくり言うと、これは このFortranサブルーチンを、C言語のプログラムから呼び出せるようにする ための指定です。そのしくみの1つとして、コンパイルのときに fstr_main という名前を(コンパイラに勝手に変えられないよう)そのまま付けてコンパイルさせています。この「名前をそのままにする」意味は、あとの「名前をそろえる」で詳しく説明します。

まず前提として、FrontISTRは1つのプログラムですが、中身は2つの言語を組み合わせて作られています

  • プログラムの入口(最初に動く部分)… C言語で書かれ、ファイルは main.c fistr1 を実行したとき、いちばん最初に動くのがここです。-v(バージョン表示)などのオプションを読んだり、並列計算(MPI)を立ち上げたりといった、解析を始める前の準備を担当します。
  • 解析の中身(計算の本体)… Fortranで書かれ、ファイルは fistr_main.f90 メッシュを読み込み、剛性行列を組み立てて方程式を解く、FEM計算の中心部分です。数値計算はFortranが得意なので、この部分はFortranで書かれています。

つまり、準備はC言語、計算はFortran、という役割分担です。そのため実行すると、まずC側の main()main.c)が動き、準備が終わるとFortran側の fstr_mainfistr_main.f90)を呼び出します。

ところが、C言語とFortranは別々の言語なので、そのままでは互いの処理を呼び合えません。この「言語の壁」を越えて、C側からFortran側の fstr_main を呼べるようにするのが bind(C,NAME='fstr_main') です。指定は次の2つの部分に分かれます。

部分ざっくり何をするか
bind(C)呼び出しの「作法」をC言語に合わせる
NAME='fstr_main'呼び出すときの「名前」をC言語に合わせて fstr_main に固定する

「作法」と「名前」の2つが合って初めて、C側からFortran側を呼べます。まず「呼び出す」とは何かを確認し、続けてこの2つをかみ砕いて説明します。

「呼び出す」の意味

プログラムでいう「呼び出す(呼ぶ)」とは、あるコードが、別のまとまった処理に「この仕事をやっておいて」と依頼し、実行してもらってから、元の場所に戻ってくることです。人に用事を頼むのに近いイメージです。

さきほどの役割分担でいうと、C言語の準備係が、自分の準備を終えたあとに「あとは解析をお願い」とFortranの計算係へ処理を渡します。この「処理を渡す」動作が、main.c に書かれた fstr_main(); という1行、つまり fstr_main呼び出しです。だからFrontISTRを実行すると、C(準備)→ Fortran(計算)の順に処理が進みます。

「名前で呼ぶ」というのは、この依頼のときに 相手を名前で指名する ということです。main.cfstr_main(); は、「fstr_main という名前の処理をやって」という指名になっています。だから、指名する名前(C側)と、指名される側の名前(Fortran側)が一致していないと、相手が見つからず呼び出せません。ここで問題になるのが、次に説明する「作法」と「名前」です。

C言語と同じ呼び出し規約(作法をそろえる)

呼び出し規約とは、ある処理を呼ぶときの「引数をどこに置いて渡すか」「戻り値をどう受け取るか」といった、細かい手順の取り決めのことです。

bind(C) を付けると、このFortranサブルーチンを 「C言語と同じ作法」で呼べる形 にしてくれます。これで、C側は普通のC関数を呼ぶのと同じ感覚で fstr_main を呼べるようになります。

コンパイル後に名前が変わる問題(名前をそろえる)

もう1つが名前です。まず前提として、私たちがソースに書いた fstr_main という名前は、コンパイル後のプログラムにそのままの文字で残るとは限りません

コンパイルすると、ソースコードは機械語(コンピュータが直接実行できる形)に変換されます。このとき各サブルーチンには、プログラムの中でその処理を見つけ出すための「ラベル」が付きます。ラベルとは、いわば処理に貼られる名札です。さきほどの「名前で呼ぶ」で相手を探すときは、ソースに書いた名前ではなく、この名札(ラベル)を目印にして探します。

やっかいなことに、Fortranコンパイラは、この名札を作るときに、書いた名前そのままではなく、モジュール名などをくっつけた別の名前に作り変えることがあります。これを名前マングリングと呼びます。

たとえばGNU Fortranで、bind(C) を付けずに module m_fstr_main の中の fstr_main をコンパイルすると、ラベルは次のような名前になります。

すると、C側が探す名前(fstr_main)と、Fortran側の実際のラベル(__m_fstr_main_MOD_fstr_main)が食い違います。この状態でプログラムを1つに結合(リンク)しようとすると、「fstr_main という名前が見つからない」というエラーになってしまいます。

そこで NAME='fstr_main' を付けると、Fortran側もラベルを作り変えず、書いたとおりの fstr_main のままにします。

これで、C側が呼ぶ fstr_main と、Fortran側のラベル fstr_main がぴったり一致し、無事に呼び出せるようになります。FrontISTRの起動部分(C側)は次のファイルにあります。

implicit none

Fortranには、宣言していない変数の型を、変数名の先頭文字から自動的に決める古い規則があります。implicit none はその自動判定を無効にし、使用する変数をすべて明示的に宣言させます。

この宣言は次のように分解できます。

部分意味
real実数型
(kind=kreal)FrontISTR共通の実数精度を使う
::型や属性と、変数名の区切り
T1, T2, T3宣言する3つの実数変数

FrontISTR 5.9では、kreal は次のファイルに定義されています。

fistr_main.f90 のモジュール先頭にある use hecmw がHEC-MWの定義を取り込んでいるため、fstr_main の中で krealkinthecmw_init などを使えます。use は、他のFortranモジュールで公開されている定義を現在のモジュールから利用するためのキーワードです。

今回使用したGNU Fortranでは、real(kind=8) は通常、8バイトの倍精度実数に対応します。FrontISTRでは解析に使う実数の精度を kreal という名前で共通化しています。

T1T2T3 には、FrontISTRの初期化前後や解析後の時刻が入ります。最後に差を取り、前処理時間や解析時間を表示するための変数です。

integer(kind=kint) :: a, b, c

integer は整数型です。kind=kint は、FrontISTRで共通使用する整数の種類を指定しています。

今回使用したGNU Fortranでは、integer(kind=4) は通常、4バイトの整数に対応します。abc は今回の練習で追加する3つの整数変数です。

kind の数値が常にバイト数を表すことはFortran規格全体で保証されていません。ここでは、今回のGNU Fortran環境とFrontISTRの定義に基づいて説明しています。

print文の記述

「編集する」でprint文として書き足したのは、次のまとまりでした。

HEC-MWの初期化とプロセス番号の取得

print文の直前にある3行は、FrontISTRの基盤ライブラリであるHEC-MWを初期化し、並列実行の情報を取得する処理です。

call hecmw_init

call はFortranのサブルーチンを呼び出すキーワードです。ここでは hecmw_init という初期化処理を呼んでいます。

hecmw_init の定義は次にあります。

hecmw_init の主な役割は次のとおりです。

  • 既定の制御ファイル名を hecmw_ctrl.dat にする
  • HEC-MWの通信情報を初期化する
  • MPI有効時は、MPIからプロセス数と自分のランクを取得する
  • hecmw_ctrl.dat を読むための制御情報を初期化する

MPI有効版では、C側の main.c がそれより前に MPI_Init を実行しています。Fortran側の hecmw_init は、そのMPI実行環境からプロセス数とランクを取得し、HEC-MW内部で使えるようにします。

今回はCMake設定で -DWITH_MPI=OFF を指定し、MPI(並列計算)を使わない構成でビルドしています。この直列構成では、HEC-MW内部で次の値が設定されます。

myrank = hecmw_comm_get_rank()

hecmw_comm_get_rank() は、現在このコードを実行しているプロセスの番号を返す関数です。戻り値を myrank に代入しています。

ランク番号は0から始まります。例えば4プロセスで実行する場合、各プロセスの myrank は次のいずれかになります。

たとえば、ランク0のプロセスでは myrank=0、ランク2のプロセスでは myrank=2 となります。各プロセスは、この番号で「自分がどの担当か」を識別します。

myrankm_fstr.F90 でFrontISTR共通の整数変数として宣言されており、fistr_main.f90 では use m_fstr を通じて使っています。

nprocs = hecmw_comm_get_size()

hecmw_comm_get_size() は、並列実行に参加している全プロセス数を返す関数です。戻り値を nprocs に代入しています。

例えば4プロセスで実行している場合、すべてのプロセスで nprocs=4 になります。それぞれの myrank は0、1、2、3と異なりますが、参加しているプロセスの合計は共通なので、nprocs はどのプロセスでも4です。

nprocsm_fstr.F90 でFrontISTR共通の整数変数として宣言されています。

今回の WITH_MPI=OFF では、実行プロセスは1つだけなので、結果は常に次のようになります。

そのため、続く次の条件は真になります。

MPIなしの今回は、実行中の唯一のプロセスがランク0です。したがって myrank == 0 を満たし、then から endif の間に書いたprint文が1回実行されます。

MPIを使っ4プロセス実行でも、この条件を満たすのは myrank=0 の1プロセスだけです。そのため、同じメッセージが4回重複せず、代表のプロセスから1回だけ表示されます。

この3つは別の処理です。最初の cmake -S ... -B ... だけでは、まだFrontISTR本体のコンパイルもインストールも行われません。

設定コマンドとコンパイルコマンドの違い

「コンパイルする」で使う2つのコマンドは、役割がはっきり分かれています。

コマンド何をするか実行ファイルは
cmake -S . -B build_test ...(設定)CMakeLists.txt を読み、コンパイラやライブラリを調べ、-D... の設定を反映して、build_test に手順書(Makefile など)を作る。まだコンパイルしないまだできない
cmake --build build_test -j2(コンパイル)build_test の手順書に従い、実際にソースを機械語へ変換し、結合して fistr1 を作る。-j2 は2つ並行ここでできる

料理でたとえると、設定が「レシピと材料の準備」、コンパイルが「実際の調理」です。

全ファイルがコンパイルされるのか、変更分だけか

コンパイル(cmake --build)で毎回すべてを作り直すわけではありません。状況によって変わります。

  • 初回(まだ何も作っていない状態)… FrontISTRの全ソースがコンパイルされます。ファイル数が多いので、数分〜十数分かかります。
  • 2回目以降(ソースを1か所直しただけ)… 変更したファイルと、その影響を受ける部分だけが再コンパイルされ、最後に fistr1 を結合し直します。変えていないファイルは前回の結果を使い回すので、数十秒で終わります。

たとえば今回のように fistr_main.f90 を1つ直しただけなら、コンパイルし直されるのは基本的に fistr_main.f90 の分だけで、あとはリンク(結合)をやり直すだけです。

この「どこを直したか、どこに影響するか」の判定は、設定のときに build_test/CMakeFiles へ記録された依存関係にもとづいて、CMakeが自動で行います。私たちが「このファイルだけ」と指定する必要はありません。

CMakeの設定コマンド

各指定の意味は次のとおりです。

指定意味
cmakeCMakeを起動する
-S .現在のフォルダ . をソースフォルダとして読む
-B build_testbuild_test をビルド用フォルダとして使う
-D変数名=値CMakeの設定変数に値を与える
CMAKE_BUILD_TYPE=RELEASEデバッグ用ではなく、最適化した実行用バイナリを作る
WITH_MPI=OFFMPI領域分割を使わない
WITH_MKL=OFFIntel MKLを使わない
WITH_MUMPS=OFFMUMPSソルバを使わない
WITH_METIS=OFFMETISを使わない
WITH_ML=OFFMLプリコンディショナを使わない
WITH_REFINER=OFFメッシュ細分化機能をビルドしない
WITH_LAPACK=ONLAPACKを有効にする
CMAKE_INSTALL_PREFIX=...cmake --install を実行したときのコピー先を指定する

$HOME はホームフォルダを表す環境変数です。今回の環境では、$HOME/local/frontistr/home/kamakiri/local/frontistr と同じ意味です。

build_test フォルダの役割

build_test という名前に特別な意味はありません。buildbuild-releasebuild-test など、分かりやすい名前を任意に付けられます。今回は作業を区別するため build_test としています。

build_test がまだ存在しない場合は、CMakeが自動的に作成します。mkdir build_test を事前に実行する必要はありません。

設定後のフォルダには、おおむね次のものが入ります。

ここに示したのは build_test 内の主な項目です。実際には、ライブラリやサブフォルダなど、FrontISTRのビルドに必要な他の生成物も入ります。

項目種類何が入っているか手で編集するか
CMakeCache.txtテキストファイルCMakeの設定値と、コンパイラ・ライブラリの検出結果通常は編集しない
CMakeFiles/ディレクトリCMakeがビルドを管理するための内部情報編集しない
Makefileテキストファイルmakeが読むビルド対象と処理手順編集しない
fistr1/fistr1実行ファイルFortranやCのソースをコンパイル・結合したFrontISTR本体編集しない

fistr1/fistr1 は、同じ名前が2回続いていて紛らわしいですが、次の意味です。

これは、GNU FortranやGCCが各ソースをオブジェクトファイルへコンパイルし、リンカが結合して作った、Linuxで実行可能なバイナリファイルです。テキストエディタで開いてもFortranソースのようには読めません。動作を変えるときは fistr1/src/ 以下のソースを編集し、もう一度コンパイルします。

ソースとビルド中間ファイルを分けておくと、設定をやり直すときに build_test だけを作り直せばよく、FrontISTRのソースと混ざりません。また、設定の違うビルドを並べて保持することもできます(例:build-release/build-debug/build_test/)。

コンパイルの実行

設定ができたら、次でビルドします。

今回の指定では、完成品は /home/kamakiri/local/frontistr の下へ配置されます。したがって2つの場所の役割は次のように異なります。

場所役割
/home/kamakiri/src/FrontISTR/build_testCMakeの設定、コンパイル途中のファイル、コンパイル結果を置く作業場所
/home/kamakiri/local/frontistr完成したFrontISTRを日常の解析で使うためのインストール先

2回目以降のビルド(変更後の再ビルド)

一度ビルドしてある場合、ソースを書き換えたあとは fistr1 をビルド対象に指定して再ビルドできます。

  • cmake --build build_testbuild_test に作成済みのビルド設定を使います。
  • --target fistr1 … CMakeが定義した fistr1 というビルド対象を完成させます。ここでの fistr1フォルダ名ではなく、実行ファイル fistr1 を作るためのビルド対象名です。
  • -j2 … 2つのビルド処理を並行します。

CMakeが管理している依存関係により、変更したソースとその影響部分だけが再コンパイルされ、最後に fistr1 が作り直されます。「fistr1 フォルダだけをコンパイルする」という意味ではなく、「fistr1 を完成させるのに必要な範囲だけをビルドする」という意味です。

次の書き方も、今回のMakefile構成ではほぼ同じ処理です。

makebuild_test の中にCMakeが生成した Makefile を読みます。ただし、CMakeがMakefile以外のビルド方式を生成する環境でも同じ手順を使えるため、この記事では cmake --build ... --target fistr1 の書き方を基本とします。

fstr_main() の全体像とステージごとのprint

「編集する」では fstr_main の入口に1か所だけprintを差し込みました。ここでは一歩進んで、fstr_main解析全体をどういう順番で進めているのかを眺めながら、その要所要所にprintを置いてみます。処理の流れが画面で追えるようになります。

fstr_main の役割(解析の司令塔)

fstr_mainfistr1/src/main/fistr_main.f90 の37行目〜)の中身は、コメントの区切りに沿って大きく3つのステージに分かれています。

3つのステージの役割は次のとおりです。

ステージコメントの区切りやっていること
STAGE 1INITIALIZEHEC-MWの初期化、メッシュと解析条件(.cnt)の読み込み、データ構造の準備
STAGE 2ANALYSISsolution_type に応じて解析本体を呼ぶ。静解析なら K u = f を組み立てて解く
STAGE 3FINALIZE結果ファイルを閉じ、メモリを解放して終了。最後に FrontISTR Completed !!

T1(開始)、T2(前処理おわり)、T3(解析おわり)で時刻を測り、あとで差を取って前処理時間・解析時間を表示しています。

select casefstrPR%solution_type は、.cnt!SOLUTION,TYPE= で決まる値です。今回の静解析は kstSTATIC(値は 1)なので、fstr_static_analysis に入ります。

各ステージへの print の追加

流れを目で追えるように、各ステージの入口に1行ずつ print を足します。すでにある「Hello / a+b=c」のブロックはそのままで、次の3行を追加します。

いずれも if( myrank == 0 ) を付けています。これは、並列(MPI)実行のときに全プロセスが同じ行を出すと画面が重複するので、代表の1プロセス(rank 0)だけが表示するためです。今回の WITH_MPI=OFF では常に myrank=0 なので、1回ずつ表示されます。

print *, '...', 変数, '...' のように、print の後ろはカンマ区切りで文字列と変数を混ぜて並べられます。STAGE 2 では fstrPR%solution_type の値もそのまま表示しています。

再ビルドと流れの確認

書き換えたら、これまでと同じように fistr1 を作り直します。

解析フォルダで実行すると、計算の進行に合わせて3つのステージが順番に表示されます。

solution_type = 1(静解析)に入り、INITIALIZE → ANALYSIS → FINALIZE の順に進んで、最後に FrontISTR Completed !! で終わっていることが分かります。

このように、「気になる場所の直前に print を置いて、実行時にそこを通ったか確かめる」 のは、ソースを読むときの基本のやり方です。どの関数がどの順番で呼ばれているのかを確かめながら読むと、大きなプログラムでも迷子になりにくくなります。

元に戻す手順

練習が終わって元のFrontISTRに戻したいときは、書き足したprint文と変数宣言をソースから削除し、もう一度 fistr1 をビルドします。

まず変更内容を確認します。

このファイルに今回の練習以外の変更がないことを確認した上で、書き足した行をエディタで削除します。その後、次で作り直します。

もし練習前の状態にそのまま戻したいだけなら、git で1つのファイルを元に戻すのが簡単です。

まとめ

  • FrontISTRは fistr1/src/main/fistr_main.f90fstr_main に print文を書き足すだけで、実行時に好きな表示を出せます。
  • ビルドはCMakeで行い、初回は cmake -S . -B build_test ... で設定してから cmake --build build_test -j2 でコンパイルします。
  • 2回目以降は cmake --build build_test --target fistr1 -j2 とすると、変更したファイルと依存部分だけが自動判定されて再ビルドされます。
  • fistr1(パスなし)は PATH上の元の版、フルパスの build_test/fistr1/fistr1書き換えた版を指します。書き換えた版を fistr1 で使いたいときは cmake --install build_test でインストールします。
  • fstr_main は INITIALIZE → ANALYSIS → FINALIZE の3ステージで進みます。各ステージの頭に print を置くと、実行時にどこを通っているかを目で追えます。

この「書き換え → コンパイル → 実行」の流れが分かれば、次はもっと意味のある改造(たとえば温度荷重行列Hを出力する DUMPH=YES の追加など。こちらの内容は後日ブログにアップします)にも進めます。