はじめに
最近出たばかりの、iPad Air 4 を買った。使用目的は主に手書きメモ作成なのだが、計算しながらメモを作成する場合も多い。手書きメモといってもテキストと数字だけなら、わざわざ手書きにしなくても、さっさとテキストエディタで打ち込めばいいのだが、説明図が必要となると、やはり手書きが便利である。計算が必要な場合には、これまでは iMac で Python を立ち上げて計算させながら iPad で手書きスケッチやメモを行っていたが、iPad があるのに iMac を立ち上げるのもなんかかっこ悪い、というかスマートでない。
そこで、最近はご無沙汰であったが、iPad mini 4 用に購入していた、Pythonista 3 を使ってみることにした。
Pythonista 3 は、numpy および matplotlib を含んでおり、これらはほぼ間違いなく動く。scipy や pandas など、その他のライブラリは使えないと思ったほうが良い。このため、複雑な計算でも numpy と matplotlib のみを使っているコードなら実用性がある。また GUI も使えるらしいのだが、これまで自分で使ったことはないので、使用頻度の高い簡単な計算プログラムを、アプリ風にして iPad で使えるようにしてみた。(要はiPad Air 4を買って嬉しいので、これを使っていろいろなことをやろうという趣旨である)
やっていること
やっていることは Mac に入れている「急勾配水路の等水深を求めるプログラム」を Pythonista 用に書き換えて GUI で動くようにしたものである。
もとのコードは以下の「はてな」に投稿したものである。
https://damyarou.hatenablog.com/entry/2020/10/23/073643
このプログラムは非線形方程式を解くため、Mac 用プログラムでは scipy を使っているが、Pythonista では scipy は使えないため、非線形方程式を解く二分法の部分は自前で書き換えている。
更に、ここからが自分にとって初めての挑戦であるが、アプリ風に GUI を使って仕上げてみた。
実行結果は以下の写真のようになる。上側4個の四角にデータを入力し、Execute
というボタンを押すと結果が下側四角の中に示される。
プログラム作成に当たり以下のサイトを参考にさせていただいた。
Pythonista 3 では、UI プログラミングを指定すると、2つのファイルができる。下の写真では。py_uniflow.py
と py_uniflow.pyui
というファイルが確認できる。「xxx.py」はコードを書き込むプログラムで、「xxx.pyui」は、UI の配置や特性を定義するファイルである。
配置できるオブジェクトの一覧は、UIの配置と特性を定義する py_uniflow.pyui
上で、左上の四角で囲まれた+マークを押すと表示されるので、そこから使いたいものを選択する。
このプログラムでは、以下の4種類のオブジェクトを使っている。
- label
- textfield
- button
- textview
label
と buttan
については、py_uniflow.pyui
の中で行っている、特性値指定箇所の写真を示しておく。
textfield
と textview
は、位置と大きさを調整しているだけなので、写真は省略。
こんな感じでプログラムをiPad上で仕上げていく。
コード
py_uniflow.py
のコード全文は以下の通り。関数 def click_button
の中に主な処理は全て詰め込んである。
# Calculation of normal depth
# (amended on 2022.05.15)
import ui
import numpy as np
def cal_hc(q,b,cs):
# critical depth
g=9.8
hc=(q**2/g/b**2/cs)**(1/3)
return hc
def func(h,q,b,n,sn):
f=q-b*h/n*(b*h/(b+2*h))**(2/3)*sn**(1/2)
return f
def bisection(q,b,n,sn,ha,hb):
for k in range(100):
hi=0.5*(ha+hb)
fa=func(ha,q,b,n,sn)
fb=func(hb,q,b,n,sn)
fi=func(hi,q,b,n,sn)
if fa*fi<0: hb=hi
if fb*fi<0: ha=hi
#print(fa,fi,fb)
if np.abs(hb-ha)<1e-10: break
return hi
def calc(q,b,n,i):
theta=np.arctan(i)
sn=np.sin(theta)
cs=np.cos(theta)
ha=0.0 # lower initial value for bisection method
hb=10.0 # upper initial value for bisection method
hn=bisection(q,b,n,sn,ha,hb)
vn=q/b/hn
hc=cal_hc(q,b,cs)
# hn: normal depth
# vn: flow velocity
# hc: critical depth
ss='ang={0:.3f} deg.\n'.format(np.degrees(theta))
ss=ss+'hn={0:.3f} m\n'.format(hn)
ss=ss+'vn={0:.3f} m/s\n'.format(vn)
ss=ss+'hc={0:.3f} m'.format(hc)
return ss
def click_button(sender):
tf1=v['textfield1']
tf2=v['textfield2']
tf3=v['textfield3']
tf4=v['textfield4']
q=float(tf1.text) # discharge
b=float(tf2.text) # channel width
n=float(tf3.text) # Manning's roughness coefficient
i=float(tf4.text) # invert gradient
ss=calc(q,b,n,i)
v['textview1'].text=ss
v = ui.load_view()
v.name='Uniform flow'
v.present('sheet')
以 上