例題第1号。最も単純な流体回路、ただ直管の圧力損失抵抗が有るだけの、1本道の流路を作る。
OpenModelicaで既存コンポーネントを組み合わせてモデルを作成する手順は、内容に関わらず毎回ほぼ同じだ(コンポーネント自体を1から作成する場合は全く異なる)。従って、OpenModelicaを用いたモデル作成操作手順は各例題のページでは割愛する。別途、モデル作成の手順一通りを解説するページを設けようと考えている。
- 手書きスケッチ
先ずは、作成しようとしているシステムの概念図を書く。慣れるまでは、作ろうとしているものを一度図に書き出す習慣を持っておこう。Modelicaではグラフィカルにコンポーネントを配置・接続してシステムモデルを組立られるが、モデリング・離散化の都合で物理的な実物の形から大きく離れた見た目のものが出来てしまうことがよく起きる。そうなった時に、作るモノのイメージを一度具体化しておかないと、何を作っているのか自分で見失ってしまう事が起きてしまう為だ。
対象物の形、要素要素の相互の繋がり、モデルに入れ込めたい物理現象、実装したい数式、など自身で必要と思うものを書き出そう。ここで書き出す情報の詳細度は人によって違いが出るところだと思う。どこまで書き出すのが正しと言うものは無い。筆者の場合は上図の通りの大雑把さだ。
モデル作成に進む前に、作成対象物について軽く纏めておこう。(parameterは省略。)
- 流路は1本の直管。
- 流す流体は水(液相)
- 内包する物理現象:
- 圧力損失。
- 質量保存。
- 熱量(エンタルピ)保存。出入口でエンタルピは変化しない。
- 圧力損失に伴う、出口での流体の温度上昇。熱流体の世界を歩くのだから、ただの流路でも熱的な現象を観る。*ただし、これは非圧縮性流体でしか発生しない。
- 境界条件(Input):
- 入口質量流量。(値を変化させる)
- 入口温度。(固定値)
- 出口圧力。(固定値)
- Output(多数有るが、注目するもの):
- 入口圧力(出口圧力と圧力損失から決まる)。
- 入口比エンタルピ。
- 出口比エンタルピ。
- 入口温度。
- 出口温度。
- packageとmodelファイルの作成
package作成は必須ではなく、modelだけを作成しても良い。しかし、演習ならそれ用packageを作っておいて、そこにmodelを足してゆく方が管理が行い易く、お薦めする。
packageを用意して、そこにmodelを作成する操作の解説は別途解説する記事を設けようと考えているのでここでは解説しない。
- コンポーネントの配置
下図の通りにコンポーネントを配置・接続する。慣れないうちは使用するコンポーネントを探す事が非常に手間・高いハードルだろうと思う。従って、以下にフルパスでリストアップしておく。
- Modelica.Fluid.System
- Modelica.Blocks.Sources.Ramp
- Modelica.Fluid.Sources.MassFlowSource_T
- Modelica.Fluid.Vessels.ClosedVolume
- Modelica.Fluid.Pipes.StaticPipe
- Modelica.Fluid.Sources.Boundary_pT
Modelica.Fluidのコンポーネントを使う為におまじない的に必要なものと考えれば良い。
ボリューム効果(質量流量、エネルギの過渡的な溜り)を代表する。
名の通り配管。圧力損失のみが起きるタイプのもので、ボリューム効果は別途上記コンポーネントで表現する。コンポーネントをドラッグ&ドロップで配置する、port間を線で繋ぐ、と言うと作業自体は単純だ。しかし、このプロセスこそが1DCAEの肝。各コンポーネントに何の機能を持たせるのか、各々の接続が何を意味するのか/何のためのものなのか、を意識・理解しなければ、自在に複雑奇怪な物理システムのモデルを組み立てられるようにはならない。上記の通り、使用コンポーネントリストにそれぞれの概要を、図中にシステム内での役割を簡単に記しているので、必ず理解・意識しながら進めて欲しい。このようなメモ書き程度の説明では理解が及ばなければ、是非、各コンポーネントのdocumentationやソースコードを見てみよう。
加えて、些細だが1点注意点が有る。multi-portを持つコンポーネント(図中の、boudary, volume, volume1, boundary1)を接続する時、何番portに繋ぐかを設定しなければならない。この時、番号を重複させたり、存在しない番号を設定(例、portは2つまでになのに、3番に設定。)してしまわないよう注意しておかねばならない。混乱しないよう、”左・上から1,2,,,と順に番号を与える”、と言ったマイルールを定めておく事をお薦めする。とは言っても、接続番号設定に不適切なものが有ると、コンパイル時にエラーが出て発覚するので神経質になる必要は無い。不適切な番号設定のまま計算が流れて不適切な結果が出る、と言う事態は心配しなくて良い。
- parameterの設定
コンポーネント配置・接続が済んだら、各々のparameterを設定していく。コンポーネントを右クリックしてparametersを選択するか、ダブルクリックするとparametersウィンドウが現れるので、必要箇所を設定する。
コンポーネント(のインスタンス)毎に、parameterの意味と設定値を記載する。尚、デフォルト設定のままにしておいて済むコンポーネント、parameterは記載自体を省略する。また、parameterの意味もparameterウィンドウ上の記載から意味が理解可能なものは省略/簡潔に済ます。
- ramp1
- height: 10
- duration: 10
- offset: 10
- startTime: 10
- boudary
- user_m_flow_in: チェックを入れる。
- T: 15+273.15 [K]
- nPorts: 1
質量流量inputをparameterではなく、portから信号で与えるスイッチ。 - volume
- V: 1.0e-3
- nPorts: 2
- use_portsData: false
配管内部容積に合わせて値を設定するのが正しいが、今回はvolumeで圧力損失による温度上昇を見られれば良いので現実的で適当な値を入れる。
portに高さ、径の情報を与えるかのスイッチ。volumeをタンクの様に出入口を持つ容器として扱いたい場合にtrueを選ぶ。今回はvolume効果を入れ、体積を持つノードして扱うので不要。
- pipe
- length: 5
- diameter: 0.05
- volume1
- V: 1.0e-3
- nPorts: 2
- use_portsData: false
- boundary1
- p: 101.325*1000
- T: 15+273.15
- nPorts: 1
*今回、流体が本コンポーネントに流れ込むので設定値は上流の計算に使われないが、本コンポーネント内のmediumの計算には使われるので、エラーを起こさせないように現実的な値を与えておく。
- ramp1
- ソースコード
上記までを行うとOpenModelicaがソースコードを自動生成してくれている。一部ソースコードを直接触らなければならない作業が有るのと、エラーが生じた場合の比較のために、本モデルの完成状態のソースコードを示す。
*誤解して欲しく無いが、”Modelica”はGUIベースで1DCAEモデルを組み立てるツールではなく、飽くまで物理モデリング用の言語。GUIでモデリングが出来るのは、OpenModelica等Modelicaを扱うツールの機能だ。
- mediumのredeclareコードを直接記述
(*OpenModelica ver 1.16でparameterウィンドウから設定出来るようになり、不要な手順となる見込み。nightly build版では既に可能になっている(2020年6月時点の情報)。)
text viewに切り替え、モデルソースコード内に、次項に示すソースコード中で
黄色ハイライト で示されている記述を、直接書き足す。これらの記述が各流体コンポーネント内の計算が参照する物性計算パッケージを指定する。これを記述することで漸く流す流体が液体の水であることを指定される。そして、使用する流体を切り替える場合はこの部分だけを書き換えるだけで済む。 - 完成状態のソースコード(チェック用)
コンパイルエラーや、計算結果が意図通りのものとならないような場合に比較・チェック用に参照して欲しい。尚、annotation()の部分はGUI上の配置位置や向きで値が変わるものなので、比較する必要は無い。
——————————————————————————-
within PropulsionSystem.Examples.WalkingInWorldOfThermoFluid; model FlowResistance_ex01 extends Modelica.Icons.Example;
//---------- replaceable package liquid1 = Modelica.Media.Water.StandardWaterOnePhase; //---------- inner Modelica.Fluid.System system(T_ambient(displayUnit = "K") = 15 + 273.15, p_ambient(displayUnit = "Pa") = 101.325 * 1000) annotation( Placement(visible = true, transformation(origin = {-90, 90}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); Modelica.Fluid.Sources.MassFlowSource_T boundary(redeclare package Medium = liquid1, T = 15 + 273.15, m_flow = 1, nPorts = 1, use_m_flow_in = true) annotation( Placement(visible = true, transformation(origin = {-50, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); Modelica.Fluid.Sources.Boundary_pT boundary1(redeclare package Medium = liquid1, T = 15 + 273.15, nPorts = 1, p = 101.325 * 1000) annotation( Placement(visible = true, transformation(origin = {70, 50}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); Modelica.Fluid.Pipes.StaticPipe pipe(redeclare package Medium = liquid1, diameter = 0.05, length = 5) annotation( Placement(visible = true, transformation(origin = {10, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); Modelica.Fluid.Vessels.ClosedVolume volume(redeclare package Medium = liquid1, V = 1.0e-3, nPorts = 2, use_portsData = false) annotation( Placement(visible = true, transformation(origin = {-20, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); Modelica.Fluid.Vessels.ClosedVolume volume1(redeclare package Medium = liquid1, V = 1.0e-3, nPorts = 2, use_portsData = false) annotation( Placement(visible = true, transformation(origin = {40, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); Modelica.Blocks.Sources.Ramp ramp1(duration = 10, height = 10, offset = 10, startTime = 10) annotation( Placement(visible = true, transformation(origin = {-90, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); equation connect(volume.ports[2], pipe.port_a) annotation( Line(points = {{-20, 50}, {0, 50}}, color = {0, 127, 255})); connect(boundary.ports[1], volume.ports[1]) annotation( Line(points = {{-40, 50}, {-20, 50}}, color = {0, 127, 255}, thickness = 0.5)); connect(volume1.ports[2], boundary1.ports[1]) annotation( Line(points = {{40, 50}, {60, 50}, {60, 50}, {60, 50}}, color = {0, 127, 255}, thickness = 0.5)); connect(ramp1.y, boundary.m_flow_in) annotation( Line(points = {{-78, 50}, {-76, 50}, {-76, 58}, {-60, 58}, {-60, 58}}, color = {0, 0, 127})); connect(pipe.port_b, volume1.ports[1]) annotation( Line(points = {{20, 50}, {38, 50}, {38, 50}, {40, 50}}, color = {0, 127, 255})); annotation( experiment(StartTime = 0, StopTime = 30, Tolerance = 1e-06, Interval = 0.06), __OpenModelica_simulationFlags(lv = "LOG_STATS", outputFormat = "mat", s = "dassl")); end FlowResistance_ex01;——————————————————————————-
- mediumのredeclareコードを直接記述
- シミュレーション実行&結果評価
ここまで来たら、作業として残っているのはシミュレーション実行だけだ。そして、観たいvariableの値や動きを評価してゆこう。
- Inputs
inputsとして与えた(変化させた)値が意図通りvariablesに反映されているか確認。
- Outputs
事前に述べた、興味のあるvariablesの動き。
- 入口圧力: pipe.port_a.p
- 入口/出口比エンタルピ: volume.medium.h, volume1.medium.h
- 入口/出口温度: pipe.flowModel.states[1].T, pipe.flowModel.states[2].T
通過質量流量を線形に増加させたのに対して、2次カーブに近い形で増加している。圧力損失は流速の2乗に比例して増加するので妥当な動きである。
*ただし、圧力損失係数がRe数に応じて変化するので、完全な2乗にはならない。
出入口で、比エンタルピの値は等しく、エンタルピ保存は保たれている。圧力損失の形で流体がエネルギを失っても、次項で観るように、失われた圧力は温度に換わるだけで流体の持つ総熱量は変わらない。もし、配管内外の温度差が大きい等、外部へ熱が逃げる経路が有る場合はエンタルピ保存は成り立たない。それを再現したい場合は、熱が逃げる回路をモデル化しなければならない。
尚、過渡応答中(シミュレーション開始直後と通過流量増加の最中)は出口に比エンタルピが入口より僅かに小さい。これはボリューム項による質量と熱量の一時的な溜りの為。従って、この事象を再現するにはvolumeをモデルに加えるか、内部にvolumeを持つdynamic pipeを持ちる必要が有る。なお、流体の持つ圧縮性が強いほど顕著に過渡応答中の差が表れる。
出口の温度は常に入口より僅かに高い。圧力損失として失われた流体のエネルギが温度に換わる。従って、通過流量を増し、圧力損失が大きくなるに従って、温度差が大きくなっている。
- Inputs
- 最後に
これで、圧力損失が発生する流路を、熱的現象を含めて一通りシミュレート完了。本例題はここまで。
初回で色々述べておきたいことが有ったために、単純なモデルであるにも関わらず長い記事となってしまった。今回のモデリング対象システムは、Excelや手計算でも実施出来そうなレベルのものだったので、つまらなかったかもしれない。今後は分岐や熱授受を含む、手計算では厳しい・Excelで実施すると大変なModelicaで行ってこそのシステムも取り扱っていくので楽しみにお待ち頂きたい。
このような単純極まりない例でも、色々とparameterを変えてみてvariablesの変化を観たり、判る範囲で造り替え(例えば、pipeをorificeに変えてみるなど)を行ったりして遊ぶと理解も作業スキルも格段に高まる。是非配布している例を弄って遊んで欲しい。
- 例モデルに関する情報
本記事で取り上げたモデルは専用の「WalkingInWorldOfThermoFluid」ライブラリに公開しており、その情報を記しておく。
- モデルのフルパス: WalkingInWorldOfThermoFluid.Introductory.flowResistance_ex01
- githubのライブラリページリンク
リンク:[連載]Modelicaによる熱流体の世界の歩き方 の記事一覧ページ
コメント