計算機:VBA・DLLとの連携
現在工事中です。リンク切れがあるかも。
ここではFortranソースコードから、DLLを作成する方法、DLLをMS-Excelから外部ライブラリ
として利用する方法を以下に述べます。
- 1. なぜFortranを利用するのか
- 2. 汎用ソフトやOfficeツールで間に合わない問題
- 3. DLLの利点
- 4. VBAによるユーザー関数の作成方法
- 5. DLLの作成方法
- 6. VBAからDLLの呼び出し
- 7. 工学計算へのDLL適用
- 8. 演習問題の解答
- 9. Literature Cited
【注】数式表示にはMathJaxを利用しています。IE8以下では表示が遅くなる可能性があります。FireFox などIE8以外のブラウザを利用下さい。
なぜFortranを利用するのか
ASPENやPro/2といった市販のプロセス・シミュレータを用いて、反応器解析や反応速度解析 を実施するには、多くの制約がある。たとえば、反応器の混合モデルとしてプラグフロー モデルや完全混合槽モデルなどの理想流れモデルは用意されているが、混合拡散モデルはない とか組み合わせモデルがないことが例として挙げられる。それ以上に反応速度式を組み込む ことが基本的に不可能に近い。簡単な1成分のn次反応で、速度定数がArrhenius型であれば 定数を組み込むだけで、特別にコードを追加し、シミュレータ本体にリンクさせる必要はない。 しかし、コードを組まずに反応器シミュレーションを実施することは、特別の場合を除き 基本的に出来ない。
そのため高級言語と言われるFortran(あるいはC言語)を用いたコード開発をしなければならない。たとえば 反応器解析で、理想流れモデルであるプラグフロー型反応器や完全混合槽型反応器では、 反応速度定数部分を自分でコーディングし、市販のシミュレータとリンクさせればこうした 反応器の解析は可能である。
市販のプロセスシミュレータでは、出力先にExcelを指定し、物質収支表や物性値を表形式 で出力することが可能であり、シミュレータ以外にも単位操作の計算を始め、多くの エンジニアリング・ワークをExcelで実施することが常態となっている。プラントの 設計業務、各種検討業務、FS、コスト積算、コスト評価など、エンジ会社ではMicrosoft社の Excelを用いて、各種の計算をすることが多い。
プロセス設計に現れる化学工学計算に限れば、Excelの表計算だけで、またちょっと複雑な 計算ではExcelのVBA(Visual Basic Application)を用いることで間に合う場合が多い。 しかしながら、化学メーカー(製造会社)やエンジ会社ではExcelだけで済ませられる 業務ばかりでなく、流体解析(CFD)を始めとし、上述のプロセス・シミュレータなどの 専用ソフトを用いた設計を実施するケースが数多い。
「Excelで気軽に化学工学」とか化学工学会から図書が発売されていたり、また講座が開催 されたりしているが、Excelが万能であるかのような表現は、誤解を招く恐れがある。Excel は確かに便利な道具ではある。連立線形方程式が解けたり、Runge-Kutta法のような微分方程式 が解けたり、場合によっては二次元の偏微分方程式が解けることをしきりに宣伝している。 ある意味では何でも可能であるように見える。
本ウェブサイトで、Fortranをプログラム言語として採用し、普及させようとしているのは 技術計算を含む計算部分を高速なFortranで実行し、それ以外の入出力部分は他の汎用ソフト (MS-Excelなど)を利用することで、トータルの性能向上を図ることができるからである。 化学工学分野を始めとするエンジニアリング業務では、ケーススタディや結果をグラフ化する 業務が日常茶飯に行われており、こうした業務の効率を改善し、共通のプラットフォーム上で 作業できるように、業務環境を統一することがFortranを利用する最大の目的である。
グラフ化処理などの結果処理、ケーススタディなどの入力データを整える作業などはExcelなどに 任せ、計算部分だけをFortranでコード化し、高速化を図ることを目的に、Fortran利用を目指している。
汎用ソフトやOfficeツールで間に合わない問題
流体解析(CFD)も連立の非線形方程式を解いているが、Excelで果たして(CPU時間が かかっても)解けるのか、あるいは反応速度解析のように、活性化エネルギーと頻度因子 を実験データに合うように最小二乗で最適化するコードをExcelのVBAで組めるのか、Excel のソルバーやゴールシークを使い最適化ができるのか、といった複雑系計算がExcelで可能 なのかはなはだ疑問である。
わたしの30年近い研究開発に携わった経験では、こうしたExcelだけ(表計算+マクロ) ではどうしても限界があり、流体解析の問題は専用のCFDソフトを使うべきだし、プロセス ・フローの最適化にはプロセス・シミュレータを使うべきと考える。反応器モデルや化学反応 モデルを取り扱うための汎用の市販ソフトはほとんど皆無であり、研究者自らが開発せざるを 得ない。汎用の反応器シミュレータがないのは、取り扱う物質の物性値がいつも違う、 反応速度式(反応モデル)が簡単でない、相変化を伴う反応のときには物質移動を考慮した 反応器設計が必要になるなど、汎用性のあるソフトウェアを開発することは事実上不可能 である。気相反応を取り扱うChemkinなどが唯一のソフトであろう。
反応器解析(特に非理想流れモデルのとき)や反応速度解析では、化学反応モデルの知識 はもちろんのこと、物性推算、混合・流れのモデル、数値解析の知識を必要とする。 また知識だけでなく、類似プロセスを取り扱った経験が必要である。
以上、Excelを用いた反応器解析、反応速度解析には限界があり、この限界を打破するには 高級言語であるFortranによるコーディング・プログラミングが必須であることが理解できる であろう。
反応器解析や反応速度解析以外の化学工学計算・単位操作計算で、Excelの表計算機能を 有効利用することが可能であるが、さらにFortran言語による外部計算ライブラリを作成し、 Excelから呼び出して利用することが可能である。外部ライブラリとすることで、コードを 公開する必要はなく、コードの機密性を保ち、またコンパイル言語を使用することで、 インタプリタ方式よりレスポンスの良い速い計算を可能とする。
以上、過去に他所のブログに記述したことを修正・加筆した。
DLLの利点
DLLを利用するときのメリットについて、簡単に紹介します。詳しくはIntel Visual Fortran等のマニュアル を参照して下さい。
DLLを、他のアプリ、たとえばMS-Excelから呼び出すときの呼び出し規則が規定されています。 特にFortranのルーチンの引数についての規則を覚えておく必要があります。Fortranでは 呼び出しは参照呼出し(call by reference)であり、C言語では値呼出し(call by value)で 規則がFortranとCとで少し異なります。C言語では、値を引数でルーチンに渡せますが、 Fortranでは変数で渡し、ルーチン側でも変数で受け取ります。戻るとき呼び出し側の変数が 書き換えられていることがあります。
Fortranコンパイラで、DLLを作成するオプションは、MS Fortran(16ビット)の時代(およそ1990年代) から利用できています。そしてDEC Visual Fortran、Compaq Visual Fortran、最新のIntel Visual Fortranでもコンパイラ・スイッチでDLLを作成することが可能です。
- 1) 実行モジュールのサイズを、外部ライブラリ(DLL)に分散させることにより、小さくできる。
- 2) 汎用ルーチンを外部ライブラリ(DLL)化することにより、保守メンテナンスが容易となる
- 3) DLLのソースコードを隠蔽することができる。
- 4) 複数の実行モジュールから参照可能である。
- 5) DLLはコンパイルされた実行モジュールに相当し、計算速度は単独モジュールと変わらない。従って 規模の小さい収束計算もDLLに含めることができる。
VBAによるユーザー関数の作成方法
実際にコンパイルしてDLLを作成する方法とサンプルを紹介する前に、まずExcelのVBAによるユーザー関数の簡単な作り方 を紹介し、そしてこのVBAのユーザー関数をFortranによる外部ライブラリに置換するという手順で紹介します。
ステップ1:VBAによるユーザー関数の作成
まずステップ1としてMS-ExcelのVBAだけでユーザー関数を作成します。
MS-ExcelのVBAの基本的な使い方や文法についてはExcelのヘルプを参照されたい。 VBAを利用してコードを作成するには、"Visual Basic Editor"を起動する。 Editorのメニューから「標準モジュール」を挿入し、このモジュール上で VBAコードを記述することになる。尚、VBAコードはマクロであり、マクロの実行を 有効にしておく必要がある。
ユーザー関数を作成する手順の具体的手順と文法の詳細は、ヘルプに譲るとして、基本的に Basic言語で記述します。エラーメッセージの表示は、VBAのMsgBox関数を利用し、INDが1,2,3,4以外 のときエラーを表示し、結果として"0"を返します。例題の回答をリスト1に示します。
VBAのユーザー関数名として漢字(2バイトコード文字)を利用することができます。VBAでは 変数の型変換にかなり自由度が高く、ある程度プログラマーの助けになります。しかし、 高級言語であるCやFortranから引数として受け渡しするとき変数の型に注意を払う必要が あります。変数の末尾の文字が"#","&"のときにはそれぞれ倍精度実数(double)、4バイト整数(long) であるという、90年代のMS-Basic(あるいはN88-Basic)を起源とする慣例がいまだ生きています。
一旦、ユーザー関数を作ってしまえば、そのExcelファイル上ではどのシードからでも呼び出し ができる。またExcelのセルの連続コピーを利用して、同類の多数の計算を繰り返し実行すること ができる。上の例題では計算内容が単純なものを取り上げたが、収束計算を含む複雑な計算もVBA 内部で計算させ、関数の戻り値としてシート上に結果を取り出すことができる。
ExcelのVBAを利用して、関数(Function)だけでなく、ボタンをクリックすることにより、VBAを 呼び出し、計算を実行後、複数の計算結果をシート上に吐き出すというマクロを組むことができる。 このマクロの計算部分も、Fortranから作成するDLLに置き換えることができる。
Excel上での実行結果を、図1に示します。IND=0、5の場合にはMsgBoxでエラーダイアログが 表示されます。また IND=4で B=0 とすると、ゼロ割りによるエラーとなりますが、Excelの エラートラップにより、"#VALUE!"と表示されています。
DLLの作成方法
ステップ1で作成したVBAルーチンを、外部計算ルーチン(DLL)に置き換える方法をこれから紹介 します。
ステップ2:Fortranによるルーチンの作成
Basic言語による計算部分をFortran言語で記述することをステップ2として考えます。Basic言語とFortran 言語の四則演算や分岐命令"If then"はほとんど同じです。Fortranのコードを作成した経験があるなら BasicからFortranへの変換は簡単ですよね。さて【例題2】として次の例を考えて見ましょう。
Fortranの文法として、Fortranの固定フォーマットを利用しています。従って文の1カラム 目はコメント、2から5カラム目は文番号エリア、6カラム目は継続行、文本体は7カラム目から72 カラム目内に記述します。文の途中の"!"以降はコメントです。回答例をリスト2に示します。
リスト2では、関数の機能としてIND=5、IND=6の場合を追加しています。この関数ルーチン を呼び出すとき、定数を埋め込み戻すこと(IND=5)、標準出力への出力(IND=6)を実行する ことができます。ただし、MS-Excelのユーザー関数として本ルーチンを使用するとき、Excel 側の標準出力を定義していません。従ってエラーが発生し、Excelがダウンする可能性があります。 Excel 97以前のバージョンではExcelがダウンしましたが、最近のExcelではDLL側で出力ユニット"6" としてファイル出力するようになっています。
リスト2の5行目のディレクティブ文は、コンパイラーに特別な指示を与えるセンテンスで、 1カラム目が"c"で始まり、Fortran言語としてはコメントに相当します。2カラム目以降が コンパイラーに与える指示文で、"DEC"は過去のCompilerのメーカであるDegital Equipment Corp. の名残、"MS"(Microsoft)でも可能。'$'以降で、属性を与えています。DLLEXPORTはこのルーチンを 関数名"EXAMPLE_02"として、DLLからほかのアプリにエクスポートします。
ステップ3:コンパイルとリンク(DLLの作成)
Fortranのソースコードが完成したら、こんどはコンパイルとリンクです。リンクが完了すると DLLファイルが作成できます。
コードの作成、コンパイル、リンクをMS Visual Studioという統合環境でも実行可能ですが、わたし の場合はCommand Prompt経由で、コードの修正、コンパイル・リンクを迅速に実行しています。 コンパイル・リンクには、MSのメイク・コマンド"nmake.exe"を利用し、たくさんのソースを コンパイル・リンクするときには修正したソースだけを再コンパイルでき、時間の節約に なります。
コマンドプロンプト上の、ソースが保存されているディレクトリ(例えば e:\sample)上で
E:\sample>nmake /f sktmp32.mak←
とキーボード入力することで、コンパイル・リンクが実行できます。nmake.exeはLinuxのコマンドmakeの Windows版に相当します。UnixではMakefileがデフォルトのファイル名になっていますが、 特定のファイル名としたときは上の/fスイッチで指定できます。
nmake.exeの使い方、メイクファイルの作り方などはMicrosoftのサイトを参照して下さい。MSの Visual Studioについてきます。
例題2で作成したFortranソース(example_01.for)をIntel Visual Fortranでコンパイル・リンクするときのMakeファイルを リスト3に示します。リストを簡単に説明すると、"#"以降はコメントを示します。行末の"\"は、継続行を示します。 Fortranの代入文に似た TAR="xxxx" は、マクロの定義文で、TARという変数に文字列"xxxx"(リストではsktmp32")を割り当てます。この 変数TARを下の20行目くらいの所で、ALL:$(TAR).dllという具合に利用していますが、$(TAR)部分をxxxx に置き換えて ALL:sktmp32.dll という文字列に置換されます。利用するときは$(マクロ名)として参照できます。 同じようにマクロ変数 FOR, LINK, FOR_OPT1, ..., OBJ が定義されています。これらはファイル名を指定したり、コンパイルオプションなどを定義 しています。
マクロ変数の定義部分の後に、ALL:、$(TAR).dll:、とかコロン":"で左右に区切られた行が出現 します。コロンの左側がターゲットと呼ばれるもので、nmake.exeを実行するときターゲット名を 指定することで、指定されたターゲットの右側部分が実行されることになります。ターゲットが 指定されないときはデフォルトの"ALL"が指定されたとみなされます。ターゲットとして"clean"が 指定されたとき、右側にあるDOSコマンドが実行されます。"clean"を指定すると、現在のディレクトリ にある、*.obj, $(TAR).dll, ...などのファイルを削除します。
ターゲット"ALL"を指定すると、右側の$(TAR).dllが次のターゲットになります。 $(TAR).dllのターゲットは、$(OBJ) と$(TAR).mak のタイムスタンプを比較します。 右側の比較されるほうのタイムスタンプがdllより新しいとき、その下の$(LINK)...行 が実行され、dllより古い(dll作成時点からobjやmakが更新されていない)ときは $(LINK)行は実行されません。$(TAR).obj:、.for.obj:ターゲットも同様にソース・ファイルと オブジェクトファイルの タイムスタンプを比較し、再コンパイルしたり、しなかったりします。詳細はmakeファイル の作り方をMicrosoftのサイトで調べて見て下さい。
$(LINK)行で、出力ファイル名sktmp32.dllを、マップファイルとしてsktmp32.dllを、 implibファイルとしてsktmp32.libを出力します。コンパイルとリンクはともにifort.exe を使います。
Intel FortranでDLLを作成するときの肝というか、最も重要なことはコンパイル・スイッチ "/iface:cvf"の指定をすることです。これは作成したDLLをExcelから利用するとき ルーチンの引数を引き渡すときインターフェイスの形式を、Compaq Visual Fortran基準と することを意味しています。Intel Fortranの履歴として、過去コンパイラーの慣習を引きずっている ため、最初のMicrosoft Fortran、DEC Fortran、Compaq Fortranとの互換性を取るためのスイッチ となっています。
出力されるファイルで、Mapファイルの先頭の方にリスト4に示す"_EXAMPLE_02@12"という 関数が利用可能であることが表示されています(cDEC$ATTRIBUTES DLLEXPORTで指定している故)。 implibによる出力ファイル sktmp32.lib にはexample_02ルーチンのオブジェクトファイルが ライブラリ形式で格納されており、ソースコードがなくても、リンク時にこのライブラリをリンク させて、他のルーチンからexample_02を利用することが可能となります。
出来上がった"sktmp32.dll"ファイルを、MS-Excelから利用するFortran側の準備が完了しました。 ソースコードの修正があるときは、テキストエディタでソースを修正し、nmake.exeを実行すること により、最新のdllを作ります。ソースファイルが多数あるときは、リスト3のマクロ変数OBJ1からOBJ4に 必要なファイルを並べます。
また一旦作成した中間ファイル(オブジェクトファイルなど)をすべて破棄し、再コンパイルを実行 するには、ターゲット"clean"を指定してnmakeを実行します。
VBAからDLLの呼び出し
コンパイル・リンクしてできたDLLを、MS-Excelから利用する方法を以下紹介します。ユーザー が作成したDLLを利用するためには、DLLにパス(DOSコマンドで言う"PATH")を通しておく必要があります。 通常のWindows環境では、パスはカレントフォルダ、Windowsをインストールしているフォルダのsystem,system32,.. がPathが通ったフォルダになります。
MS-Excelを起動し、"ファイルを開く"操作を実行したときに表示されるフォルダがカレント・フォルダになります。 または環境変数で"PATH="に、作成したDLLを置いたフォルダを設定することでもパスを通すことができます。
ステップ4:MS-ExcelからDLLルーチンの呼び出し
上で作成したDLLをExcelから利用するとき、DLLの存在するフォルダにExcelファイルを作る ことで、パスをCurrent Folderにします。このExcelファイルのVisual Basic Editorを開き、 標準モジュールのシート上に、"Declare文"を定義し、DLL中のルーチンを利用することが可能となります。
Declare文を、リスト5に示します。Single Quotation "'"は、VBAのコメントです。Underscore "_" は行が継続することを示します。ステップ3で作成したDLLには、Exportする関数がひとつだけで あり、Declare文は1行で済みます。複数あるときは、その数だけDeclare文で宣言します。
下の例は、DLLファイル"sktmp32.dll"中にある、"_EXAMPLE_02@12"という関数を、Excel上で "EXAMPLE_02" という倍精度の関数で使うことを示しています。引数は3つで、IND&はVBAからはlong整数、A#とB#は double実数を示し、EXAMPLE_02の戻り値はdoubleとして返すことを示します。
aliasnameとして、IVFで"/iface:cvf"スイッチを使うと、"_xxxx@nn"と名づけられます。 xxxxは、Fortranの関数名(実際にはDLLEXPORT:: xxxxで指定した関数名)で、"@"以下の"nn"は 引数の数(例題2のときはIND,A,Bの3つ)を4倍した整数値が割り当てられます。先頭の"_"(Underscore)もコンパイラーにより 付加されます。コンパイラーにより出力されるルーチン名は、Mapファイル中に定義されて います(前出リスト4)。
注意すべき点は、ルーチンの引数の型をFortran側とExcel側とで一致させておくことです。
Excel側の制限として、次のものがあり、留意する必要があります。
- 1. 引数の最大数は29個まで
- 2. 配列(FortranでいうArray)は渡せない
- 3. 文字列変数は渡せない
- 4. 配列や文字列は引数として渡せませんが、構造体にすれば渡せる
4番目の構造体とすることにより、VBA側とDLL側とでほとんどすべての変数を引数として受け渡し できることのメリットは結構大きく、利用価値が高い。これについては別のところ(未リンク)で詳述したい。
工学計算へのDLL適用
FortranのFunction文を用いDLLを作ることにより、MS-Excelシート上で種々の工学計算を実行 させることが可能となる。本サイトで紹介する物性計算、化学工学計算など適用場面はかなり広い。
Function文以外にも、Subroutine文をDLL中に入れて、これをVBAから利用することも可能です。 反応器シミュレーションや蒸留計算で、入力データをExcelシート上に入力し、マクロボタンを 配置し、これをクリックすることでデータをVBAで読み込み、DLLに引渡し、DLLで計算を実行し、 結果をVBAに引渡し、結果をVBAでExcelシート上に戻すという一連の作業を行うこともできます。 サブルーチンの利用は別のところ(未リンク)で詳述したい。
工学計算にDLLを適用する上で相応しい問題を次の練習問題1に掲載します。 回答などはこちら(未リンク)を参照して下さい。
演習問題の解答
上の演習問題の解答、およびファイルのダウンロードは、こちら(未リンク)で取り扱っています。
Literature Cited
- note
- 1) 化学工学会編:化学工学便覧、改訂6版、丸善(1999).
- 2) 鞭・森・堀尾著:「流動層の反応工学」、培風館(1984)
- 3) Sieder,E.N. and G.E.Tate: Ind.Eng.Chem.,28,1429(1936).