Excel から xfoil-python を呼び出して2次元翼型を解析する方法について説明する
xlwingsとは
xlwingsとは,pythonでExcelを操作したりExcelからpythonを操作したりできるようになるライブラリである
公式ドキュメント
≫xlwings Documentation
詳しいことはいろいろなブログでまとめられているのでそちらを参考に
≫ openpyxl と xlwings の比較 - Qiita
≫【Python】openpyxlとxlwingsとの比較 _ プログラミングで人生が楽になりました
今回の記事の目的は前回の記事で導入した xfoil-python を Excel VBA から呼び出せるようにすることである
↓xfoil-python についてはこちら
xlwings のインストール
公式ドキュメントに従って,xlwingsのパッケージとアドインをインストールする
≫インストール - xlwings Documentation
前提条件
インストール - xlwings Documentation
・xlwingsはExcelのインストールを前提としているため、WindowsとmacOSでしか動作しません。また、macOSでは現在UDFをサポートしていません。
・xlwingsはPython 3.6以上で動作します。
ちなみにVBAのプログラムの中でpythonで定義した関数と引数や戻り値をやり取りするにはUDF(ユーザー定義関数)を使う必要がある
パッケージのインストール
パッケージのインストールは pip install xlwings で行う(前回の記事同様pythonのバージョンは3.6を使用)
C:\Users\XXX\Desktop\xfoil>py -3.6 -m pip install xlwings
Collecting xlwings
Downloading xlwings-0.25.3.tar.gz (807 kB)
|████████████████████████████████| 807 kB 1.7 MB/s
Preparing metadata (setup.py) ... done
Collecting pywin32
Downloading pywin32-303-cp36-cp36m-win_amd64.whl (9.3 MB)
|████████████████████████████████| 9.3 MB 6.4 MB/s
Using legacy 'setup.py install' for xlwings, since package 'wheel' is not installed.
Installing collected packages: pywin32, xlwings
Running setup.py install for xlwings ... done
Successfully installed pywin32-303 xlwings-0.25.3
できた
どこぞの xf〇il とは大違いである
pip list で確認しても問題なくインストールできている
C:\Users\XXX\Desktop\xfoil>py -3.6 -m pip list
Package Version
--------------- -------
cycler 0.11.0
kiwisolver 1.3.1
matplotlib 3.3.4
numpy 1.19.5
Pillow 8.4.0
pip 21.3.1
pyparsing 3.0.6
python-dateutil 2.8.2
pywin32 303
setuptools 40.6.2
six 1.16.0
xfoil 1.1.1
xlwings 0.25.3
アドインのインストール
xlwings addin install でアドインをインストールする
C:\Users\XXX\Desktop\xfoil>xlwings addin install
xlwings version: 0.25.3
Successfully installed the xlwings add-in! Please restart Excel.
Excelを開いてみると,タブに「xlwings」が追加されていることがわかる
クイックスタート
xlwings quickstart myproject のコマンドを実行することで「myproject」というディレクトリが作成される
quickstart
コマンド ライン クライアント(CLI) - xlwings Documentation
Run "xlwings quickstart myproject" to create a folder called "myproject" in the current directory with an Excel file and a Python file, ready to be used.
ディレクトリの中にはサンプルコードである myproject.py とマクロ有効ブック myproject.xlsm が作成されている
# myproject.py
import xlwings as xw
def main():
wb = xw.Book.caller()
sheet = wb.sheets[0]
if sheet["A1"].value == "Hello xlwings!":
sheet["A1"].value = "Bye xlwings!"
else:
sheet["A1"].value = "Hello xlwings!"
@xw.func
def hello(name):
return f"Hello {name}!"
if __name__ == "__main__":
xw.Book("myproject.xlsm").set_mock_caller()
main()
マクロ有効ブックのほうには2つのシートがあり,「_xlwings.conf」はリボンで行うxlwingsの設定をシートで行う時に使うものである
ワークブック設定: xlwings.conf シート
アドインおよび設定 - xlwings Documentation
ワークブック固有の設定は、グローバル設定やワークブック ディレクトリの設定を上書きします。 xlwings.conf という名前のシートに設定のキーと値を入力すれば、ワークブック固有の設定を行えます。 xlwings quickstart で新しいプロジェクトを始めれば、ワークブックにそのようなシートが初めから含まれており、シート名を xlwings.conf に変更すると設定が有効になります。
「Alt+F11」でVBEを開くと,VBAのサンプルプログラムも確認できる
Sub SampleCall()
mymodule = Left(ThisWorkbook.name, (InStrRev(ThisWorkbook.name, ".", -1, vbTextCompare) - 1))
RunPython "import " & mymodule & ";" & mymodule & ".main()"
End Sub
サンプルプログラムの内容についてはこちら
≫RunPython - xlwings Documentation
サンプルプログラムの実行
せっかくなのでサンプルプログラムを実行してみる
「Alt+F8」でマクロのウィンドウを開き,SampleCall > Run をクリックする
Sheet1のセルA1に「Hello xlwings!」が表示された
xfoil-pythonの実行
サンプルプログラムをいじって xfoil を実行してみる
使うのはユーザー定義関数
≫ユーザー定義関数 (UDFs) - xlwings Documentation
プログラム
myproject.py のプログラムはこんな感じ
define() はマクロ有効ブックの絶対パス wb_path と解析する翼型の名前 airfoil_name を引数として受け取り,翼型を読み込んで各種設定を行う関数
xf_a() は迎角 alpha とレイノルズ数 Re を引数として受け取り,xf.a()を実行して空力係数を計算して計算結果を返す関数である
#!python3.6
import os
import numpy as np
from xfoil import XFoil
from xfoil.model import Airfoil
import xlwings as xw
xf = XFoil() # Create an instance of the XFoil class
@xw.func
def define(wb_path, airfoil_name):
# Read airfoil
with open(os.path.join(wb_path,airfoil_name+".dat"), "r") as f:
airfoil = f.readlines() # Read an airfoil in the same format as XFLR5 (.dat)
airfoil = [line.split() for line in airfoil] # Split strings by tab
airfoil = np.array(airfoil[1:],dtype='float64') # Convert strings in list to numpy array
xf.airfoil = Airfoil(airfoil[:,0],airfoil[:,1]) # Airfoil: Instance of the Airfoil class
# Difine analysis
xf.M = 0 # float: Mach number.
xf.n_crit = 9 # float: Critical amplification ratio
xf.xtr = (1, 1) # tuple(float, float): Top and bottom flow trip x/c locations
xf.max_iter = 100 # int: Maximum number of iterations
xf.repanel # Re-panel airfoil
@xw.func
def xf_a(alpha, Re):
xf.reset_bls # Reset the boundary layers to be reinitialized on the next analysis
xf.Re = Re # float: Reynolds number
cl, cd, cm, cp = xf.a(alpha) # Analyze airfoil at a fixed angle of attack
return cl, cd, cm, cp
if __name__ == "__main__":
wb = xw.Book("myproject.xlsm")
macro = wb.macro('SampleCall')
macro()
参考
≫xfoil-python_xfoil.py at master
≫Pythonのif name == main とは何ですか?への回答 - Python学習チャンネル by PyQ
myproject.xlsm のプログラムはこれ
airfoil_name,alpha,Re はシートから読み取り,計算結果をシートに出力する
Sub SampleCall()
Dim airfoil_name As String: airfoil_name = Range("A2")
Dim alpha As Double: alpha = Range("B2")
Dim Re As Double: Re = Range("C2")
Dim coeff As Variant
' define
wb_path = ThisWorkbook.Path
Call xlwings_udfs.define(wb_path, airfoil_name)
'xfoil_a
coeff = xlwings_udfs.xf_a(alpha, Re)
Range("D2:G2") = coeff
End Sub
エクセルシートを置いているフォルダをOneDriveと同期している場合はThisWorkbook.Pathが使えないのでこちらを参考
≫[VBA]OneDriveで同期しているファイルまたはフォルダのURLをローカルパスに変換する関数
OneDriveUrlToLocalPath(ByRef Url As String)
エクセルシートの配置はこんな感じ
今回解析する DAE31.dat はこれ
DAE31
1.0000000 0.0000000
0.9910549 0.0019676
0.9751725 0.0056508
0.9562892 0.0102773
0.9348845 0.0157716
0.9118290 0.0219602
0.8877617 0.0287011
0.8629994 0.0358851
0.8377395 0.0434059
0.8121316 0.0511492
0.7867002 0.0588254
0.7619602 0.0661241
0.7378954 0.0729224
0.7142982 0.0791842
0.6909062 0.0849452
0.6675955 0.0902334
0.6443157 0.0950530
0.6210077 0.0994086
0.5976155 0.1033104
0.5741033 0.1067704
0.5504558 0.1097981
0.5266740 0.1124031
0.5027839 0.1145914
0.4788216 0.1163647
0.4548339 0.1177244
0.4308940 0.1186644
0.4070451 0.1191690
0.3832867 0.1192302
0.3596416 0.1188447
0.3361549 0.1180073
0.3128750 0.1167072
0.2898298 0.1149313
0.2670436 0.1126721
0.2445728 0.1099286
0.2225073 0.1067006
0.2009441 0.1029850
0.1799680 0.0987808
0.1596995 0.0941120
0.1403288 0.0890216
0.1220556 0.0835674
0.1050817 0.0778315
0.0895859 0.0719246
0.0757089 0.0659851
0.0635164 0.0601440
0.0529609 0.0544931
0.0439060 0.0490943
0.0361794 0.0439863
0.0296006 0.0391763
0.0239969 0.0346545
0.0192170 0.0304007
0.0151340 0.0263895
0.0116467 0.0225925
0.0086870 0.0189712
0.0062058 0.0154863
0.0041396 0.0121274
0.0024387 0.0088917
0.0011249 0.0057470
0.0005111 0.0036795
0.0002956 0.0026546
0.0001444 0.0016368
0.0000000 0.0000000
0.0000732 -0.0033344
0.0003224 -0.0052847
0.0005253 -0.0062484
0.0007913 -0.0071995
0.0011270 -0.0081316
0.0015386 -0.0090365
0.0020315 -0.0099069
0.0026069 -0.0107343
0.0032641 -0.0115095
0.0040024 -0.0122247
0.0048172 -0.0128750
0.0057020 -0.0134557
0.0066512 -0.0139647
0.0076586 -0.0144080
0.0087170 -0.0147934
0.0098213 -0.0151289
0.0121629 -0.0156765
0.0160127 -0.0162722
0.0203174 -0.0166809
0.0251704 -0.0169573
0.0307077 -0.0170976
0.0371267 -0.0170789
0.0447105 -0.0168835
0.0538609 -0.0164863
0.0651185 -0.0158460
0.0791218 -0.0148852
0.0964621 -0.0135084
0.1173137 -0.0116815
0.1411530 -0.0094668
0.1669774 -0.0070044
0.1937839 -0.0044371
0.2208949 -0.0018732
0.2480412 0.0006298
0.2751500 0.0030496
0.3021781 0.0053706
0.3291109 0.0075769
0.3559543 0.0096567
0.3827039 0.0116006
0.4093341 0.0133929
0.4358625 0.0150181
0.4622963 0.0164689
0.4886091 0.0177316
0.5148084 0.0187870
0.5409500 0.0196233
0.5670984 0.0202439
0.5932355 0.0206558
0.6193428 0.0208512
0.6454416 0.0208262
0.6715560 0.0205806
0.6977112 0.0201197
0.7238936 0.0194539
0.7500470 0.0185860
0.7761535 0.0175065
0.8022314 0.0162106
0.8282915 0.0146975
0.8543374 0.0129730
0.8802830 0.0110562
0.9059293 0.0089751
0.9307780 0.0068061
0.9538566 0.0046630
0.9740739 0.0026703
0.9908034 0.0009545
1.0000000 0.0000000
実行
myproject.py,myproject.xlsm,DAE31.dat を同じディレクトリに置き,マクロ有効ブックを開いてxlwings > Import Functions をクリックする
「Alt+F11」でVBEを開くと,「xlwings_udfs」というモジュールが作成され,define と xf_a という Function が作成されていることがわかる
VBEを閉じて,「Alt+F8」でマクロウィンドウを開き,SampleCall > Run をクリックしてマクロを実行する
できた
ちなみにVisual Studio Codeのターミナルからも実行できる
C:\Users\XXX\Desktop\xfoil\myproject>py myproject.py
PYTHONPATH と UDF Modules
クイックスタートで作成したpyとxlsmは次のように設定されている
quickstart で作成した場合、デフォルトの設定では、Pythonのソース ファイルは次のようになっていなければなりません:
ユーザー定義関数 (UDFs) - xlwings Documentation
・Excelファイルと同じディレクトリ
・Excelファイルと同じ名前で、拡張子が .xlsm ではなく .py
実際には,Excelファイルと違うディレクトリにあるExcelファイルと違う名前の python のファイルを使いたいことが多い
PYTHONPATH: コードのソースファイルが見つからない場合、ここにディレクトリーのパスを追加してください。
UDF Modules: UDFをインポートするPythonモジュールの名前(.py拡張子を除く)。モジュールが複数の場合は";"で区切ります。例: UDF_MODULES = "common_udfs;myproject" 何も入力しなければ、Excel スプレッドシートと同じディレクトリにある同じ名前のファイル(拡張子は .py)をインポートします。
アドインおよび設定 - xlwings Documentation
例えば,「C:\Users\XXX\Desktop\xfoil\src」というディレクトリにある「xfoil_a.py」というファイルを参照したいとすると xlwings > PYTHONPATH に「C:\Users\XXX\Desktop\xfoil\src」を入力し,xlwings > UDF modules に「xfoil_a」を入力する
もう一度 xlwings > Import Functions をクリックすれば,マクロが実行できるようになる
まとめ
Excel から xfoil-python を呼び出して2次元翼型を解析する方法について説明した
エクセルで3次元翼解析のプログラムを組みたい時に役立つのではないだろうか
↓まとめ記事
コメント