pV=nRT 単位換算地獄 ~気体の状態方程式をPythonで! ep 1~

python
python

気体の温度、圧力、体積を計算する状態方程式!

あ~単位換算がメンドクサイ!

高校物理で習う「理想気体の状態方程式」は覚えていますか?
私は、これが嫌いでした。なぜなら、単位換算が面倒だから!

今回は、単位換算とか計算とか全部まとめてやってくれるヤツを作ってみましょう!
(2021年3月3日:学習開始12日目、PyQさんで学習中!

オンラインPython学習サービス「PyQ™(パイキュー)」


これから空気の性質を明らかにしていこう!という事で。。
魅惑の低音から晴れ渡る高音を使いこなす、新世代のミュージシャンmiletさんの「Grab the air」とともにやっていきます。

(公式YouTubeに飛びます。とてもお綺麗な方なので画像貼りたいけどやめておきます。)


※最後に「単位換算とか計算とか全部まとめてやってくれるヤツ」が出てきます。
全部コピペすればPythonで動かせる(動かし方参照:10分でプログラマーになろう ~100000000人をごぼう抜き~)ので、皆さんのPCで使っていただいてもOKです!
ただ、間違えていいるかもしれないので、そこはノークレームでお願いします。

1.状態方程式ってなんだっけ?

理想気体の状態方程式」を軽ーくおさらいしてみます。

「理想気体」:wikipediaの説明は難しい・・・。
簡単にいうと、分子のサイズと分子間力を無視した想像上の気体です。
いろいろな作用を無視することで、計算を簡単にできるという事ですね。

「状態方程式」:これもwikipediaの説明難しい・・・
詳しいことはパスして、理想気体ではこの式が成り立つって事だけ分かればいいか!。

ここで、pは圧力、Vは体積、nが分子の数、Tが温度です。
Rが気体定数で、pVnTをつなぐ比例定数です。
つまり、pVnTのうち、3つが分かれば残り1つが計算できるわけです。

便利な方程式ですが、面倒なところは、

圧力pの単位が多すぎる!
圧力の単位は、Pa、N/m2、bar、atm、Torr、mmHg、kgf / cm2 といったものが使用され、計算する際に換算が必要です。
②体積Vも地味にややこしい!
m3、cm3、L、mL、の変換も3乗で変わるので桁数が大きくなって面倒なのと、ヤード・ポンド法のガロン、クォート、パインなんかもあります。
③温度Tは絶対温度!
状態方程式では絶対温度を使用するので、一般的な温度から計算が必要です。
また、「一般的な温度」もセルシウス度(摂氏度℃)とファーレンハイト度(華氏°F)があります。

これらを計算できる形にそろえて初めて、方程式で計算できます。
もちろん、出てきた答えも欲しい形に変換する必要があります。
数字と単位をいれれば、一括で計算してくれるプログラムを作ります。

2.作戦会議

方針を決めていきましょう。

「フローチャート」を書いていきましょう。今回から、「draw.io」というサイトで書いてみます。

なるほど、最初の分岐以降は並列で計算する感じになりました。
というか、「draw.io」使いやす!これが無料、登録なしで保存できるとは・・・

では、プログラムを書いていきましょう!

3.プログラムを書いていこう!

プログラムを書いていきます。
今回から、defで関数を定義して書いていきます。まだ理解できていませんが、調べているとプログラムを書いている方は、ほぼそのような書き方をしています。おそらくかなりメリットがあるのだと思います。

さて、上から始めましょう。「求める値のインプット」「分岐」です。
まずはインプットです。(後で分かりますが、下記は誤りです。

def output_choice():
    print('状態方程式を使って圧力、体積、分子数、温度を求めます')
    print('どの物理量を求めますか?')
    motomeru = input('p → 1、V → 2、n → 3、T → 4、中止 → その他:')
    if motomeru in ['1', '2', '3,', '4']:
        return motomeru #p → 1、V → 2、n → 3、T → 4を返す。
    else:
        print('中止します')

続いて分岐です。

def bunki():
    if motomeru == '1':
        #Pを求める。
    elif motomeru == '2':
        #Vを求める。
    elif motomeru == '3':
        #nを求める。
    else:
        #Tを求める。

それぞれの計算は後で記載するので、今の段階ではここまでです。

pを求める場合から考えていきましょう。「求めるpの単位のインプット」は、上の「分岐」の中に入ることになります。

        #Pを求める。
        while True:
            print('求めるpの単位は?')
            p_ans_small_unit = 0
            p_ans_unit = 0
            while True:
                #単位が多いのでPa系かその他で分ける。
                p_ans_pa_or_not = input('Pa (=N/m2)系の単位? YES → y, NO → n:')
                if p_ans_pa_or_not == 'y':
                    p_ans_small_unit = input('Pa → 1、hPa → 2、kPa → 3、MPa → 4 : ')
                    break
                elif p_ans_pa_or_not == 'n':
                     #その他単位を決定
                    p_ans_unit = input('bar → 1、atm → 2、Torr(=mmHg) → 3、kgf/cm2 → 4、psi → 5 :')
                    break
                else:
                    print('y か nを入力してください')
            if p_ans_small_unit in ['1', '2', '3', '4'] or p_ans_unit in ['1', '2', '3', '4', '5']:
                break #適切なインプットか?
            else:
                print('単位入力に誤りがあります。')

単位多いわ!

次は、「V、n、Tのインプット」です。入力は、ほかでも使い回しすることになるので、ここで関数を定義しておいた方が良いように思います。(後で分かりますが、下記は誤りです

def v_kanzan_shiki():
    while True:
        v_val = float(input('体積Vの値は?:'))
        print('体積vの単位は?')
        v_unit = input('m3 → 1、cm3 → 2、L → 3、mL → 4、ヤード・ポンド法 → 5:') #単位を決定
        if v_unit == '5':#ヤード・ポンド単位を決定
            v_unit = input('ガロン(gallon) → 6、クォート(quart) → 7、パイント(pint) → 8:')
        else:
            pass
        if v_unit in ['1', '2', '3,', '4', '6', '7', '8']:
            break #適切なインプットか?
        else:
            print('単位入力に誤りがあります。')
    #単位をm3で統一していく。
    if v_unit == '1':
        v_kanzan = v_val
        print(f'v : {v_val}m3')
    elif v_unit == '2':
        v_kanzan = v_val/1000000 #1 m3 = 1000000 cm3
        print(f'v : {v_val}cm3 = {v_kanzan:5f}m3')
    elif v_unit == '3':
        v_kanzan = v_val/1000 #1 m3 = 1000 L
        print(f'v : {v_val}L = {v_kanzan:.5f}m3')
    elif v_unit == '4':
        v_kanzan = v_val/1000000 #1 m3 = 1000000 mL
        print(f'v : {v_val}mL = {v_kanzan:.5f}m3')
    elif v_unit == '6':
        v_kanzan = v_val/219.969 #1 m3 =219.969 gallon
        print(f'v : {v_val}gallon = {v_kanzan:.5f}m3')
    elif v_unit == '7':
        v_kanzan = v_val/879.877 #1 m3 = 879.877 quart
        print(f'v : {v_val}quart = {v_kanzan:.5f}m3')
    else:
        v_kanzan = v_val/1759.754 #1 m3 = 1759.754 pint
        print(f'v : {v_val}pint = {v_kanzan:.5f}m3')

Vだけでこんなことになりました。次はnです。重量から行けるようにしています。(重量のヤード・ポンド法はスルーさせてもらいます。)(後で分かりますが、下記は誤りです。

def n_kanzan_shiki():
    while True:
        n_val = float(input('物質量n(または重量)の値は?:'))
        print('物質量n(または重量)の単位は?')
        n_unit = input('mol → 1、個 → 2、重量 → 3 :') #単位を決定
        g_unit = 0 #重量単位を決定g_unitを定義
        if n_unit == '3':#ヤード・ポンド単位を決定
            g_unit = input('g → 4、mg→ 5、kg → 6、ton → 7:')
            bunnshi_ryou = float(input('気体の分子量を入れてください:'))
        else:
            pass
        if n_unit in ['1', '2'] or g_unit in ['4', '5', '6', '7']:
            break #適切なインプットか?
        else:
            print('単位入力に誤りがあります。')
            #単位をmolで統一していく。
    if n_unit == '1':
        n_kanzan = n_val
        print(f'n : {n_val}mol')
    elif n_unit == '2':
        n_kanzan = n_val/(6.022*10**23) #1 mol = 6.022*10**23個
        print(f'n : {n_val}個 = {n_kanzan:5E}mol')
    else:
        if g_unit == '4':
            n_kanzan = n_val/bunnshi_ryou #1 mol = g/M
            print(f'n : {n_val}g = {n_kanzan:.5f}mol')
        elif g_unit == '5':
            n_kanzan = n_val/(1000*bunnshi_ryou) #1 mol = mg/1000M
            print(f'n : {n_val}mg = {n_kanzan:.5f}mol')
        elif g_unit == '6':
            n_kanzan = (1000*n_val)/bunnshi_ryou #1 mol = 1000kg/M
            print(f'n : {n_val}kg = {n_kanzan:.5f}mol')
        else:
            n_kanzan = (1000000*n_val)/bunnshi_ryou #1 mol = 1000000t/M
            print(f'n : {n_val}ton = {n_kanzan:.5f}mol')

次は、Tです。絶対温度換算をしておく必要がありますね。(後で分かりますが、下記は誤りです。

def t_kanzan_shiki():
    while True:
        t_val = float(input('温度Tの値は?:'))
        print('温度Tの単位は?')
        t_unit = input('K (絶対温度) → 1、℃ (摂氏温度)→ 2、℉ (華氏温度) → 3 :') #単位を決定
        if t_unit in ['1', '2', '3']:
            break #適切なインプットか?
        else:
            print('単位入力に誤りがあります。')
            #単位をKで統一していく。
    if t_unit == '1':
        t_kanzan = t_val
        print(f'T : {t_val}K')
    elif t_unit == '2':
        t_kanzan = t_val + 273.15  #1 K = -273.15 ℃
        print(f'T : {t_val}℃ = {t_kanzan:5f}K')
    else:
        t_kanzan = ((t_val-32)/1.8) + 273.15  #1 ℃ = (℉ - 32)/1.8 
        print(f'T : {t_val}℉ = {t_kanzan:5f}K')

これまでより短いです。日本ではほぼ使わないですが、華氏温度がややこしいですね。

華氏温度は、ドイツの物理学者ガブリエル・ファーレンハイトが考案した温度で、由来は諸説あるそうですが、当時作れ出せた温度(水,氷,食塩を混ぜて得られる温度らしいです)を0°F、氷の融点を32°F(=0℃)、体温を96°F(=35.5℃)としたものだそうです。
体温低めです!ファーレンハイトさん。当時は便利だったのでしょうが、現在で0°Fはあまり意味のない数字になってしまっています。ファーレンハイトさんには悪いですが、もう華氏はやめようよ、人類!

ところで、ここまででV、n、Tの入力と換算が終わったのでpの計算に移れるのですが、ほかの計算でpの換算は使うので、ここで作っておきます。では「pの換算の定義」です。(後で分かりますが、下記は誤りです。

def p_kanzan_shiki():
    while True:
        p_val = float(input('圧力pの値は?:'))
        print('圧力pの単位は?')
        while True:
            p_pa_or_not = input('Pa (=N/m2)系の単位? YES → y, NO → n:') #単位が多いのでPa系かその他で分ける。
            p_small_unit = 0
            p_unit = 0
            if p_pa_or_not == 'y':
                p_small_unit = input('Pa → 1、hPa → 2、kPa → 3、MPa → 4 : ')
                break
            elif p_pa_or_not == 'n':
                p_unit = input('bar → 1、atm → 2、Torr(=mmHg) → 3、kgf/cm2 → 4、psi → 5 :') #その他単位を決定
                break
            else:
                print('y か nを入力してください')
        if p_small_unit in ['1', '2', '3', '4'] or p_unit in ['1', '2', '3', '4', '5']:
            break #適切なインプットか?
        else:
            print('単位入力に誤りがあります。')
            #単位をPaで統一していく。
    if p_small_unit == '1':
        p_kanzan = p_val
        print(f'p : {p_kanzan}Pa')
    elif p_small_unit == '2':
        p_kanzan = 100*p_val #hpa = 100pa。
        print(f'p : {p_val}hPa = {p_kanzan:5f}Pa')
    elif p_small_unit == '3':
        p_kanzan = 1000*p_val #kpa = 1000pa。
        print(f'p : {p_val}kPa = {p_kanzan:5f}Pa')
    elif p_small_unit == '4':
        p_kanzan = 1000000*p_val #Mpa = 1000000pa。
        print(f'p : {p_val}MPa = {p_kanzan:5f}Pa')
    elif p_unit == '1':
        p_kanzan = 100000*p_val #bar = 100000pa。
        print(f'p : {p_val}bar = {p_kanzan:5f}Pa')
    elif p_unit == '2':
        p_kanzan = 101325*p_val #atm = 101325pa。
        print(f'p : {p_val}atm = {p_kanzan:5f}Pa')
    elif p_unit == '3':
        p_kanzan = 133.322*p_val #Torr = 133.322pa。
        print(f'p : {p_val}Torr(=mmHg) = {p_kanzan:5f}Pa')
    elif p_unit == '4':
        p_kanzan = 98066.5*p_val #kgf/cm2 = 98066.5pa。
        print(f'p : {p_val}kgf/cm2 = {p_kanzan:5f}Pa')
    else:
        p_kanzan = 6894.76*p_val #psi = 6894.76pa。
        print(f'p : {p_val}psi = {p_kanzan:5f}Pa')

長い・・・。まあ、とにかくこれでインプット側の単位換算は完了です。

つぎは、pを求めるところに進みましょう。pV = nRTですので、p =nRT/Vですね。
ここまで単位は、p[Pa]、V[m3]、n[mol]、T[K]で統一してきました。
ですので気体定数R = 8.314462 [J/K・mol] (J =Pa·m3)であり、pはPaで求まります

プログラムを書いていきますが、位置は、「求めるpの単位input」→「V、n、Tのinput」の下にきます。Rは今後共通で使うので上で定義しておきましょう。

def bunki():
    R = 8.314462 #気体定数[J/K・mol]
    if motomeru == '1':
        #Pを求める。
        while True:
~~~略~~~
                print('単位入力に誤りがあります。')
        v_kanzan_shiki()
        n_kanzan_shiki()
        t_kanzan_shiki()
        p_ans_val = (n_kanzan * R * T_kanzan)/v_kanzan #p[Pa] = nRT/V

pがPa単位で計算しました。

なるほど、defで関数定義すると、後で楽になるというのがよく分かります
今回は行き当たりばったりでしたが、先に必要な道具(=関数)を用意するイメージができれば、関数を先に作っておいて、それを集約していけばプログラムが組みあがるわけですね!

では、Paを求める単位に換算しましょう。前に作った、pの換算式を改変すればできそうです。

        p_ans_val = (n_kanzan * R * T_kanzan)/v_kanzan #p[Pa] = nRT/V
        if p_ans_small_unit == '1':
            p_ans_kanzan = p_ans_val
            print(f'求める圧力p : {p_ans_kanzan}Pa')
        elif p_ans_small_unit == '2':
            p_ans_kanzan = p_ans_val/100 #hpa = 100pa。
            print(f'求める圧力p : {p_ans_val}Pa = {p_ans_kanzan:5f}hPa')
        elif p_ans_small_unit == '3':
            p_ans_kanzan = p_ans_val/1000 #kpa = 1000pa。
            print(f'求める圧力p  : {p_ans_val}Pa = {p_ans_kanzan:5f}kPa')
        elif p_ans_small_unit == '4':
            p_ans_kanzan = p_ans_val/1000000 #Mpa = 1000000pa。
            print(f'求める圧力p  : {p_ans_val}Pa = {p_ans_kanzan:5f}MPa')
        elif p_ans_unit == '1':
            p_ans_kanzan = p_ans_val/100000 #bar = 100000pa。
            print(f'求める圧力p  : {p_ans_val}Pa = {p_ans_kanzan:5f}bar')
        elif p_ans_unit == '2':
            p_ans_kanzan = p_ans_val/101325 #atm = 101325pa。
            print(f'求める圧力p  : {p_ans_val}pa = {p_ans_kanzan:5f}atm')
        elif p_ans_unit == '3':
            p_ans_kanzan = p_ans_val/133.322 #Torr = 133.322pa。
            print(f'求める圧力p  : {p_ans_val}Pa = {p_ans_kanzan:5f}Torr(=mmHg)')
        elif p_ans_unit == '4':
            p_ans_kanzan = p_ans_val/98066.5 #kgf/cm2 = 98066.5pa。
            print(f'求める圧力p  : {p_ans_val}Pa = {p_ans_kanzan:5f}kgf/cm2')
        else:
            p_ans_kanzan = p_ans_val/6894.76 #psi = 6894.76pa。
            print(f'求める圧力p  : {p_ans_val}Pa = {p_ans_kanzan:5f}psi')

いままでのものをまとめると、pが求まるはずです。
まずbunki()の冒頭にoutput_choice()をもってきて、bunki()を実行すればよいはずです。
ここでは長くなる(+かなり誤りがある)ので、略しますがやってみると、まず「どの物理量を求めるか?」の一連の質問があり、その後このような結果になります。

NameError: name 'motomeru' is not defined

output_choice()の中のmatomeruが定義できていないということです。どういう事でしょうか?
(この後、いろいろ試すこと数十分・・・)

defの使い方に誤りがあります。
今の状態でoutput_choice()を実行するとどうなるか?pを選んだ場合、単に値’1’が帰ってきています。「matomeru =’1’」ではありません。
ということは、XXXX = output_choice()のような形にして返してやり、XXXXで分岐させる必要があります。
また同じことが、p、V、n、Tのインプットでも言えます。いままではreturnがなく、printしていただけでした。
これは大幅な修正が必要です。修正点は以下です。

修正①:output_choice()をbunki_choiceで受ける。
修正②:motomeruではなくbunki_choiceで分岐させる。
修正③:def v_kanzan_shiki()をreturn v_kanzanで返す。(n、T、pも同様)
修正④:v_kanzan_shiki()をv_inpで受ける。(n、T、pも同様)
修正⑤:pの計算をv_inpをもとにおこなう。

def v_kanzan_shiki():
    while True:
~~~略~~~
    return v_kanzan #v_kanzanを返す
~~~略~~~
def bunki():
    bunki_choice = output_choice() #output_choice()をbunki_choiceで受ける。
~~~略~~~
    if bunki_choice == '1':
        #Pを求める。
~~~略~~~
        v_inp = v_kanzan_shiki() #v_kanzanをv_inpで受ける
        n_inp = n_kanzan_shiki() #n_kanzanをn_inpで受ける
        t_inp = t_kanzan_shiki() #t_kanzanをt_inpで受ける
        p_ans_val = (n_inp * R * t_inp)/v_inp #p[Pa] = nRT/V
~~~略~~~
bunki()

できました!!きちんとpが求まりました。(pのみで動かすため、分岐の2~4はpassで通しています。)

あとは、pと同じように、n、V、Tのアウトプットをやっていきます。
ここでは繰り返しで長くなるので、それぞれのコードは省略して最終形態を載せます。

def output_choice():
    print('状態方程式を使って圧力、体積、分子数、温度を求めます')
    print('どの物理量を求めますか?')
    motomeru = input('p → 1、V → 2、n → 3、T → 4、中止 → その他:')
    if motomeru in ['1', '2', '3', '4']:
        return motomeru #p → 1、V → 2、n → 3、T → 4を返す。
    else:
        print('中止します')

def v_kanzan_shiki():
    while True:
        v_val = float(input('体積Vの値は?:'))
        print('体積vの単位は?')
        v_unit = input('m3 → 1、cm3 → 2、L → 3、mL → 4、ヤード・ポンド法 → 5:') #単位を決定
        if v_unit == '5':#ヤード・ポンド単位を決定
            v_unit = input('ガロン(gallon) → 6、クォート(quart) → 7、パイント(pint) → 8:')
        else:
            pass
        if v_unit in ['1', '2', '3', '4', '6', '7', '8']:
            break #適切なインプットか?
        else:
            print('単位入力に誤りがあります。')
    #単位をm3で統一していく。
    if v_unit == '1':
        v_kanzan = v_val
        print(f'v : {v_val}m3')
    elif v_unit == '2':
        v_kanzan = v_val/1000000 #1 m3 = 1000000 cm3
        print(f'v : {v_val}cm3 = {v_kanzan:5f}m3')
    elif v_unit == '3':
        v_kanzan = v_val/1000 #1 m3 = 1000 L
        print(f'v : {v_val}L = {v_kanzan:.5f}m3')
    elif v_unit == '4':
        v_kanzan = v_val/1000000 #1 m3 = 1000000 mL
        print(f'v : {v_val}mL = {v_kanzan:.5f}m3')
    elif v_unit == '6':
        v_kanzan = v_val/219.969 #1 m3 =219.969 gallon
        print(f'v : {v_val}gallon = {v_kanzan:.5f}m3')
    elif v_unit == '7':
        v_kanzan = v_val/879.877 #1 m3 = 879.877 quart
        print(f'v : {v_val}quart = {v_kanzan:.5f}m3')
    else:
        v_kanzan = v_val/1759.754 #1 m3 = 1759.754 pint
        print(f'v : {v_val}pint = {v_kanzan:.5f}m3')
    return v_kanzan #v_kanzanを返す
        
def n_kanzan_shiki():
    while True:
        n_val = float(input('物質量n(または重量)の値は?:'))
        print('物質量n(または重量)の単位は?')
        n_unit = input('mol → 1、個 → 2、重量 → 3 :') #単位を決定
        g_unit = 0 #重量単位を決定g_unitを定義
        if n_unit == '3':#ヤード・ポンド単位を決定
            g_unit = input('g → 4、mg→ 5、kg → 6、ton → 7:')
            bunnshi_ryou = float(input('気体の分子量を入れてください:'))
        else:
            pass
        if n_unit in ['1', '2'] or g_unit in ['4', '5', '6', '7']:
            break #適切なインプットか?
        else:
            print('単位入力に誤りがあります。')
            #単位をmolで統一していく。
    if n_unit == '1':
        n_kanzan = n_val
        print(f'n : {n_val}mol')
    elif n_unit == '2':
        n_kanzan = n_val/(6.022*10**23) #1 mol = 6.022*10**23個
        print(f'n : {n_val}個 = {n_kanzan:5E}mol')
    else:
        if g_unit == '4':
            n_kanzan = n_val/bunnshi_ryou #1 mol = g/M
            print(f'n : {n_val}g = {n_kanzan:.5f}mol')
        elif g_unit == '5':
            n_kanzan = n_val/(1000*bunnshi_ryou) #1 mol = mg/1000M
            print(f'n : {n_val}mg = {n_kanzan:.5f}mol')
        elif g_unit == '6':
            n_kanzan = (1000*n_val)/bunnshi_ryou #1 mol = 1000kg/M
            print(f'n : {n_val}kg = {n_kanzan:.5f}mol')
        else:
            n_kanzan = (1000000*n_val)/bunnshi_ryou #1 mol = 1000000t/M
            print(f'n : {n_val}ton = {n_kanzan:.5f}mol')
    return n_kanzan

def t_kanzan_shiki():
    while True:
        t_val = float(input('温度Tの値は?:'))
        print('温度Tの単位は?')
        t_unit = input('K (絶対温度) → 1、℃ (摂氏温度)→ 2、℉ (華氏温度) → 3 :') #単位を決定
        if t_unit in ['1', '2', '3']:
            break #適切なインプットか?
        else:
            print('単位入力に誤りがあります。')
            #単位をKで統一していく。
    if t_unit == '1':
        t_kanzan = t_val
        print(f'T : {t_val}K')
    elif t_unit == '2':
        t_kanzan = t_val + 273.15  #1 K = -273.15 ℃
        print(f'T : {t_val}℃ = {t_kanzan:5f}K')
    else:
        t_kanzan = ((t_val-32)/1.8) + 273.15  #1 ℃ = (℉ - 32)/1.8 
        print(f'T : {t_val}℉ = {t_kanzan:5f}K')
    return t_kanzan

def p_kanzan_shiki():
    while True:
        p_val = float(input('圧力pの値は?:'))
        print('圧力pの単位は?')
        while True:
            p_pa_or_not = input('Pa (=N/m2)系の単位? YES → y, NO → n:') #単位が多いのでPa系かその他で分ける。
            p_small_unit = 0
            p_unit = 0
            if p_pa_or_not == 'y':
                p_small_unit = input('Pa → 1、hPa → 2、kPa → 3、MPa → 4 : ')
                break
            elif p_pa_or_not == 'n':
                p_unit = input('bar → 1、atm → 2、Torr(=mmHg) → 3、kgf/cm2 → 4、psi → 5 :') #その他単位を決定
                break
            else:
                print('y か nを入力してください')
        if p_small_unit in ['1', '2', '3', '4'] or p_unit in ['1', '2', '3', '4', '5']:
            break #適切なインプットか?
        else:
            print('単位入力に誤りがあります。')
            #単位をPaで統一していく。
    if p_small_unit == '1':
        p_kanzan = p_val
        print(f'p : {p_kanzan}Pa')
    elif p_small_unit == '2':
        p_kanzan = 100*p_val #hpa = 100pa。
        print(f'p : {p_val}hPa = {p_kanzan:5f}Pa')
    elif p_small_unit == '3':
        p_kanzan = 1000*p_val #kpa = 1000pa。
        print(f'p : {p_val}kPa = {p_kanzan:5f}Pa')
    elif p_small_unit == '4':
        p_kanzan = 1000000*p_val #Mpa = 1000000pa。
        print(f'p : {p_val}MPa = {p_kanzan:5f}Pa')
    elif p_unit == '1':
        p_kanzan = 100000*p_val #bar = 100000pa。
        print(f'p : {p_val}bar = {p_kanzan:5f}Pa')
    elif p_unit == '2':
        p_kanzan = 101325*p_val #atm = 101325pa。
        print(f'p : {p_val}atm = {p_kanzan:5f}Pa')
    elif p_unit == '3':
        p_kanzan = 133.322*p_val #Torr = 133.322pa。
        print(f'p : {p_val}Torr(=mmHg) = {p_kanzan:5f}Pa')
    elif p_unit == '4':
        p_kanzan = 98066.5*p_val #kgf/cm2 = 98066.5pa。
        print(f'p : {p_val}kgf/cm2 = {p_kanzan:5f}Pa')
    else:
        p_kanzan = 6894.76*p_val #psi = 6894.76pa。
        print(f'p : {p_val}psi = {p_kanzan:5f}Pa')
    return p_kanzan

def bunki():
    bunki_choice = output_choice() #output_choice()をbunki_choiceで受ける。
    R = 8.314462 #気体定数[J/K・mol]
    if bunki_choice == '1':
        #Pを求める。
        while True:
            print('求めるpの単位は?')
            p_ans_small_unit = 0
            p_ans_unit = 0
            while True:
                #単位が多いのでPa系かその他で分ける。
                p_ans_pa_or_not = input('Pa (=N/m2)系の単位? YES → y, NO → n:')
                if p_ans_pa_or_not == 'y':
                    p_ans_small_unit = input('Pa → 1、hPa → 2、kPa → 3、MPa → 4 : ')
                    break
                elif p_ans_pa_or_not == 'n':
                     #その他単位を決定
                    p_ans_unit = input('bar → 1、atm → 2、Torr(=mmHg) → 3、kgf/cm2 → 4、psi → 5 :')
                    break
                else:
                    print('y か nを入力してください')
            if p_ans_small_unit in ['1', '2', '3', '4'] or p_ans_unit in ['1', '2', '3', '4', '5']:
                break #適切なインプットか?
            else:
                print('単位入力に誤りがあります。')
        v_inp = v_kanzan_shiki() #v_kanzanをv_inpで受ける
        n_inp = n_kanzan_shiki() #n_kanzanをn_inpで受ける
        t_inp = t_kanzan_shiki() #t_kanzanをt_inpで受ける
        p_ans_val = (n_inp * R * t_inp)/v_inp #p[Pa] = nRT/V
        if p_ans_small_unit == '1':
            p_ans_kanzan = p_ans_val
            print(f'求める圧力p : {p_ans_kanzan}Pa')
        elif p_ans_small_unit == '2':
            p_ans_kanzan = p_ans_val/100 #hpa = 100pa。
            print(f'求める圧力p : {p_ans_val}Pa = {p_ans_kanzan:5f}hPa')
        elif p_ans_small_unit == '3':
            p_ans_kanzan = p_ans_val/1000 #kpa = 1000pa。
            print(f'求める圧力p  : {p_ans_val}Pa = {p_ans_kanzan:5f}kPa')
        elif p_ans_small_unit == '4':
            p_ans_kanzan = p_ans_val/1000000 #Mpa = 1000000pa。
            print(f'求める圧力p  : {p_ans_val}Pa = {p_ans_kanzan:5f}MPa')
        elif p_ans_unit == '1':
            p_ans_kanzan = p_ans_val/100000 #bar = 100000pa。
            print(f'求める圧力p  : {p_ans_val}Pa = {p_ans_kanzan:5f}bar')
        elif p_ans_unit == '2':
            p_ans_kanzan = p_ans_val/101325 #atm = 101325pa。
            print(f'求める圧力p  : {p_ans_val}pa = {p_ans_kanzan:5f}atm')
        elif p_ans_unit == '3':
            p_ans_kanzan = p_ans_val/133.322 #Torr = 133.322pa。
            print(f'求める圧力p  : {p_ans_val}Pa = {p_ans_kanzan:5f}Torr(=mmHg)')
        elif p_ans_unit == '4':
            p_ans_kanzan = p_ans_val/98066.5 #kgf/cm2 = 98066.5pa。
            print(f'求める圧力p  : {p_ans_val}Pa = {p_ans_kanzan:5f}kgf/cm2')
        else:
            p_ans_kanzan = p_ans_val/6894.76 #psi = 6894.76pa。
            print(f'求める圧力p  : {p_ans_val}Pa = {p_ans_kanzan:5f}psi')
    elif bunki_choice == '2':
        #Vを求める。
        while True:
            print('求めるvの単位は?')
            v_ans_unit = input('m3 → 1、cm3 → 2、L → 3、mL → 4、ヤード・ポンド法 → 5:') #単位を決定
            if v_ans_unit == '5':#ヤード・ポンド単位を決定
                v_ans_unit = input('ガロン(gallon) → 6、クォート(quart) → 7、パイント(pint) → 8:')
            else:
                pass
            if v_ans_unit in ['1', '2', '3', '4', '6', '7', '8']:
                break #適切なインプットか?
            else:
                print('単位入力に誤りがあります。')
        p_inp = p_kanzan_shiki() #p_kanzanをp_inpで受ける
        n_inp = n_kanzan_shiki() #n_kanzanをn_inpで受ける
        t_inp = t_kanzan_shiki() #t_kanzanをt_inpで受ける
        v_ans_val = (n_inp * R * t_inp)/p_inp #V[m3] = nRT/p
        if v_ans_unit == '1':
            v_ans_kanzan = v_ans_val
            print(f'求める体積v : {v_ans_kanzan}m3')
        elif v_ans_unit == '2':
            v_ans_kanzan = v_ans_val*1000000 #1 m3 = 1000000 cm3
            print(f'求める体積v  : {v_ans_val}m3 = {v_ans_kanzan:5f}cm3')
        elif v_ans_unit == '3':
            v_ans_kanzan = v_ans_val*1000 #1 m3 = 1000 L
            print(f'求める体積v  : {v_ans_val}m3 = {v_ans_kanzan:.5f}L')
        elif v_ans_unit == '4':
            v_ans_kanzan = v_ans_val*1000000 #1 m3 = 1000000 mL
            print(f'求める体積v  : {v_ans_val}m3 = {v_ans_kanzan:.5f}mL')
        elif v_ans_unit == '6':
            v_ans_kanzan = v_ans_val*219.969 #1 m3 =219.969 gallon
            print(f'求める体積v  : {v_ans_val}m3 = {v_ans_kanzan:.5f}gallon')
        elif v_ans_unit == '7':
            v_ans_kanzan = v_ans_val*879.877 #1 m3 = 879.877 quart
            print(f'求める体積v  : {v_ans_val}m3 = {v_ans_kanzan:.5f}quart')
        else:
            v_ans_kanzan = v_ans_val*1759.754 #1 m3 = 1759.754 pint
            print(f'求める体積v : {v_ans_val}m3 = {v_ans_kanzan:.5f}pint')
    elif bunki_choice == '3':
        #nを求める。
        while True:
            print('求める物質量n(または重量)の単位は?')
            n_ans_unit = input('mol → 1、個 → 2、重量 → 3 :') #単位を決定
            g_ans_unit = 0 #重量単位を決定g_unitを定義
            if n_ans_unit == '3':#ヤード・ポンド単位を決定
                g_ans_unit = input('g → 4、mg→ 5、kg → 6、ton → 7:')
                ans_bunnshi_ryou = float(input('気体の分子量を入れてください:'))
            else:
                pass
            if n_ans_unit in ['1', '2'] or g_ans_unit in ['4', '5', '6', '7']:
                break #適切なインプットか?
            else:
                print('単位入力に誤りがあります。')
        p_inp = p_kanzan_shiki() #p_kanzanをp_inpで受ける
        v_inp = v_kanzan_shiki() #v_kanzanをv_inpで受ける
        t_inp = t_kanzan_shiki() #t_kanzanをt_inpで受ける
        n_ans_val = (p_inp * v_inp)/(R * t_inp) #n[mol] = pv/RT
        if n_ans_unit == '1':
            n_ans_kanzan = n_ans_val
            print(f'求めるn : {n_ans_kanzan}mol')
        elif n_ans_unit == '2':
            n_ans_kanzan = n_ans_val*(6.022*10**23) #1 mol = 6.022*10**23個
            print(f'求めるn : {n_ans_val}mol = {n_ans_kanzan:5E}個')
        else:
            if g_ans_unit == '4':
                n_ans_kanzan = n_ans_val * ans_bunnshi_ryou #1 mol = g/M
                print(f'求めるn : {n_ans_val}mol = {n_ans_kanzan:.5f}g')
            elif g_ans_unit == '5':
                n_ans_kanzan = n_ans_val * (1000*ans_bunnshi_ryou) #1 mol = mg/1000M
                print(f'求めるn : {n_ans_val}mol = {n_ans_kanzan:.5f}mg')
            elif g_ans_unit == '6':
                n_ans_kanzan = n_ans_val * ans_bunnshi_ryou /1000 #1 mol = 1000kg/M
                print(f'求めるn : {n_ans_val}mol = {n_ans_kanzan:.5f}kg')
            else:
                n_ans_kanzan = n_ans_val * ans_bunnshi_ryou /1000000 #1 mol = 1000000t/M
                print(f'求めるn : {n_ans_val}mol = {n_ans_kanzan:.5f}ton')
    else:
        while True:
            print('求める温度Tの単位は?')
            t_ans_unit = input('K (絶対温度) → 1、℃ (摂氏温度)→ 2、℉ (華氏温度) → 3 :') #単位を決定
            if t_ans_unit in ['1', '2', '3']:
                break #適切なインプットか?
            else:
                print('単位入力に誤りがあります。')
        p_inp = p_kanzan_shiki() #p_kanzanをp_inpで受ける
        v_inp = v_kanzan_shiki() #v_kanzanをv_inpで受ける
        n_inp = n_kanzan_shiki() #n_kanzanをn_inpで受ける
        t_ans_val = (p_inp * v_inp)/(R * n_inp) #T[K] = pv/nR
        if t_ans_unit == '1':
            t_ans_kanzan = t_ans_val
            print(f'求める温度T : {t_ans_kanzan}K')
        elif t_ans_unit == '2':
            t_ans_kanzan = t_ans_val - 273.15  #1 K = -273.15 ℃
            print(f'求める温度T : {t_ans_val}K = {t_ans_kanzan:5f}℃')
        else:
            t_ans_kanzan = (1.8 * (t_ans_val - 273.15)) + 32 #1 ℃ = (℉ - 32)/1.8 
            print(f'求める温度T : {t_ans_val}K = {t_ans_kanzan:5f}℉')
bunki()

とりあえず動く状態になりましたが、長すぎ!308行・・・
これで、大体の単位換算をしなくても、理想気体の状態方程式を扱えるようになりました。


力技でやったのですが、同じような繰り返しだったので、うまい方がやれば半分くらいの長さでできるのではないかと思います。例えば、辞書型のデータとして、あらかじめ
Pa_1 = {kPa:1000, MPa:1000000, atm:1/101325, ・・・}
のような感じでまとめておいて、それぞれ単位換算する時にkeyとvalueを紐付けて計算すれば、かなり減るように思います。というか1/5くらいになりそうです。全部書いてから気づきました。
全部やるのは大変なので、「vのinputとoutput」に関する部分だけやってみました。

~~~略~~~
v_dict = {'m3':1, 'cm3':1000000, 'L':1000, 'mL':1000000, 
         'gallon':219.969, 'quart':879.877, 'pint':1759.754}
v_choice_dict ={'1':'m3', '2':'cm3', '3':'L', '4':'mL', '6':'gallon', '7':'quart', '8':'pint'}

def v_kanzan_shiki():
    while True:
        v_val = float(input('体積Vの値は?:'))
        print('体積vの単位は?')
        v_unit = input('m3 → 1、cm3 → 2、L → 3、mL → 4、ヤード・ポンド法 → 5:') #単位を決定
        if v_unit == '5':#ヤード・ポンド単位を決定
            v_unit = input('ガロン(gallon) → 6、クォート(quart) → 7、パイント(pint) → 8:')
        else:
            pass
        if v_unit in ['1', '2', '3', '4', '6', '7', '8']:
            break #適切なインプットか?
        else:
            print('単位入力に誤りがあります。')
    v_unit_ch = v_choice_dict[v_unit]
    v_kanzan = v_val * v_dict[v_unit_ch]
    print(f'v : {v_val}{v_unit_ch} = {v_kanzan:5f}m3')
    return v_kanzan
~~~略~~~
def bunki():
~~~略~~~
    elif bunki_choice == '2':
        #Vを求める。
        while True:
            print('求めるvの単位は?')
            v_ans_unit = input('m3 → 1、cm3 → 2、L → 3、mL → 4、ヤード・ポンド法 → 5:') #単位を決定
            if v_ans_unit == '5':#ヤード・ポンド単位を決定
                v_ans_unit = input('ガロン(gallon) → 6、クォート(quart) → 7、パイント(pint) → 8:')
            else:
                pass
            if v_ans_unit in ['1', '2', '3', '4', '6', '7', '8']:
                break #適切なインプットか?
            else:
                print('単位入力に誤りがあります。')
        p_inp = p_kanzan_shiki() #p_kanzanをp_inpで受ける
        n_inp = n_kanzan_shiki() #n_kanzanをn_inpで受ける
        t_inp = t_kanzan_shiki() #t_kanzanをt_inpで受ける
        v_ans_val = (n_inp * R * t_inp)/p_inp #V[m3] = nRT/p
        v_ans_unit_ch = v_choice_dict[v_ans_unit]
        v_ans_kanzan = v_val / v_dict[v_ans_unit_ch]
        print(f'求める体積v  : {v_ans_val}m3 = {v_ans_kanzan:.5f}{v_ans_unit_ch}')

どう考えても、こっちの方がスマートです。
フローチャートもそうですが、プログラムを書く前に頭を使うことがかなり重要です。

次回、状態方程式をもう少し深堀します。

To Be Continued : 気体の状態方程式をPythonで! episode 2

PyQさんで勉強中!

コメント

タイトルとURLをコピーしました