%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% コンピュータ演習 : プログラムの作成 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{はじめに} 現代のコンピュータの利用法には、大きく分けて次の二つがあると言える。 * 数値計算 * 情報処理 化学の分野では、日々新たに作られていく化合物を対象としなければなら ないので、後者の意味のコンピュータ利用はたいへん重要である。しかし ここでは前者についてとりあげ、しかも計算のためのプログラムを自分で 作ることを実習する。将来出来合いのプログラムパッケージを利用する場 合にも、プログラムの作成を経験していれば、ブラックボックスの中身に ついての感覚を持ち合わせていることになり、応用の幅が広がるであろう。 化学の研究で行われている数値計算には次のようなものがある。 * 実験データの処理 + 統計的な処理 + 仮説・モデルへの当てはめ * 計算機実験・シミュレーション(simulation) + 分子軌道計算 + 分子力場計算 + 物性値の計算 + 仮説・モデルによる予測 ここで実験データの処理については、直線回帰の様な定型的なものであれ ば、現在では表計算ソフトを用いるのが便利である。分子軌道計算などは、 初歩的なものをのぞいて通常はパッケージのプログラムを用いる。その他 のモデルへの当てはめ、予測や、シミュレーションは、個別の問題であり、 研究者がそれぞれ独自に開発したプログラムを用いることが多い。 ここではモデルによる予測に近いものとして、理論式による物性値の計算 をおこない、それを視覚的にわかりやすく図示することを試みる。そのた めにまず、物理化学の教科書に出てくるような理論式をとりあげる。そし てこれを用いた計算のプログラムの実例を示して、その流れを解説する。 そのあと別の式による計算のプログラムの作成を、演習としておこなう。 サンプルプログラムは、共通教育の情報処理の簡単なプログラム作成で用 いたc言語により記述する。\footnote{% B. W. カーニハン, D. M. リッチー 著, 石田晴久 訳, プログラミング言語C, 第2版, 共立出版. } なお簡単化のために、計算のプログラムは結果をファイルに書き出すものとする。 実際にグラフにプロットするのは、表計算ソフトを用いるものとする。 課題の部分はレポートとして提出すること。なおこの場合に、プログラム を記述する言語は、各人が使用可能なものを用いれば良い。(c言語でのプ ログラム作成を強制するものではない。) \subsection*{注意点} * 3.5-inch のフロッピーディスク(1.44MB または DOS/V 用と書かれている もの)を各人が用意し、データファイルはそこに保存すること。(共有 ディスクを用いることもできる。)パソコンのハードディスクには save しない。 * 昨年度の共通教育:情報処理(理系)の実習用資料をもってくること。 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{実在気体の状態方程式 (van der Waals の方程式)} 実在の気体についての状態方程式はvan der Waalsにより次の\ref{eq:vdW}式 のように与えられている。\footnote% {P. K. Atkins, {\it Physical Chemistry}, 5th ed., Oxford, p. 44 \& Data section C4.} p = (nRT/(V-nb))-a(n/V)^2 ここでパラメータ a,b は、表\ref{tbl:vdW}に示すとおりである。 \begin{table}[h] \caption{van der Waals coefficients.} \label{tbl:vdW} ----------------------------------------------------- & a/( atom L^2 mol^{-2}) & b/(10^{-2}L mol^{-1}) ----------------------------------------------------- Ar & 1.345 & 3.220 CO_2 & 3.592 & 4.267 He & 0.034 & 2.37 N_2 & 1.390 & 3.913 ----------------------------------------------------- \end{table} van der Waals の実在気体の状態方程式による、実在気体の体積と圧力 との関係を計算するプログラムの例を図\ref{prg:vdw}に示す。またこの プログラムの実行結果を gnuplot で表示させた結果を図\ref{fig:vdw1}, \ref{fig:vdw2}に示す。これらのグラフは、 a=0, b=0 の理想気体の 場合と、He,Ar の場合について計算し、その3つの結果を重ねて表示し てある。図\ref{fig:vdw1}では少しわかりにくいが、図\ref{fig:vdw2}で は圧力が高くなるほど理想気体からずれていく様子がよくわかる。 \begin{figure} \caption{van der Waals の実在気体の状態方程式による体積と圧力との関係を 計算するプログラム.} \label{prg:vdw} #include#include void main( int argc, char* argv[] ){ float T, a, b; float n, R; float p, V; if ( argc!=4 ) { fprintf(stderr, " parameter error \n"); fprintf(stderr, " usage: vdw T a b \n"); exit(1); } T=atof(argv[1]); a=atof(argv[2]); b=atof(argv[3]); fprintf(stderr, " T/K=%f, a/(atom L^2 mol^-2)=%f, b/(L mol^-1)=%f \n", T, a, b); R=8.31451; /* J mol^-1 K^-1 */ n=1.0; /* mol */ for(V=0; V<10; V+=0.01) { if (V!=0) { p=(n*R*T)/(V-n*b)-a*(n/V)*(n/V); if (p>0) fprintf(stdout, "%f %f %f\n", p, V, 1/V); } } } \end{figure} \begin{figure}
\caption{van der Waals の状態方程式(p vs. V):
\ 理想気体の場合、He,Arの場合をあわせて表示.T=200K.}
\label{fig:vdw1}
\caption{van der Waals の状態方程式(p vs. 1/V).}
\label{fig:vdw2}
\end{figure} %%%%%%%%%%%%%%%%%%%% \subsection*{プログラムの解説} 以下に図\ref{prg:vdw}のプログラムについて解説する。解説の便宜上各行 に番号がついているが、実際にはこの番号は必要ない。 [line 1-2] プログラム中で用いる標準関数のプロトタイプや定数の宣言の ファイルをここに読み込む。始めのうちは c 言語の約束の呪文だと思って もよい。詳しくは解説書、文法書を参照のこと。 [line 4] このプログラムは、メインルーチンだけからなる。起動時にコマ ンドラインから指定した引数を使用する。 [line 5-7] プログラム中で用いる変数の型を宣言する。ここではすべて浮 動小数点による実数型である。 [line 9-13] 起動時にコマンドラインから指定した引数の数がおかしければ、 簡単な使い方の説明とあわせて表示し、プログラムを終了する。 fprintf 関数をもちいてメッセージを標準エラー出力に表示する。 exit 関数はプログラムを終了し、引数を OS に返す。 [line 15-17] 起動時にコマンドラインから指定した引数を変数に代入する。 [line 18] きちんと値が代入されたかどうかの確認のため、変数の値を標 準エラー出力に表示する。 [line 21-22] プログラム中で使用する物理定数の値を変数に代入する。 n と R は定数変数としても良いが、このプログラムでは通常の変数にし てある。 [line 24-30] 体積 V を変えながら、その時の圧力 p を計算する。計算は V \neq 0 の時にのみおこない、また p > 0 の時にのみ結果を標準出力に 表示する。 プログラムの実行時に、コマンドラインで標準出力をリダイレクトすれば、 計算結果だけをファイルに得ることができる。これを表計算ソフトなどで 図示することができる。 [line 26] van der Waals の実在気体の状態方程式により、気体の圧力を 計算する。 [line 28] 計算結果を標準出力に表示する。p,V だけでなく、1/V も出力する。 このプログラムは、25行と27行の if 文でわかるように、特定の条件 を満たした場合にのみ、計算および結果の出力を行うようになっている。 式の上ではどんな計算も可能であるが、意味のある結果であるかどうかの判 断は、利用する人間が考えなければならない。計算機で求めた結果であるこ とは、結果の正しさとは無関係である。 \begin{exam} 図\ref{prg:vdw}のプログラムを入力し、動作を確かめよ。\footnote{% backslash と yen の記号は表示の上では異なるが、機械内部のコードとしては 同じものである。適宜読み換えること。} \end{exam} \begin{exam} 25行と27行の if 文による制限を取り払うとどんな結果になるか。 \end{exam} \begin{exam} 実行時にコマンドラインから指定する引数として、表\ref{tbl:vdW}に示す値 とは異なるものを試してみよ。どのような結果が得られるか。 \end{exam} \begin{exam} 教科書から適当な式を拾いだし、そのグラフを描くプログラムを作ってみよう。 \end{exam} \begin{prob} 球面調和関数(Spherical Harmonics)の形を、極座標で描け。\footnote{% P. K. Atkins, {\it Physical Chemistry}, 5th ed., Oxford, p. 413.} 2p, 3d 軌道からそれぞれひとつずつ描け。興味があれば 4f 軌道についても 試みよ。これは例えば y=0 の xz 平面において(\phi=0)、\theta を 0--2\pi まで変化させた時の関数の値の絶対値を、その方向での原点 からの距離に対応させればよい。これは xz 平面による断面図にである。 形がわかれば良いので、規格化定数は省略してよい。また数学関数を用い るので、math.h を #include すること。 \end{prob} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{群の表現行列の積} 分子の性質を調べる場合に、分子の形を考えにいれておくと、わかりやすい 場合が多い。この様な分子の形をとりあつかう学問分野に、 ``群論(group theory)''というものがある。\footnote% {P. K. Atkins, {\it Physical Chemistry}, 5th ed., Oxford, Chapter 15, pp.511--538.} 群論では分子をある軸の回りでまわしたり、ある面で鏡映させたときに、 もとの分子とぴったり重なるような操作(対称操作)について考える。 回れ右してから鏡に映すと、その結果がどうなるかを考えるわけである。 この様な対称操作は、数学的には行列をもちいて記述でき、上の例では それぞれの操作を表す行列の積を求めるのである。 例えばアンモニア分子(NH_3)のようなものは C_{3v} の点群に属すると言い、 ここで考えられる対称操作は、 動かさない(E)、N を通る軸で 120度回す(C_3)、同じ軸で 240度回す(C_3^2)、 N-H のひとつを含む面で鏡映する( 3通り、(\sigma_v,\sigma_{v'},\sigma_{v''}))、 の合計 6通りのものがある。これらを 4 x 4 の行列で表すと 表\ref{tbl:c3v}の様に書くことができる。 またこれらの対称操作の積は表\ref{tbl:mult}の様になる。 ここでは、Firstの操作をあらわす行列が右に、Secondの方が左にくる。 (New\_operation) = (Second)(First) \begin{table} \caption{The matrix representation of C_{3v}.} \label{tbl:c3v} ------------------------------------------------- E & C_3 & C_3^2 ( 1 0 0 0 ) ( 1 0 0 0 ) ( 1 0 0 0 ) ( 0 1 0 0 ) ( 0 0 0 1 ) ( 0 0 1 0 ) ( 0 0 1 0 ) ( 0 1 0 0 ) ( 0 0 0 1 ) ( 0 0 0 1 ) ( 0 0 1 0 ) ( 0 1 0 0 ) ------------------------------------------------- \sigma_v & \sigma_{v'} & \sigma_{v''} ( 1 0 0 0 ) ( 1 0 0 0 ) ( 1 0 0 0 ) ( 0 1 0 0 ) ( 0 0 1 0 ) ( 0 0 0 1 ) ( 0 0 0 1 ) ( 0 1 0 0 ) ( 0 0 1 0 ) ( 0 0 1 0 ) ( 0 0 0 1 ) ( 0 1 0 0 ) ------------------------------------------------- \end{table} %%%%% \begin{table} \caption{The multiplication table of C_{3v}.} \label{tbl:mult} ---------------------------------------------------------------- First & E & C_3 & C_3^2 & \sigma_v & \sigma_{v'} & \sigma_{v''} ---------------------------------------------------------------- Second E & E & C_3 & C_3^2 & \sigma_v & \sigma_{v'} & \sigma_{v''} C_3 & C_3 & C_3^2 & E & \sigma_{v'} & \sigma_{v''} & \sigma_v C_3^2 & C_3^2 & E & C_3 & \sigma_{v''} & \sigma_v & \sigma_{v'} \sigma_v & \sigma_v & \sigma_{v''} & \sigma_{v'} & E & C_3^2 & C_3 \sigma_{v'} & \sigma_{v'} & \sigma_v & \sigma_{v''} & C_3 & E$ & C_3^2 \sigma_{v''} & \sigma_{v''} & \sigma_{v'} & \sigma_v & C_3^2 & C_3 & E ---------------------------------------------------------------- \end{table} % n次元の行列 A と B があって、それぞれの(i,j)要素が a_{ij},b_{ij} であるとする。このときの積 C=AB の(i,j)要素 c_{ij} は、 c_{ij} = \sum_{k=1}^{n} a_{ik}b_{kj} と書くことができる。行列の積を計算するプログラムは、これをそのまま 記述すれば良い。プログラムを図\ref{prg:mat1},\ref{prg:mat2}に示す。 \begin{figure} \caption{ 4 x 4 行列ふたつの積を計算するプログラム. メインルーチンだけのファイルにする.} \label{prg:mat1} #include#include void input_mat44( float m[4][4] ); void print_mat44( float m[4][4] ); void main() { int i, j, k; float w; float A[4][4], B[4][4], C[4][4]; fprintf(stderr,"Input matrix A \n"); input_mat44( A ); fprintf(stderr,"Input matrix B \n"); input_mat44( B ); fprintf(stderr,"Print matrix A \n"); print_mat44( A ); fprintf(stderr,"Print matrix B \n"); print_mat44( B ); for(i=0; i<4; i++) { for(j=0; j<4; j++) { w=0; for(k=0; k<4; k++) w+=A[i][k]*B[k][j]; C[i][j]=w; } } fprintf(stderr,"Print resulting matrix C=AB \n"); print_mat44( C ); } #include "mat2.c" \end{figure} \begin{figure} \verbatimlisting{mat2.c} \caption{ 4 x 4 行列ふたつの積を計算するプログラムの続き. ``mat2.c''というファイル名にすること.} \label{prg:mat2} void input_mat44( float m[4][4] ) { int i, j; for(i=0; i<4; i++) for(j=0; j<4; j++) { fprintf(stderr, "m[%i][%i] = ", i,j); scanf("%f", &(m[i][j])); } } void print_mat44( float m[4][4] ) { int i, j; for(i=0; i<4; i++) { for(j=0; j<4; j++) fprintf(stderr, "%f ", m[i][j]); fprintf(stderr, "\n"); } } \end{figure} %%%%%%%%%%%%%%%%%% \subsection*{プログラムの解説} 以下に図\ref{prg:mat1}のプログラムについて解説する。解説の便宜上各行 に番号がついているが、実際にはこの番号は必要ない。また、テキスト作成 の都合でプログラムは図\ref{prg:mat1}と図\ref{prg:mat2}のふたつのファ イルに分割されており、後者は mat2.c というファイル名である必要がある。 もちろんひとつのファイルに結合しても良いが、その場合には図\ref{prg:mat1}の 34行目の #include 文は削除する。 [line 1-2] プログラム中で用いる標準関数のプロトタイプや定数の宣言の ファイルをここに読み込む。 [line 4-5] 用いているサブルーチンのプロトタイプ宣言。 [line 7] このプログラムは、処理の一部をサブルーチンにしているが、中 心となる処理はこのメインルーチンに書いてある。サブルーチンは 図\ref{prg:mat2}に示す。 [line 9-11] メインルーチン中で用いる変数の型を宣言。 [line 13-16] 4 x 4 行列を入力する。実際の入力はサブルーチン input_mat44 で行う。 [line 17-20] 確認のため、入力された行列を表示する。実際の表示は、サ ブルーチン print_mat44 で行う。 [line 22-28] 行列の積の計算。c_{ij} がいくつになるか、順次計算する。 [line 29-30] 計算結果の行列を表示する。 [line 34] テキスト作成の都合でサブルーチン部分が別ファイルになってい るが、それをここに読み込む。分割コンパイルはしない。 \begin{exam} 表\ref{tbl:c3v}の行列どうしの積を計算し、表\ref{tbl:mult}の様になって いることを確認せよ。 \end{exam} \begin{exam} その他のデータを入力し、行列の積が計算できることを確認せよ。 \end{exam} \begin{prob} 逆行列をもとめるサブルーチンを用い、 4元連立一次方程式を解くプログラムを作れ。 \end{prob} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{課題} ここまでに出てきた課題とあわせて、以下の課題からはひとつ以上を選んで プログラムを作成し、レポートとして提出せよ。レポートはプログラムのソ ースリスト、プログラムの流れ(計算手順、アルゴリズム)の簡単な解説、プ ログラムの実行結果、目的の図表とそれを得るための手順など、および今回 のプログラム作成に関する感想などを含み、ワードプロセッサで作成すること。 さらにこれらのデータは、各人のフロッピーディスクに記録し、氏名を書い たラベルをはって提出すること。協力した友人、参考図書などがあれば、も ちろん記すこと。 \begin{prob} n次の行列の逆行列を求めるプログラムを作れ。行列の次数はデータで指定 できるようにせよ。逆行列を求めるアルゴリズムとしては、(1)ガウスの消 去法を用いる(掃き出し法)、(2)行列の余因子を用いる、(3)固有値分解を用 いる、等の方法が考えられるが、どんなアルゴリズムを用いたかの説明をつ けること。また、入力データを確認し、間違いがあれば訂正できるような機 能を持たせよ。逆行列がないような行列を、入力データとして与えた場合に は、正しく処理を中止して、その旨表示するようにすること。 \end{prob} \begin{prob} 次に挙げる関数を x=0 の近傍で Taylor 展開し、高次の項までとるにつれて 近似が良くなる様子を図示せよ。 (1) $\sin(x)$; (2) $\exp(-x)$; (3) $1/x$ \end{prob} \begin{prob} 次に挙げる関数の積分(定積分)を計算し、区間の分割の程度と計算手法に よる違いや、解析的な値との差を調べ、必要なら図示せよ。 (1) $\sin(x),~[0\sim\pi]$; (2) $\exp(-x),~[0\sim1]$; (3) $1/x,~[1\sim2]$ \end{prob} \begin{prob} 表\ref{tbl:pvt},\ref{tbl:pvt2}\ に与えるデータを直線にあてはめ、 データ点と直線を図示せよ。また、表\ref{tbl:wtph}\ に与えるデータを 2次曲線にあてはめるとどうなるか。 \begin{table}[h] \caption{Data1} \label{tbl:pvt} --------------- t & p --------------- 3.62 & 0.96541 3.59 & 0.91373 3.53 & 0.80672 3.52 & 0.78949 3.49 & 0.76586 3.48 & 0.73067 3.46 & 0.70854 3.45 & 0.67210 3.43 & 0.64124 3.41 & 0.62337 3.40 & 0.59077 3.38 & 0.56463 3.37 & 0.54156 3.35 & 0.51327 3.34 & 0.49933 3.33 & 0.48062 3.32 & 0.46218 3.28 & 0.39637 3.27 & 0.37702 3.26 & 0.35421 3.23 & 0.32186 3.22 & 0.29569 ---------------- \caption{Data2} \label{tbl:wtph} ------------ w & t ------------ 10 & 45.3 15 & 58.9 20 & 64.0 25 & 66.5 30 & 67.1 36 & 67.2 40 & 67.0 45 & 66.2 55 & 61.0 64 & 48.0 70 & 31.0 ------------ \end{table} \end{prob} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section*{参考図書} * プログラム作成に当たっての考え方 + B. W. カーニハン、P. J. プローガー \ 著、木村泉訳、 「プログラム書法 \ 第2版」、共立出版 + B. W. カーニハン、P. J. プローガー \ 著、木村泉訳、 「ソフトウェア作法」、共立出版 * アルゴリズムに関するもの + N. ヴィルト \ 著、浦昭二・國府方久史 \ 共訳、 「アルゴリズムとデータ構造」、近代科学社 + 奥村晴彦、「C言語による最新アルゴリズム辞典」、技術評論社 * C言語に関するもの + B.W.カーニハン、D.M.リッチー \ 著、石田晴久 \ 訳、 「プログラミング言語 C \ 第2版」、共立出版 + 「改訂第3版 \ C言語入門」、アスキー * 数値計算に関するもの + 高橋大輔、理工系の基礎数学 \ 8 \ 「数値計算」、岩波書店 + 森正武、「FORTRAN77 \ 数値計算プログラミング \ 増補版」、岩波書店 + 小池慎一、「改訂 \ Cによる科学技術計算」、CQ出版 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section*{付録:Exelでグラフを描く} 数値計算の結果をファイルに出力したら、その次にはこの結果をグラフに することを考える。このテキストでは図\ref{fig:vdw1},\ref{fig:vdw2}に 示したようなグラフを、gnuplot というソフトを用いて描いた。その他に もいろいろな方法があるだろうが、ここでは表計算ソフト(Exel)のグラフ 表示機能を利用する。 Exelによるグラフの書き方を、手順を追って示す。なおここで、グラフ化 しようとするデータは、PC98 の B: ドライブにあるフロッピーディスクの datafile という名前のファイルであるとする。データはx軸の値とy軸の値 がこの順で一行にひと組ずつ記述されており、数値は空白で区切られてい るものとする。 1) Windows3.1のExelをダブルクリックして起動する 2) Exelで、datafileを読み込む a) メニューバーの[ファイル]--[開く]を順に選ぶ b) ドライブ(b:)、ディレクトリ(\yen)、ファイル名(datafile)を順に指定する 3) テキストファイルウィザードが現れ、ファイルの形式を指定する a) 「区切り文字によるデータ並び」の形式を選ぶ b) 「列の区切り文字はスペース」をチェック c) データ形式は「標準」を選ぶ 4) ツールバーのグラフウィザードポタンを押す a) データ範囲を列ごとに2回指定する i) まずx軸のデータを指定する。$A$1 から縦に $A$9 までマウスを ドラッグすると、ウインドウに =$A$1:$A$9 の文字が入っている ii) カンマ(,)を入力する iii) y軸のデータとして、$B$1 から縦に $B$9 までマウスをドラッグする iv) ウインドウに =$A$1:$A$9,$B$1:$B$9 の文字が入っている b) グラフの種類として、「散布図(S)」を選ぶ c) グラフの形式を選ぶ。マークを打って、折れ線で結ぶのなら、(2)を選ぶ。 d) グラフのサンプルが表示されるので、「先頭の1列をxの値として 使用」すると設定する e) 必要ならグラフのタイトルや軸のラベルを設定する 5) 画面上に枠が表示され、グラフが描かれる。枠をマウスでドラッグす ると縦横好きな大きさに引き延ばされる 6) 枠の中程でマウスをドラッグすると、画面上でグラフの位置を動かす ことができる 7) 出来上がったら印刷してみよう a) この方法ではワークシート上にグラフが乗った形になっているので、 グラフの位置などを確認し、必要なら直す b) [ファイル]--[プレビュウ]で出来上がりを確かめる c) ([ファイル]--)[印刷]すると、ディスプレイの上部に張ってある色 のシールと同じプリンタから出力される d) 紙をむだにしないように %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%