-
Notifications
You must be signed in to change notification settings - Fork 13
/
atom.xml
899 lines (786 loc) · 444 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Giskard's CFD Learning Tricks]]></title>
<subtitle><![CDATA[CFD and Scientific Computing]]></subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://xiaopingqiu.github.io/"/>
<updated>2017-05-12T03:49:10.618Z</updated>
<id>http://xiaopingqiu.github.io/</id>
<author>
<name><![CDATA[Giskard Q.]]></name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title><![CDATA[多说评论系统将停止提供服务]]></title>
<link href="http://xiaopingqiu.github.io/2017/05/12/duoshuoAnnouncement/"/>
<id>http://xiaopingqiu.github.io/2017/05/12/duoshuoAnnouncement/</id>
<published>2017-05-12T03:36:26.000Z</published>
<updated>2017-05-12T03:49:10.618Z</updated>
<content type="html"><![CDATA[<p>各位读者,本博客所依赖的“多说评论系统”将于 2017 年 6 月 1 日关闭,届时所有的评论数据都将丢失。虽然多说提供了评论数据下载,我也计划将来添加 Disqus 评论系统,也许可以将多说的数据导入进来,但不一定能成功。所以如果在评论系统中有对您重要的信息,请提前复制保存到其他地方。</p>
]]></content>
<summary type="html">
<![CDATA[<p>各位读者,本博客所依赖的“多说评论系统”将于 2017 年 6 月 1 日关闭,届时所有的评论数据都将丢失。虽然多说提供了评论数据下载,我也计划将来添加 Disqus 评论系统,也许可以将多说的数据导入进来,但不一定能成功。所以如果在评论系统中有对您重要的信息,请提前复制保]]>
</summary>
<category term="test" scheme="http://xiaopingqiu.github.io/tags/test/"/>
<category term="test" scheme="http://xiaopingqiu.github.io/categories/test/"/>
</entry>
<entry>
<title><![CDATA[Paraview 脚本一例]]></title>
<link href="http://xiaopingqiu.github.io/2016/08/27/ParaviewScritps/"/>
<id>http://xiaopingqiu.github.io/2016/08/27/ParaviewScritps/</id>
<published>2016-08-27T08:45:24.000Z</published>
<updated>2016-08-27T13:03:29.108Z</updated>
<content type="html"><![CDATA[<p>Paraview 提供了一个 python 接口,可以用 python 脚本来控制 Paraview,以实现自动化的后处理。使用方法是,先写一个 python 脚本,里面包含调用 Paraview 的各种语句,然后,用 Paraview 的安装目录的 bin 下的 <code>pvpython</code> 来运行这个脚本即可。本篇用一个例子来说明 python 脚本的写法,以及常用 Paraview 操作对应的语句。</p>
<a id="more"></a>
<p>这个脚本实现的功能如下:</p>
<ol>
<li>从指定路径中读取一个 “xxx.foam”</li>
<li>作一个截面,再在截面的基础上作矢量箭头</li>
<li>对截面使用 Surface Vector 这个 filter</li>
<li>对得到的 SurfaceVector 使用 Mask Points</li>
<li>使用 Stream Tracer With Custom Source,其中 Input 为 SurfaceVector,Seed point 为 MaskPoints,这样就得到了 slice 上的流线。</li>
<li>输出流线这个视图的一张屏幕截图</li>
<li>输出流场箭头叠加 slice 这个视图的 11 帧动画,动画输出过程中,Camera 是绕 y 轴旋转的,所以得到的是旋转效果的动画。</li>
</ol>
<p>需要说明的是,以下脚本绝大部分都不是手写的,而是用 trace 功能自动生成的。打开一个空白的 Paraview,选择 Tools->Satrt Trace,然后,再去进行操作,Paraview 会将你的操作转换成 pvpython 语句,完成以后再 Tools->Stop Strace,就自动生成了一个脚本。</p>
<p>下面先给出脚本的全部,然后在脚本中给出注释,最后再给出一些额外的说明。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span>: paraview.simple</span><br><span class="line"><span class="keyword">except</span>: <span class="keyword">from</span> paraview.simple <span class="keyword">import</span> * <span class="comment">## 这是 python 的语法,注意 pvpython 是基于 python 的,使用的完全是 python 的语法</span></span><br><span class="line">paraview.simple._DisableFirstRenderCameraReset()</span><br><span class="line"></span><br><span class="line">pM_foam = OpenFOAMReader( FileName=<span class="string">'E:\\OF_tutorials\\mapped\\pitzDailyMapped\\pM.foam'</span> ) <span class="comment">## 用 OpenFOAMReader 读取一个 "xxx.foam" 文件</span></span><br><span class="line"></span><br><span class="line">AnimationScene1 = GetAnimationScene() <span class="comment">## 获取动画操作的接口</span></span><br><span class="line">AnimationScene1.EndTime = <span class="number">0.1</span></span><br><span class="line">AnimationScene1.PlayMode = <span class="string">'Snap To TimeSteps'</span> </span><br><span class="line"></span><br><span class="line">pM_foam.CellArrays = [<span class="string">'U'</span>, <span class="string">'UMean'</span>, <span class="string">'UPrime2Mean'</span>, <span class="string">'U_0'</span>, <span class="string">'k'</span>, <span class="string">'k_0'</span>, <span class="string">'nuSgs'</span>, <span class="string">'nuTilda'</span>, <span class="string">'p'</span>, <span class="string">'pMean'</span>, <span class="string">'pPrime2Mean'</span>] <span class="comment">## 获取可显示的场数据</span></span><br><span class="line">pM_foam.MeshRegions = [<span class="string">'internalMesh'</span>]</span><br><span class="line"></span><br><span class="line">RenderView1 = GetRenderView() <span class="comment">## 获取当前窗口的接口</span></span><br><span class="line">RenderView1.CenterOfRotation = [<span class="number">0.10999999567866325</span>, <span class="number">0.0</span>, <span class="number">0.0</span>] </span><br><span class="line"></span><br><span class="line">RenderView1.Background = (<span class="number">81.0</span>/<span class="number">255.0</span>, <span class="number">87.0</span>/<span class="number">255.0</span>, <span class="number">110.0</span>/<span class="number">255.0</span>) <span class="comment">## 设置窗口的背景色,注意这里使用的RGB值是用 255 归一化的,即颜色值范围是 0~1</span></span><br><span class="line">RenderView1.ViewSize = [<span class="number">1086</span>,<span class="number">642</span>] <span class="comment">## 设置窗口的大小</span></span><br><span class="line">RenderView1.CameraViewAngle = <span class="number">30</span> <span class="comment">## 设置相机的远近,这个值越大,相机越远</span></span><br><span class="line">RenderView1.CenterAxesVisibility=<span class="number">0</span> <span class="comment">## 设置窗口旋转中心十字的显示,0 为不显示,1为显示</span></span><br><span class="line"></span><br><span class="line">DataRepresentation1 = Show() <span class="comment">## 获取当前 source 的操作接口 </span></span><br><span class="line"><span class="comment">#DataRepresentation1.ConstantRadius = 0.28999999165534973</span></span><br><span class="line">DataRepresentation1.EdgeColor = [<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.5000076295109483</span>]</span><br><span class="line"><span class="comment">#DataRepresentation1.PointSpriteDefaultsInitialized = 1</span></span><br><span class="line">DataRepresentation1.SelectionPointFieldDataArrayName = <span class="string">'p'</span></span><br><span class="line">DataRepresentation1.SelectionCellFieldDataArrayName = <span class="string">'p'</span></span><br><span class="line">DataRepresentation1.ColorArrayName = (<span class="string">'POINT_DATA'</span>, <span class="string">'p'</span>)</span><br><span class="line">DataRepresentation1.ScalarOpacityUnitDistance = <span class="number">0.015162935987203615</span></span><br><span class="line">DataRepresentation1.Texture = []</span><br><span class="line">DataRepresentation1.ExtractedBlockIndex = <span class="number">1</span></span><br><span class="line"><span class="comment">#DataRepresentation1.RadiusRange = [-0.07000000029802322, 0.28999999165534973]</span></span><br><span class="line">DataRepresentation1.ScaleFactor = <span class="number">0.0359999991953373</span></span><br><span class="line"></span><br><span class="line">a1_p_PVLookupTable = GetLookupTableForArray( <span class="string">"p"</span>, <span class="number">1</span>, RGBPoints=[<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">1.0</span>, <span class="number">1e-16</span>, <span class="number">1.0</span>, <span class="number">0.0</span>, <span class="number">0.0</span>], VectorMode=<span class="string">'Magnitude'</span>, NanColor=[<span class="number">0.498039</span>, <span class="number">0.498039</span>, <span class="number">0.498039</span>], ColorSpace=<span class="string">'HSV'</span>, ScalarRangeInitialized=<span class="number">1.0</span> )</span><br><span class="line"></span><br><span class="line">a1_p_PiecewiseFunction = CreatePiecewiseFunction( Points=[<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.5</span>, <span class="number">0.0</span>, <span class="number">1e-16</span>, <span class="number">1.0</span>, <span class="number">0.5</span>, <span class="number">0.0</span>] )</span><br><span class="line"></span><br><span class="line">DataRepresentation1.ScalarOpacityFunction = a1_p_PiecewiseFunction</span><br><span class="line">DataRepresentation1.LookupTable = a1_p_PVLookupTable</span><br><span class="line"><span class="comment">#DataRepresentation1.RadiusRange = [-0.07, 0.29]</span></span><br><span class="line"></span><br><span class="line">a1_p_PVLookupTable.ScalarOpacityFunction = a1_p_PiecewiseFunction</span><br><span class="line"></span><br><span class="line">RenderView1.CameraPosition = [<span class="number">0.10999999567866325</span>, <span class="number">0.0</span>, <span class="number">0.7023592915690968</span>]</span><br><span class="line">RenderView1.CameraFocalPoint = [<span class="number">0.10999999567866325</span>, <span class="number">0.0</span>, <span class="number">0.0</span>]</span><br><span class="line">RenderView1.CameraClippingRange = [<span class="number">0.6943406986061459</span>, <span class="number">0.7141471810021238</span>]</span><br><span class="line">RenderView1.CameraParallelScale = <span class="number">0.18178396116279658</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">######### generate a slice ################</span></span><br><span class="line">Slice1 = Slice( SliceType=<span class="string">"Plane"</span> ) <span class="comment">## 作一个截面</span></span><br><span class="line"></span><br><span class="line">Slice1.SliceOffsetValues = [<span class="number">0.0</span>] <span class="comment">## 截面属性的设置,想必这种不需要解释,因为属性名字跟Paraview里是一样的</span></span><br><span class="line">Slice1.SliceType.Origin = [<span class="number">0.11</span>, <span class="number">0.0</span>, <span class="number">0.0</span>]</span><br><span class="line">Slice1.SliceType = <span class="string">"Plane"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># toggle the 3D widget visibility.</span></span><br><span class="line"><span class="comment">#active_objects.source.SMProxy.InvokeEvent('UserEvent', 'ShowWidget')</span></span><br><span class="line"><span class="comment">#RenderView1.CameraClippingRange = [0.4287074803602159, 1.0485246743217493]</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># toggle the 3D widget visibility.</span></span><br><span class="line">active_objects.source.SMProxy.InvokeEvent(<span class="string">'UserEvent'</span>, <span class="string">'HideWidget'</span>) <span class="comment">## 这句在后面有说明</span></span><br><span class="line">RenderView1.CameraClippingRange = [<span class="number">0.6943406986061459</span>, <span class="number">0.7141471810021238</span>]</span><br><span class="line"></span><br><span class="line">Slice1.SliceType.Normal = [<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">1.0</span>]</span><br><span class="line"></span><br><span class="line">DataRepresentation2 = Show()</span><br><span class="line"><span class="comment">#DataRepresentation2.ConstantRadius = 0.28999999165534973</span></span><br><span class="line">DataRepresentation2.EdgeColor = [<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.5000076295109483</span>]</span><br><span class="line"><span class="comment">#DataRepresentation2.PointSpriteDefaultsInitialized = 1</span></span><br><span class="line">DataRepresentation2.SelectionPointFieldDataArrayName = <span class="string">'p'</span></span><br><span class="line">DataRepresentation2.SelectionCellFieldDataArrayName = <span class="string">'p'</span></span><br><span class="line">DataRepresentation2.ColorArrayName = (<span class="string">'POINT_DATA'</span>, <span class="string">'p'</span>)</span><br><span class="line">DataRepresentation2.Texture = []</span><br><span class="line">DataRepresentation2.LookupTable = a1_p_PVLookupTable</span><br><span class="line"><span class="comment">#DataRepresentation2.RadiusRange = [-0.07000000029802322, 0.28999999165534973]</span></span><br><span class="line">DataRepresentation2.ScaleFactor = <span class="number">0.0359999991953373</span></span><br><span class="line"></span><br><span class="line">DataRepresentation1.Visibility = <span class="number">0</span> <span class="comment">## 把第一个source设置为不显示,对应着在 Paraview 里,将pipeline中 PM.foam 前面的“眼睛” 关掉</span></span><br><span class="line"></span><br><span class="line">RenderView1.CameraClippingRange = [<span class="number">0.6953356986534058</span>, <span class="number">0.7128946809426333</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">#DataRepresentation2.RadiusRange = [-0.07, 0.29]</span></span><br><span class="line">DataRepresentation2.ColorArrayName = (<span class="string">'POINT_DATA'</span>, <span class="string">'U'</span>) <span class="comment">## 将颜色显示改为用速度来显示。</span></span><br><span class="line"></span><br><span class="line">a3_U_PVLookupTable = GetLookupTableForArray( <span class="string">"U"</span>, <span class="number">3</span>, RGBPoints=[<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">1.0</span>, <span class="number">16.0</span>, <span class="number">1.0</span>, <span class="number">0.0</span>, <span class="number">0.0</span>], VectorMode=<span class="string">'Magnitude'</span>, NanColor=[<span class="number">0.498039</span>, <span class="number">0.498039</span>, <span class="number">0.498039</span>], ColorSpace=<span class="string">'HSV'</span>, ScalarRangeInitialized=<span class="number">1.0</span>, LockScalarRange=<span class="number">1</span> ) <span class="comment">## 这里是设置速度的范围,以及速度与颜色的映射关系</span></span><br><span class="line"></span><br><span class="line">a3_U_PiecewiseFunction = CreatePiecewiseFunction( Points=[<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.5</span>, <span class="number">0.0</span>, <span class="number">16.0</span>, <span class="number">1.0</span>, <span class="number">0.5</span>, <span class="number">0.0</span>] )</span><br><span class="line"></span><br><span class="line">AnimationScene1.AnimationTime = <span class="number">0.1</span></span><br><span class="line"></span><br><span class="line">ScalarBarWidgetRepresentation1 = CreateScalarBar( ComponentTitle=<span class="string">'Magnitude'</span>, Title=<span class="string">'U'</span>, Enabled=<span class="number">1</span>, LabelFontSize=<span class="number">12</span>, LookupTable=a3_U_PVLookupTable, TitleFontSize=<span class="number">12</span> )</span><br><span class="line">GetRenderView().Representations.append(ScalarBarWidgetRepresentation1)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">###### generate a glyph #################</span></span><br><span class="line">Glyph1 = Glyph( GlyphType=<span class="string">"Arrow"</span>, GlyphTransform=<span class="string">"Transform2"</span> ) <span class="comment">## 作流场箭头</span></span><br><span class="line"></span><br><span class="line">DataRepresentation2.LookupTable = a3_U_PVLookupTable</span><br><span class="line"></span><br><span class="line">a3_U_PVLookupTable.ScalarOpacityFunction = a3_U_PiecewiseFunction</span><br><span class="line"></span><br><span class="line">Glyph1.Scalars = [<span class="string">'POINTS'</span>, <span class="string">'p'</span>]</span><br><span class="line">Glyph1.SetScaleFactor = <span class="number">0.0359999991953373</span></span><br><span class="line">Glyph1.Vectors = [<span class="string">'POINTS'</span>, <span class="string">'U'</span>]</span><br><span class="line">Glyph1.GlyphTransform = <span class="string">"Transform2"</span></span><br><span class="line">Glyph1.GlyphType = <span class="string">"Arrow"</span></span><br><span class="line"></span><br><span class="line">Glyph1.SetScaleFactor = <span class="number">0.01</span></span><br><span class="line">Glyph1.ScaleMode = <span class="string">'off'</span></span><br><span class="line">Glyph1.MaximumNumberofPoints = <span class="number">1000</span></span><br><span class="line"></span><br><span class="line">DataRepresentation3 = Show()</span><br><span class="line"><span class="comment">#DataRepresentation3.ConstantRadius = 0.2999996840953827</span></span><br><span class="line">DataRepresentation3.EdgeColor = [<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.5000076295109483</span>]</span><br><span class="line"><span class="comment">#DataRepresentation3.PointSpriteDefaultsInitialized = 1</span></span><br><span class="line">DataRepresentation3.SelectionPointFieldDataArrayName = <span class="string">'p'</span></span><br><span class="line">DataRepresentation3.SelectionCellFieldDataArrayName = <span class="string">'p'</span></span><br><span class="line">DataRepresentation3.ColorArrayName = (<span class="string">'POINT_DATA'</span>, <span class="string">'U'</span>)</span><br><span class="line">DataRepresentation3.Texture = []</span><br><span class="line"><span class="comment">#DataRepresentation3.RadiusRange = [-0.07000353187322617, 0.2999996840953827]</span></span><br><span class="line">DataRepresentation3.ScaleFactor = <span class="number">0.03700032159686089</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#DataRepresentation3.ColorArrayName = ('POINT_DATA', '')</span></span><br><span class="line"></span><br><span class="line">RenderView1.CameraClippingRange = [<span class="number">0.6936123081169067</span>, <span class="number">0.7150640745576737</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">#DataRepresentation3.RadiusRange = [-0.0700035, 0.3]</span></span><br><span class="line">DataRepresentation3.ColorArrayName = (<span class="string">'POINT_DATA'</span>, <span class="string">'p'</span>)</span><br><span class="line">DataRepresentation3.LookupTable = a1_p_PVLookupTable</span><br><span class="line"></span><br><span class="line">DataRepresentation2.Texture = []</span><br><span class="line">DataRepresentation2.Visibility = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">ScalarBarWidgetRepresentation1.Enabled = <span class="number">0</span></span><br><span class="line">ScalarBarWidgetRepresentation1.Visibility = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">a1_p_PVLookupTable.RGBPoints = [-<span class="number">96.12127685546875</span>, <span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">1.0</span>, <span class="number">61.768226623535156</span>, <span class="number">1.0</span>, <span class="number">0.0</span>, <span class="number">0.0</span>]</span><br><span class="line"></span><br><span class="line">a1_p_PiecewiseFunction.Points = [-<span class="number">96.12127685546875</span>, <span class="number">0.0</span>, <span class="number">0.5</span>, <span class="number">0.0</span>, <span class="number">61.768226623535156</span>, <span class="number">1.0</span>, <span class="number">0.5</span>, <span class="number">0.0</span>]</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">###### generate a surface vector ###################</span></span><br><span class="line">SetActiveSource(Slice1) <span class="comment">## 将截面这个 source 设置为当前的source ,即对应在 Paraview 里用鼠标选择 slice</span></span><br><span class="line">SurfaceVectors1 = SurfaceVectors() <span class="comment">## 然后,在 slice 上使用 Surface Vectors 这个 fliter</span></span><br><span class="line"></span><br><span class="line">SurfaceVectors1.SelectInputVectors = [<span class="string">'POINTS'</span>, <span class="string">'U'</span>]</span><br><span class="line"></span><br><span class="line">DataRepresentation4 = Show()</span><br><span class="line"><span class="comment">#DataRepresentation4.ConstantRadius = 0.28999999165534973</span></span><br><span class="line">DataRepresentation4.EdgeColor = [<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.5000076295109483</span>]</span><br><span class="line"><span class="comment">#DataRepresentation4.PointSpriteDefaultsInitialized = 1</span></span><br><span class="line">DataRepresentation4.SelectionPointFieldDataArrayName = <span class="string">'p'</span></span><br><span class="line">DataRepresentation4.SelectionCellFieldDataArrayName = <span class="string">'p'</span></span><br><span class="line">DataRepresentation4.ColorArrayName = (<span class="string">'POINT_DATA'</span>, <span class="string">'U'</span>)</span><br><span class="line">DataRepresentation4.Texture = []</span><br><span class="line">DataRepresentation4.LookupTable = a3_U_PVLookupTable</span><br><span class="line"><span class="comment">#DataRepresentation4.RadiusRange = [-0.07000000029802322, 0.28999999165534973]</span></span><br><span class="line">DataRepresentation4.ScaleFactor = <span class="number">0.0359999991953373</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#DataRepresentation4.RadiusRange = [-0.07, 0.29]</span></span><br><span class="line"></span><br><span class="line">DataRepresentation3.Visibility = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">RenderView1.CameraClippingRange = [<span class="number">0.6953356986534058</span>, <span class="number">0.7128946809426333</span>]</span><br><span class="line"></span><br><span class="line">DataRepresentation2.Texture = []</span><br><span class="line"></span><br><span class="line">DataRepresentation2.Visibility = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">RenderView1.CameraClippingRange = [<span class="number">0.002996152353161611</span>, <span class="number">2.9961523531616105</span>]</span><br><span class="line"></span><br><span class="line">DataRepresentation4.Visibility = <span class="number">1</span></span><br><span class="line"></span><br><span class="line">ScalarBarWidgetRepresentation1.Enabled = <span class="number">1</span></span><br><span class="line">ScalarBarWidgetRepresentation1.Visibility = <span class="number">1</span></span><br><span class="line"></span><br><span class="line">RenderView1.CameraPosition = [<span class="number">0.10999999567866325</span>, <span class="number">0.0</span>, <span class="number">0.702356634767752</span>]</span><br><span class="line">RenderView1.CameraClippingRange = [<span class="number">0.6953330684200745</span>, <span class="number">0.7128919842892683</span>]</span><br><span class="line">RenderView1.CameraParallelScale = <span class="number">0.1817832735320095</span></span><br><span class="line"></span><br><span class="line">DataRepresentation4.Texture = []</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">##### generate a maskpoint ##########################</span></span><br><span class="line">MaskPoints1 = MaskPoints() <span class="comment">## 在 SurfaceVector1 的基础上使用 Mask Points 这个filter</span></span><br><span class="line"></span><br><span class="line">MaskPoints1.GenerateVertices = <span class="number">1</span></span><br><span class="line">MaskPoints1.RandomSampling = <span class="number">1</span></span><br><span class="line">MaskPoints1.RandomSamplingMode = <span class="string">'Spatially Stratified Random Sampling'</span></span><br><span class="line">MaskPoints1.MaximumNumberofPoints = <span class="number">1000</span></span><br><span class="line"></span><br><span class="line">DataRepresentation5 = Show()</span><br><span class="line"><span class="comment">#DataRepresentation5.ConstantRadius = 0.28999999165534973</span></span><br><span class="line">DataRepresentation5.EdgeColor = [<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.5000076295109483</span>]</span><br><span class="line"><span class="comment">#DataRepresentation5.PointSpriteDefaultsInitialized = 1</span></span><br><span class="line">DataRepresentation5.SelectionPointFieldDataArrayName = <span class="string">'p'</span></span><br><span class="line">DataRepresentation5.SelectionCellFieldDataArrayName = <span class="string">'p'</span></span><br><span class="line">DataRepresentation5.ColorArrayName = (<span class="string">'POINT_DATA'</span>, <span class="string">'U'</span>)</span><br><span class="line">DataRepresentation5.Texture = []</span><br><span class="line">DataRepresentation5.LookupTable = a3_U_PVLookupTable</span><br><span class="line"><span class="comment">#DataRepresentation5.RadiusRange = [-0.07000000029802322, 0.28999999165534973]</span></span><br><span class="line">DataRepresentation5.ScaleFactor = <span class="number">0.0359999991953373</span></span><br><span class="line"></span><br><span class="line">DataRepresentation4.Visibility = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#DataRepresentation5.RadiusRange = [-0.07, 0.29]</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">####### generate stream line on a surface #########################</span></span><br><span class="line">SetActiveSource(SurfaceVectors1) <span class="comment">## 选定 SurfaceVectors1,在此基础上,使用 Stream Tracer With Custom Source 这个 fliter。因此,这种情况下,Input 就等于 SurfaceVectors1 了</span></span><br><span class="line">StreamTracerWithCustomSource1 = StreamTracerWithCustomSource( SeedSource=MaskPoints1 ) <span class="comment">## 本来这里括号里应该还需要指定 Input 的,但是上一句已经默认了 Input 为 SurfaceVectors1</span></span><br><span class="line"></span><br><span class="line">StreamTracerWithCustomSource1.Vectors = [<span class="string">'POINTS'</span>, <span class="string">'U'</span>]</span><br><span class="line">StreamTracerWithCustomSource1.MaximumStreamlineLength = <span class="number">0.35999999195337296</span></span><br><span class="line"></span><br><span class="line">StreamTracerWithCustomSource1.MaximumError = <span class="number">1e-06</span></span><br><span class="line">StreamTracerWithCustomSource1.TerminalSpeed = <span class="number">1e-12</span></span><br><span class="line"></span><br><span class="line">DataRepresentation6 = Show()</span><br><span class="line"><span class="comment">#DataRepresentation6.ConstantRadius = 0.28999999165534973</span></span><br><span class="line">DataRepresentation6.EdgeColor = [<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.5000076295109483</span>]</span><br><span class="line"><span class="comment">#DataRepresentation6.PointSpriteDefaultsInitialized = 1</span></span><br><span class="line">DataRepresentation6.SelectionPointFieldDataArrayName = <span class="string">'p'</span></span><br><span class="line">DataRepresentation6.SelectionCellFieldDataArrayName = <span class="string">'ReasonForTermination'</span></span><br><span class="line">DataRepresentation6.ColorArrayName = (<span class="string">'POINT_DATA'</span>, <span class="string">'U'</span>)</span><br><span class="line">DataRepresentation6.Texture = []</span><br><span class="line">DataRepresentation6.LookupTable = a3_U_PVLookupTable</span><br><span class="line"><span class="comment">#DataRepresentation6.RadiusRange = [-0.07000000029802322, 0.28999999165534973]</span></span><br><span class="line">DataRepresentation6.ScaleFactor = <span class="number">0.0359999991953373</span></span><br><span class="line"></span><br><span class="line">DataRepresentation5.Visibility = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#DataRepresentation6.RadiusRange = [-0.07, 0.29]</span></span><br><span class="line">DataRepresentation6.ColorArrayName = (<span class="string">'POINT_DATA'</span>, <span class="string">''</span>)</span><br><span class="line"></span><br><span class="line">ScalarBarWidgetRepresentation1.Enabled = <span class="number">0</span></span><br><span class="line">ScalarBarWidgetRepresentation1.Visibility = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">MaskPoints1.MaximumNumberofPoints = <span class="number">200</span></span><br><span class="line"></span><br><span class="line">DataRepresentation6.Texture = []</span><br><span class="line"></span><br><span class="line">DataRepresentation6.Opacity = <span class="number">0.7</span></span><br><span class="line">DataRepresentation6.DiffuseColor = [<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.0</span>]</span><br><span class="line"></span><br><span class="line">DataRepresentation4.Texture = []</span><br><span class="line"></span><br><span class="line">DataRepresentation4.Visibility = <span class="number">1</span> <span class="comment">## 开启 SurfaceVectors1 的显示</span></span><br><span class="line"></span><br><span class="line">RenderView1.CameraPosition = [<span class="number">0.10999999567866325</span>, <span class="number">0.0</span>, <span class="number">0.4797190320113051</span>]</span><br><span class="line">RenderView1.CameraClippingRange = [<span class="number">0.47492184169119206</span>, <span class="number">0.4869148174914747</span>]</span><br><span class="line"></span><br><span class="line">DataRepresentation2.Texture = []</span><br><span class="line"></span><br><span class="line">DataRepresentation2.Visibility = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">DataRepresentation4.Texture = []</span><br><span class="line"></span><br><span class="line">WriteImage(<span class="string">'E:/OF_tutorials/mapped/pitzDailyMapped/testscreen.png'</span>, Magnification=<span class="number">2</span>) <span class="comment">## 将 SurfaceVectors1 和 stream line 叠加的视图输出为屏幕截图,截图大小为设置的窗口大小的两倍</span></span><br><span class="line"></span><br><span class="line">DataRepresentation6.Visibility = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">DataRepresentation4.Visibility = <span class="number">0</span> <span class="comment">## 关闭 SurfaceVectors1 的显示</span></span><br><span class="line"></span><br><span class="line">RenderView1.CameraClippingRange = [<span class="number">0.0026043054963398975</span>, <span class="number">2.6043054963398973</span>]</span><br><span class="line"></span><br><span class="line">DataRepresentation3.Texture = []</span><br><span class="line"></span><br><span class="line">DataRepresentation3.Visibility = <span class="number">1</span></span><br><span class="line"></span><br><span class="line">RenderView1.CameraPosition = [<span class="number">0.11499807611107826</span>, <span class="number">0.00038802623748779297</span>, <span class="number">0.725254404116244</span>]</span><br><span class="line">RenderView1.CameraFocalPoint = [<span class="number">0.11499807611107826</span>, <span class="number">0.00038802623748779297</span>, <span class="number">0.0</span>]</span><br><span class="line">RenderView1.CameraClippingRange = [<span class="number">0.7162784695385823</span>, <span class="number">0.7383026137930281</span>]</span><br><span class="line">RenderView1.CenterOfRotation = [<span class="number">0.11499807611107826</span>, <span class="number">0.00038802623748779297</span>, <span class="number">0.0</span>]</span><br><span class="line">RenderView1.CameraParallelScale = <span class="number">0.18770965232976394</span></span><br><span class="line"></span><br><span class="line">DataRepresentation2.Texture = []</span><br><span class="line"></span><br><span class="line">DataRepresentation2.Visibility = <span class="number">1</span> <span class="comment">## 开启 slice 的显示 </span></span><br><span class="line"></span><br><span class="line">DataRepresentation3.Texture = []</span><br><span class="line"></span><br><span class="line">DataRepresentation3.ColorArrayName = (<span class="string">'POINT_DATA'</span>, <span class="string">''</span>)</span><br><span class="line">DataRepresentation3.DiffuseColor = [<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.0</span>]</span><br><span class="line"></span><br><span class="line">RenderView1.CameraPosition = [<span class="number">0.11499807611107826</span>, <span class="number">0.00038802623748779297</span>, <span class="number">0.599383805054747</span>]</span><br><span class="line">RenderView1.CameraClippingRange = [<span class="number">0.5916665764677003</span>, <span class="number">0.6105439557456087</span>]</span><br><span class="line"></span><br><span class="line">AnimationScene1.AnimationTime = <span class="number">0.0</span></span><br><span class="line">AnimationScene1.PlayMode = <span class="string">'Sequence'</span> <span class="comment">## 设置动画的播放模式</span></span><br><span class="line">AnimationScene1.NumberOfFrames = <span class="number">11</span></span><br><span class="line"></span><br><span class="line">CameraAnimationCue1 = GetCameraTrack()</span><br><span class="line">CameraAnimationCue1.AnimatedProxy = RenderView1</span><br><span class="line">CameraAnimationCue1.Mode = <span class="string">'Path-based'</span> <span class="comment">## 设置 Camera 的旋转</span></span><br><span class="line"></span><br><span class="line">TimeAnimationCue1 = GetTimeTrack()</span><br><span class="line"></span><br><span class="line">KeyFrame5047 = CameraKeyFrame( FocalPathPoints=[<span class="number">0.114998</span>, <span class="number">0.000388026</span>, <span class="number">0.0</span>], FocalPoint=[<span class="number">0.11499807611107826</span>, <span class="number">0.00038802623748779297</span>, <span class="number">0.0</span>], PositionPathPoints=[<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.5</span>, <span class="number">0.43120039439853625</span>, <span class="number">0.0</span>, <span class="number">0.40403042680054746</span>, <span class="number">0.6279812289875636</span>, <span class="number">0.0</span>, <span class="number">0.008529172380306538</span>, <span class="number">0.4444572181383874</span>, <span class="number">0.0</span>, -<span class="number">0.39329526260513553</span>, <span class="number">0.016685579000083814</span>, <span class="number">0.0</span>, -<span class="number">0.5035466293017314</span>, -<span class="number">0.3382012405958345</span>, <span class="number">0.0</span>, -<span class="number">0.24048906072285084</span>, -<span class="number">0.35710462563060374</span>, <span class="number">0.0</span>, <span class="number">0.20085728982710624</span>], ClosedPositionPath=<span class="number">1</span>, ParallelScale=<span class="number">0.18770965232976394</span>, Position=[<span class="number">0.11499807611107826</span>, <span class="number">0.00038802623748779297</span>, <span class="number">0.725254404116244</span>] )</span><br><span class="line"></span><br><span class="line">KeyFrame5048 = CameraKeyFrame( ParallelScale=<span class="number">0.18770965232976394</span>, Position=[<span class="number">0.11499807611107826</span>, <span class="number">0.00038802623748779297</span>, <span class="number">0.725254404116244</span>], KeyTime=<span class="number">1.0</span>, FocalPoint=[<span class="number">0.11499807611107826</span>, <span class="number">0.00038802623748779297</span>, <span class="number">0.0</span>] )</span><br><span class="line"></span><br><span class="line">CameraAnimationCue1.KeyFrames = [ KeyFrame5047, KeyFrame5048 ]</span><br><span class="line"></span><br><span class="line">RenderView1.CameraFocalPoint = [<span class="number">0.10459624231466369</span>, <span class="number">0.000388026</span>, -<span class="number">0.002392362660596616</span>]</span><br><span class="line">RenderView1.CameraClippingRange = [<span class="number">0.5303500129360129</span>, <span class="number">0.7361458699228238</span>]</span><br><span class="line">RenderView1.CameraPosition = [-<span class="number">0.03455133768533633</span>, -<span class="number">8.148545999999996e-05</span>, <span class="number">0.6026076373394033</span>]</span><br><span class="line"></span><br><span class="line">WriteAnimation(<span class="string">'E:/OF_tutorials/mapped/pitzDailyMapped/ani/rotateTest.png'</span>, Magnification=<span class="number">2</span>, Quality=<span class="number">2</span>, FrameRate=<span class="number">15.000000</span>) <span class="comment">## 输出动画,</span></span><br><span class="line"></span><br><span class="line">Render()</span><br></pre></td></tr></table></figure>
<h5 id="一些细节:">一些细节:</h5><ul>
<li><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">active_objects<span class="class">.source</span><span class="class">.SMProxy</span><span class="class">.InvokeEvent</span>(<span class="string">'UserEvent'</span>, <span class="string">'HideWidget'</span>)</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>语句的作用是,不显示 slice 的时候产生的哪个边框,即相当于 Paraview 里点掉 slice 的 “Show Plane”。</p>
<ul>
<li><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RenderView1<span class="class">.Background</span> = (<span class="number">81.0</span>/<span class="number">255.0</span>, <span class="number">87.0</span>/<span class="number">255.0</span>, <span class="number">110.0</span>/<span class="number">255.0</span>)</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>作用是设置 RenderView1 的背景颜色。如果是直接在 Paraview 里以宏的形式运行脚本,那不需要这个,但若是用 pvpython 来运行脚本则需要,否则背景是黑色的。另外,这里的 RGB 颜色是用 255 归一化过的。</p>
<ul>
<li>颜色显示应该是以下几个语句的结果<figure class="highlight nix"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">a3_U_PVLookupTable =</span> GetLookupTableForArray( <span class="string">"U"</span>, <span class="number">3</span>, <span class="variable">RGBPoints=</span>[<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">1.0</span>, <span class="number">16.0</span>, <span class="number">1.0</span>, <span class="number">0.0</span>, <span class="number">0.0</span>], <span class="variable">VectorMode=</span>'Magnitude', <span class="variable">NanColor=</span>[<span class="number">0.498039</span>, <span class="number">0.498039</span>, <span class="number">0.498039</span>], <span class="variable">ColorSpace=</span>'HSV', <span class="variable">ScalarRangeInitialized=</span><span class="number">1.0</span>, <span class="variable">LockScalarRange=</span><span class="number">1</span> )</span><br><span class="line"></span><br><span class="line"><span class="variable">a3_U_PiecewiseFunction =</span> CreatePiecewiseFunction( <span class="variable">Points=</span>[<span class="number">0.0</span>, <span class="number">0.0</span>, <span class="number">0.5</span>, <span class="number">0.0</span>, <span class="number">16.0</span>, <span class="number">1.0</span>, <span class="number">0.5</span>, <span class="number">0.0</span>] )</span><br><span class="line"></span><br><span class="line">DataRepresentation4.<span class="variable">LookupTable =</span> a3_U_PVLookupTable</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>至于 LookupTable 中,RGBPoints 的构建规则,细节不清楚。这种套用模板就好了,没必要自己手动写。</p>
<ul>
<li>相机的位置,即在 Paraview 里看到的图片的位置,旋转角度,远近等,由以下语句控制:<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">RenderView1<span class="class">.CameraPosition</span> = [<span class="number">0.11499807611107826</span>, <span class="number">0.00038802623748779297</span>, <span class="number">0.725254404116244</span>]</span><br><span class="line">RenderView1<span class="class">.CameraFocalPoint</span> = [<span class="number">0.11499807611107826</span>, <span class="number">0.00038802623748779297</span>, <span class="number">0.0</span>]</span><br><span class="line">RenderView1<span class="class">.CameraClippingRange</span> = [<span class="number">0.7162784695385823</span>, <span class="number">0.7383026137930281</span>]</span><br><span class="line">RenderView1<span class="class">.CenterOfRotation</span> = [<span class="number">0.11499807611107826</span>, <span class="number">0.00038802623748779297</span>, <span class="number">0.0</span>]</span><br><span class="line">RenderView1<span class="class">.CameraParallelScale</span> = <span class="number">0.18770965232976394</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>这些数据对不同算例是不一样的,需要根据特定情景来修改。没必要手动改,应该用 trace 功能来生成这些坐标值。</p>
<ul>
<li>关于相机选择部分,参考之前<a href="http://xiaopingqiu.github.io/2016/08/27/ParaviewCamera/" target="_blank" rel="external">那篇</a>讲添加旋转相机的。这些代码也应该用 trace 来生成,一般情况下没必要自找麻烦去手写。</li>
</ul>
<p>最后附上一些上面脚本中没有涉及到,但可能会用到的功能:</p>
<ol>
<li>dir 用来查找一个对象所有可调用的函数,比如,假如 slice1 是一个 Slice 的对象,dir(slice1),则将列出所有 slice1 可以调用的函数或者成员。help(slice1) 类似,而且会列出每个函数的简短说明,这是 python 的特性。</li>
<li><p>关于动画时间的操作</p>
<figure class="highlight 1c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">animationScene1.GoToNext() <span class="preprocessor">## 下一帧 </span></span><br><span class="line"></span><br><span class="line">animationScene1.Play() <span class="preprocessor">## 播放动画</span></span><br><span class="line"></span><br><span class="line">animationScene1.GoToFirst() <span class="preprocessor">## 跳到开始</span></span><br><span class="line"></span><br><span class="line">animationScene1.GoToLast() <span class="preprocessor">## 跳到最后</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>Hide, Show, Render<br>Hide 和 Show 可以作用于 pipeline 里的每个条目,使其隐藏/可见,对应 paraview 关闭/点亮某个“眼睛”。Render 是当改变了某个显示属性后,要想显示出改变以后的效果需要调用的函数,相当于 Paraview 里点 Apply。</p>
</li>
<li>setActiveSource,getActiveSource,setActiveView,getActiveView<br>这四个,作用分别是,将某个 pipeline设为选定状态,相当于鼠标选中某个 pipeline;获取当前选定的 pipeline;将某个 窗口设为选定状态(针对有多个窗口的情形);返回当前选定的窗口。此外,还有很多对 pipeline 和 窗口进行操作的接口,需要时查即可。</li>
<li><p>pvpython 本质上就是 python,所以,python 的语法都可以用。比如,下面是一个循环删除所有 pipeline 的方法</p>
<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> key <span class="keyword">in</span> <span class="function"><span class="title">GetSources</span><span class="params">()</span></span>.<span class="function"><span class="title">keys</span><span class="params">()</span></span>:</span><br><span class="line"> s = <span class="function"><span class="title">GetSources</span><span class="params">()</span></span>[key]</span><br><span class="line"> <span class="function"><span class="title">Delete</span><span class="params">(s)</span></span></span><br><span class="line"> <span class="tag">del</span> s</span><br></pre></td></tr></table></figure>
</li>
<li><p>Paraview 的 python shell(Tools->Python Shell),可以当作是一个 pvpython 的 IDE,里面可以方便地进行命令补全,并且每条语句的效果可以即时地显示在 Paraview 中,调试脚本的时候非常有用。</p>
<p>最后说明一下,上述脚本只适用于 Paraview-4.1,在 Paraview-5.0 以后,接口的名字有所变化,这里给出一个<a href="https://github.com/xiaopingqiu/ParaviewScripts" target="_blank" rel="external">链接</a>,感兴趣的读者可以在链接中找到本文中介绍的脚本以及另一个适用于 Paraview-5.0 的脚本。</p>
</li>
</ol>
<p>参考:</p>
<ol>
<li><a href="http://www.paraview.org/Wiki/ParaView/Python_Scripting" target="_blank" rel="external">http://www.paraview.org/Wiki/ParaView/Python_Scripting</a></li>
<li><a href="http://www.paraview.org/Wiki/Python_recipes" target="_blank" rel="external">http://www.paraview.org/Wiki/Python_recipes</a></li>
<li><a href="http://www.paraview.org/ParaView/Doc/Nightly/www/py-doc/index.html" target="_blank" rel="external">http://www.paraview.org/ParaView/Doc/Nightly/www/py-doc/index.html</a></li>
</ol>
]]></content>
<summary type="html">
<![CDATA[<p>Paraview 提供了一个 python 接口,可以用 python 脚本来控制 Paraview,以实现自动化的后处理。使用方法是,先写一个 python 脚本,里面包含调用 Paraview 的各种语句,然后,用 Paraview 的安装目录的 bin 下的 <code>pvpython</code> 来运行这个脚本即可。本篇用一个例子来说明 python 脚本的写法,以及常用 Paraview 操作对应的语句。</p>]]>
</summary>
<category term="Postprocessing" scheme="http://xiaopingqiu.github.io/tags/Postprocessing/"/>
<category term="Paraview" scheme="http://xiaopingqiu.github.io/categories/Paraview/"/>
</entry>
<entry>
<title><![CDATA[Paraview 中有关 Camera 的操作两例]]></title>
<link href="http://xiaopingqiu.github.io/2016/08/27/ParaviewCamera/"/>
<id>http://xiaopingqiu.github.io/2016/08/27/ParaviewCamera/</id>
<published>2016-08-27T08:28:40.000Z</published>
<updated>2016-08-27T09:52:17.142Z</updated>
<content type="html"><![CDATA[<p>这篇介绍 Paraview 中有关 Camera 的两个操作:Link Camera 和 利用 Camera 来制作旋转动画。</p>
<a id="more"></a>
<h5 id="1-_Link_Camera">1. Link Camera</h5><p>这个功能作用是将两个窗口(views)链接起来,这样,当一个窗口的视角变动的时候,另一个也相应跟着变化。比如,建立 Link 之前,这两个视窗是独立转动的,</p>
<p><img src="/image/Paraview/beforeLink.png" alt=""></p>
<p>有时候,为了比较,希望两个视窗是同步转动的,这时只要建立一个 link 就可以了,在左边视窗右键点击空白处,选择 Link Camera,给这个Link 取个名字,然后左键点一下右边的视窗,就完成了链接</p>
<p><img src="/image/Paraview/Link1.png" alt=""></p>
<p>链接之后,二者就不再是独立的了。这种链接是双向的,改变其一,另一个也跟着改,而且,允许多个窗口链接在一起,如下图,左一和右上先建立了链接,然后再建立一个左一和右下的链接,这样就把三个都链接在一起了。</p>
<p><img src="/image/Paraview/Link2.png" alt=""></p>
<p>新版的(5.0以上)还有一个 Interactive view 的选项,<br><img src="/image/Paraview/Link5.png" alt=""><br>选择这个选项以后,<br><img src="/image/Paraview/Link6.gif" alt=""><br>会在建立链接的那一个视窗中(主动视窗),出现一个小的窗口,这个小窗口会将被链接视窗(被动视窗)的相同位置的显示结果叠加到主动视窗中。</p>
]]></content>
<summary type="html">
<![CDATA[<p>这篇介绍 Paraview 中有关 Camera 的两个操作:Link Camera 和 利用 Camera 来制作旋转动画。</p>]]>
</summary>
<category term="Postprocessing" scheme="http://xiaopingqiu.github.io/tags/Postprocessing/"/>
<category term="Paraview" scheme="http://xiaopingqiu.github.io/categories/Paraview/"/>
</entry>
<entry>
<title><![CDATA[Paraview 中创建 Custom Filter]]></title>
<link href="http://xiaopingqiu.github.io/2016/08/27/ParaviewCustomFilter/"/>
<id>http://xiaopingqiu.github.io/2016/08/27/ParaviewCustomFilter/</id>
<published>2016-08-27T08:04:07.000Z</published>
<updated>2016-08-27T09:52:07.585Z</updated>
<content type="html"><![CDATA[<p>在 <a href="http://xiaopingqiu.github.io/2016/08/27/ParaviewStreamLineOnSlice/" target="_blank" rel="external">上一篇</a>,介绍了如果作截面上的流线,其中涉及到多个 filter 的组合操作。如果每次都要来这么一串操作,挺繁琐的。Paraview 提供的 Custom Filter 的功能,能大大简化这种繁琐的重复操作。Custom Filter,本质上就是将一系列 filter 的组合操作打包成一个新的 filter。下面以作截面流线的操作为例,介绍如何创建一个 Custom Filter。</p>
<a id="more"></a>
<p>步骤如下:</p>
<ol>
<li>选定下图中所示的三个pipeline,</li>
</ol>
<p><img src="/image/Paraview/select1.png" alt=""></p>
<p>然后点右键选择 Create Custom Filter</p>
<p><img src="/image/Paraview/CF1.png" alt=""></p>
<ol>
<li>Next,进入 Custom Fliter 的配置环节</li>
</ol>
<p><img src="/image/Paraview/CFsetting1.png" alt=""></p>
<p>选择 SurfaceVector1,设置为 Input,并取名为 SurfaceVector,设置好以后,点 “+”添加这个 Input。<br>然后,Next</p>
<p><img src="/image/Paraview/CFsetting2.png" alt=""></p>
<p>将 StreamTracerWithCustomSource1 和 MaskPoints1 设置为 output。</p>
<p>继续 Next,这一步可以指定一些将来可以再调整的参数,如果不设置,那么新建立的 filter 将使用当前的 StreamTracerWithCustomSource1 和 MaskPoints1 使用的参数,不可调整,这样显然会严重限制新 fliter 的实用性,至少,我们应该添加控制 MaskPoint 的点数的参数。添加的方法是,选定左边的 MaskPoints,然后在右边的 Property 下拉菜单中,选择一个参数,比如,Maximum Number of Points,然后点 “+”,将来可能需要重新调整什么参数,就在这一步选上它,</p>
<p><img src="/image/Paraview/CFsetting3.png" alt=""></p>
<p>然后,点 Finish,就完成了 Custom Filter 的添加。</p>
<p>之后,你可以在 Filter 菜单中找到新添加的 SurfaceStreamLines ,将其用在某个 slice 上,就自动生成了这个 slice 的流线。</p>
<p><img src="/image/Paraview/CFusing1.png" alt=""></p>
<p>注意 pipe line 这边,能调的参数,正是在建立 Custom filter 的最后一步添加的那四个。</p>
<p>建立好的 Custom Filter,应该保存下来,用下图中的 export。要不然,下次打开Paraview,自定义的 filter 就没了。选择菜单的 Tools-> Manage Custom Filters</p>
<p><img src="/image/Paraview/export.png" alt=""></p>
<p>导出的文件可以共享给其他人。</p>
<p>如果对建立的 filter 不满意,需要删除重建,在上图中选择需要删除的,点 Remove 即可。</p>
]]></content>
<summary type="html">
<![CDATA[<p>在 <a href="http://xiaopingqiu.github.io/2016/08/27/ParaviewStreamLineOnSlice/">上一篇</a>,介绍了如果作截面上的流线,其中涉及到多个 filter 的组合操作。如果每次都要来这么一串操作,挺繁琐的。Paraview 提供的 Custom Filter 的功能,能大大简化这种繁琐的重复操作。Custom Filter,本质上就是将一系列 filter 的组合操作打包成一个新的 filter。下面以作截面流线的操作为例,介绍如何创建一个 Custom Filter。</p>]]>
</summary>
<category term="Postprocessing" scheme="http://xiaopingqiu.github.io/tags/Postprocessing/"/>
<category term="Paraview" scheme="http://xiaopingqiu.github.io/categories/Paraview/"/>
</entry>
<entry>
<title><![CDATA[在 Paraview 中画截面上的流线]]></title>
<link href="http://xiaopingqiu.github.io/2016/08/27/ParaviewStreamLineOnSlice/"/>
<id>http://xiaopingqiu.github.io/2016/08/27/ParaviewStreamLineOnSlice/</id>
<published>2016-08-27T07:39:10.000Z</published>
<updated>2016-08-27T08:03:04.437Z</updated>
<content type="html"><![CDATA[<p>paraview 的 Stream Tracer 无法直接作一个截面上的流线。比如,对于OpenFOAM的算例,即使是二维算例,截取一个面后,用 Stream tracer 无法得到流线。解决办法是存在的,本篇介绍如果通过一系列 filter 的组合来得到截面上的流线。</p>
<a id="more"></a>
<p>以 pitzdaily 算例为例,步骤如下:</p>
<ol>
<li><p>作一个截面(slice),这一步不需详述</p>
</li>
<li><p>对截面使用 Surface Vector filter,这个的作用是让速度矢量投影到平面上。</p>
</li>
<li><p>对得到的 SurfaceVector 使用 Mask Points filter,这个的作用是生成一系列参考点,将来画流线的时候,以这些参考点的位置来确定流线的位置和疏密。<br><img src="/image/Paraview/maskPoint.png" alt=""><br>On Ratio 参数控制取点的疏密,这里的设置,表示每2560个点中取一个;Maximum number of points 控制总点数的数目;Random Sampling,开启随机取点模式,如果是非随机模式,将按坐标从小到大取点。假设 On Ratio = 2560 情况下,一共有1000个点,但是 Maximum number of points 设置为 100,那么将只取坐标最小的前100个点,而如果开启了随机模式,则点的分布基本上是均匀充满这个流动区域的。Generate Vertices,选择是否要显示参考点,如果开启,则会显示一个点阵。</p>
</li>
<li><p>Filter 里选择 Stream Tracer with Custom Source,Input 和 Seed Source 分别按下图设置<br><img src="/image/Paraview/Input1.png" alt=""><br><img src="/image/Paraview/seedSource1.png" alt=""></p>
</li>
</ol>
<p>就得到了如下的流线图,流线的疏密,可以通过Mask Points 的点数来控制,只是,遗憾的是点数的空间分布不好控制,比如,我想让中间部分稀疏一点,角落上密一点,不容易做到。另外,还需要注意左边 Pipeline,出现了三个 StreamTracerWithCustomSource,似乎这三个其实是一个,改变任意一个都会改变流线的属性。</p>
<p><img src="/image/Paraview/streamline1.png" alt=""></p>
]]></content>
<summary type="html">
<![CDATA[<p>paraview 的 Stream Tracer 无法直接作一个截面上的流线。比如,对于OpenFOAM的算例,即使是二维算例,截取一个面后,用 Stream tracer 无法得到流线。解决办法是存在的,本篇介绍如果通过一系列 filter 的组合来得到截面上的流线。</p>]]>
</summary>
<category term="Postprocessing" scheme="http://xiaopingqiu.github.io/tags/Postprocessing/"/>
<category term="Paraview" scheme="http://xiaopingqiu.github.io/categories/Paraview/"/>
</entry>
<entry>
<title><![CDATA[OpenFOAM 中求解 ODE 一例]]></title>
<link href="http://xiaopingqiu.github.io/2016/08/21/ODE/"/>
<id>http://xiaopingqiu.github.io/2016/08/21/ODE/</id>
<published>2016-08-21T07:26:43.000Z</published>
<updated>2016-08-21T07:57:24.790Z</updated>
<content type="html"><![CDATA[<p>本篇介绍如何编写一个小程序来调用 OpenFOAM 的 ODE 求解器来求解任意常微分方程的初值问题。 </p>
<a id="more"></a>
<h5 id="1-_数学背景">1. 数学背景</h5><p>首先简要看一下涉及的数学背景。对于一阶的常微分方程,<br>$$<br>y’=f(x,y), \quad x\in[a,b] \\<br>y(a)=y_0<br>$$<br>常微分方程,如果存在解析解的话,其解应该是一个函数 $y=f(x)$。然而,大多数常微分方程是没有解析解的,只能数值求解。数值方法得到的,是一系列的 $x_0, x_1, \cdots x_n$ 对应的函数值 $y_0, y_1, \cdots y_n$。</p>
<p>常用的数值解法有:</p>
<ul>
<li>显式欧拉法<br>这种方法最简单,将区间 $[a,b]$ 分成 n 份,则得到步长 $h=(b-a)/n$。以 $y(a)=y_0$ 为起点,通过下述迭代,<br>$$<br>y_{m+1} = y_m+hf(x_m,y_m)<br>$$<br>可以得到 $x_m=a+m*h$ 处的函数值 $y_m$,此即为常微分方程的数值解。显式欧拉法形式简单,但是只有一阶精度,而且稳定性是有条件的,一般在实际中较少用到。</li>
<li>改进的欧拉法<br>这种方法是在显式欧拉法的基础上改进得到,将显式欧拉法中使用的向前积分改为梯形积分。其迭代形式为<br>$$<br>y_{m+1} = y_m +\frac{h}{2}[f(x_m,y_m)+f(x_{m+1},y_{m+1})]<br>$$<br>这种方法不是显式地,所以,需要在每一步内进行迭代求解。可以用如下的迭代公式<br>$$<br>y_{m+1}^{(n+1)} = y_m +\frac{h}{2}[f(x_m,y_m)+f(x_{m+1},y_{m+1}^{(n)})]<br>$$<br>注意,这里的 n 指的是计算 $y_{m+1}$ 的值时的内迭代次数,迭代的初始值 $y_{m+1}^{(0)}$ 可以用显式欧拉公式来给出<br>$$<br>y_{m+1}^{(0)} = y_m + hf(x_m, y_m)<br>$$</li>
<li>显式 4 阶 Runge-Kutta 方法<br>这是现实中常用的一种方法,其迭代形式如下<br>$$<br>\begin{align*}<br>y_{m+1} & = y_m + \frac{h}{6}[k_1+2k_2+2k_3+k_4] \\<br>k_1 & = f(x_m, y_m) \\<br>k_2 & = f(x_m+\frac{1}{2}h, y_m+\frac{1}{2}hk_1) \\<br>k_3 & = f(x_m+\frac{1}{2}h, y_m+\frac{1}{2}hk_2) \\<br>k_4& = f(x_m+h, y_m+hk_3)<br>\end{align*}<br>$$</li>
</ul>
<p>除了以上,当然还有很多方法,比如预测校正等等,这里就不再逐一介绍了。</p>
<p>问题是,实际中遇到的还可能是高阶的常微分方程,比如,弹簧-谐振子系统可以用以下e二阶常微分方程描述<br>$$<br>\frac{d^2y}{dt^2} = -\frac{k}{m}y<br>$$</p>
<p>高阶常微分方程的初值问题,可以用以下通式来描述<br>$$<br>y^{n} = f(x,y,y’,\cdots y^{n-1})<br>$$</p>
<p>其初始条件为<br>$$<br>y(0) = a_0, \quad y’(0) = a_1, \quad \cdots, \quad y^{n-1}(0) = a_n<br>$$<br>对于这种高阶常微分方程,可以将其表述为一系列一阶常微分方程的组成的方程组来求解。下面以二阶常微分方程为例,介绍如何将高阶常微分方程的初值问题转化为一阶常微分方程组。<br>考察如下二阶常微分方程<br>$$<br>y’’ = f(x,y,y’), \quad x\in[a,b] \\<br>y(a) = a_0, \quad y’(a) = a_1<br>$$</p>
<p>若令 $z=y’$,则上述二阶常微分方程可以表示成如下方程组<br>$$<br>\left \{<br>\begin{align*}<br>y’ &= z \\<br>z’ &= f(x,y,z)<br>\end{align*}<br>\right. \\<br>y(a)=a_0,\quad z(a)=a_1<br>$$</p>
<p>这个方程组,就可以用前面介绍的一阶常微分方程的解法来求解了,比如,若用最简单的显式欧拉法,则<br>$$<br>\begin{align*}<br>y_{m+1} &= y_m + h z_m \\<br>z_{m+1} &= z_m +hf(x_m, y_m, z_m)<br>\end{align*}<br>$$<br>或者用显式 4 阶 Runge-Kutta 方法<br>$$<br>\begin{align*}<br>y_{m+1} & = y_m + \frac{h}{6}[K_1+2K_2+2K_3+K_4] \\<br>z_{m+1} & = z_m + \frac{h}{6}[M_1+2M_2+2M_3+K_4] \\<br>K_1 & = z_m,\quad M_1=f(x_m, y_m, z_m) \\<br>K_2 & = z_m + \frac{M_1}{2}, \quad M_2 = f(x_m+\frac{h}{2}, y_m+\frac{K_1}{2}, z_m+\frac{M_1}{2})\\<br>K_3 & = z_m + \frac{M_2}{2},\quad M_3 = f(x_m+\frac{h}{2}, y_m+\frac{K_2}{2}, z_m+\frac{M_2}{2})\\<br>K_4& = z_m + M_3,\quad M_4=f(x_m+h, y_m+K_3, z_m+M_3)<br>\end{align*}<br>$$</p>
<p>二阶以上的常微分方程,除了可以给出初值条件,还可以给出边值条件,比如<br>$$<br>y’’ = f(x,y,y’), \quad x\in[a,b] \\<br>y(a) = \alpha, \quad y(b) = \beta<br>$$</p>
<p>这种情况下,就无法直接将此方程转化为一阶常微分方程组了。但是,边值问题可以通过一定的方法转换成初值问题,以下给出一种:<strong>试射法</strong>。<br>在不知道 $y’(a)$ 的情况下,不妨假设 $y’(a)=\gamma_1$,这样,就得到了一个初值问题<br>$$<br>y’’ = f(x,y,y’), \quad x\in[a,b] \\<br>y(a) = \alpha, \quad y’(a) = \gamma_1<br>$$<br>解此初值问题,得到 $y(b)$ 的值 $\beta_1$,并与 $\beta$ 比较,如果误差足够小,则认为假设的 $y’(a)=\gamma_1$ 是合理的。否则,就对 $\gamma_1$ 进行修正,比如令 $\gamma_2 = \tfrac{\beta}{\beta_1}\gamma_1$,然后再以 $y’(a)=\gamma_2$ 为初值,继续求解初值问题。直到得到的初值问题的解$y(b)=\beta_k$ 与 $\beta$ 足够接近为止。</p>
<p>上述方程可以归纳为,将初值问题转化为如下边值问题<br>$$<br>y’’ = f(x,y,y’), \quad x\in[a,b] \\<br>y(a) = \alpha, \quad y’(a) = \gamma_k, k=1,2,\cdots<br>$$<br>若记问题 $y_k(x)$ 的解为 $y(x;\gamma_k)$,则 $\gamma_k$ 的理想值应该满足<br>$$<br>F(\gamma) = y(b;\gamma)-\beta = 0<br>$$<br>这个方程,可以用牛顿迭代法来求解:<br>$$<br>\gamma_{k+1} = \gamma_k-\frac{F(\gamma_k)}{F’(\gamma_k)}<br>$$<br>其中,$F(\gamma_k)=y(b;\gamma_k)-\beta=\beta_k-\beta$。那么 $F’(\gamma_k)$ 该如何得到呢?根据 $F(\gamma_k)$ 的定义,可以知道 $F’(\gamma_k) = \frac{\partial y(b;\gamma)}{\partial \gamma}\big|_{\gamma=\gamma_k}$,若定义 $W=\frac{\partial y(b;\gamma)}{\partial \gamma}$,则 $F’(\gamma_k)=W(b;\gamma_k)$。</p>
<p>将上述归纳形式的初值问题,对$\gamma$ 求偏导,得<br>$$<br>\frac{\partial y’’}{\partial \gamma} = \frac{\partial f(x,y(x;\gamma),y’(x,y’))}{\partial y} \frac{\partial y(x;\gamma)}{\partial \gamma} + \frac{\partial f(x,y(x;\gamma),y’(x,y’))}{\partial y’} \frac{\partial y’(x,y’)}{\partial \gamma}<br>$$</p>
<p>根据 $W$ 的定义,有<br>$$<br>W=\frac{\partial y(x;\gamma)}{\partial \gamma}, W’=\frac{\partial y’(x,y’)}{\partial \gamma}, W’’=\frac{\partial y’’}{\partial \gamma}<br>$$</p>
<p>于是,可以得到一个关于 $W$ 的二阶常微分方程<br>$$<br>W’’=\frac{\partial f(x,y,y’)}{\partial y} W + \frac{\partial f(x,y,y’)}{\partial y’}W’<br>$$<br>其定解条件为<br>$$<br>W(a)=\frac{\partial y(a;\gamma)}{\partial \gamma}=0, W’(a)=\frac{\partial y’(a;\gamma)}{\partial \gamma}=\frac{\partial \gamma}{\partial \gamma} = 1<br>$$</p>
<p>这样就构成了一个关于 $W$ 的二阶初值常微分方程。<br>总结一下,二阶常微分方程的边值问题<br>$$<br>y’’ = f(x,y,y’), \quad x\in[a,b] \\<br>y(a) = \alpha, \quad y(b) = \beta<br>$$<br>的求解步骤如下:</p>
<ol>
<li>假定一个 $\gamma_1$ 值,求解初值问题<br>$$<br>y’’ = f(x,y,y’), \quad x\in[a,b] \\<br>y(a) = \alpha, \quad y’(a) = \gamma_1<br>$$<br>然后计算 $F(\gamma_1)=y(b;\gamma_1)$</li>
<li>求解关于 $W$ 的初值问题<br>$$<br>W’’=\frac{\partial f(x,y,y’)}{\partial y} W + \frac{\partial f(x,y,y’)}{\partial y’}W’ \\<br>W(a) = 0, W’(a) = 1<br>$$<br>然后计算 $F’(\gamma_1) = W(b;\gamma_1)$。</li>
<li>更新$\gamma$ 的值,<br>$$<br>\gamma_2 = \gamma_1-\frac{F(\gamma_1)}{F’(\gamma_1)}<br>$$<br>继续迭代,直到最后得到的 $y(b;\gamma_k)$ 与 $\beta$ 足够接近为止。</li>
</ol>
<h5 id="2-_OpenFOAM_中的实现">2. OpenFOAM 中的实现</h5><p>为了在OpenFOAM中求解一个任意阶常微分方程的初值问题,需要做如下准备。<br>考虑一个通用形式的常微分方程<br>$$<br>y^{n}=f(x,y,y’,\cdots,y^{n-1})<br>$$<br>定义<br>$$<br>\begin{align*}<br>y_1 &=y\\<br>y_2 &=y’\\<br>y_j &=y^{\,j-1}, \quad j=1,2,\cdots,n<br>\end{align*}<br>$$<br>如果是求解刚性问题的 ODE 求解器,还需要定义 jacobian 矩阵。<br>令<br>$$<br>\begin{align*}<br>f_1 &=y’=y_2\\<br>f_j &=y’_{j}=y^{\,j+1}, \quad j=1,2,\cdots,n<br>\end{align*}<br>$$<br>则 jacobian 矩阵<br>$$<br>\begin{equation*}<br>J =<br>\begin{bmatrix}<br>\frac{\partial f_1}{\partial y_1} & \frac{\partial f_1}{\partial y_2} &<br>\cdots &\frac{\partial f_1}{\partial y_n}\\<br>\frac{\partial f_2}{\partial y_1} & \frac{\partial f_2}{\partial y_2} &<br>\cdots &\frac{\partial f_2}{\partial y_n}\\<br>\vdots & \vdots & \ddots & \vdots \\<br>\frac{\partial f_n}{\partial y_1} & \cdots & \cdots<br>&\frac{\partial f_n}{\partial y_n}<br>\end{bmatrix}<br>\end{equation*}<br>$$<br>此外,还需要给出 $f_1, f_2,\cdots,f_n$ 对自变量 $x$ 的偏导数,$\frac{\partial f_1}{\partial x}, \frac{\partial f_2}{\partial x},\cdots,\frac{\partial f_n}{\partial x}$。</p>
<p>下面举一个例子来具体说明。以常微分方程<br>$$<br>y’’=2x+2, x\in[0,1] \\<br>y(0) = 0, y’(0)= 0<br>$$<br>为例,需要定义的量为<br>$$<br>\begin{align*}<br>f_1 &=y’=y_2 \\<br>f_2 &= y’_{2} = 2x+2<br>\end{align*}<br>$$</p>
<p>$$<br>\begin{equation*}<br>J=<br>\begin{bmatrix}<br>0 & 1 \\<br>0 & 0<br>\end{bmatrix}<br>\end{equation*}<br>$$</p>
<p>$$<br>\frac{\partial f_1}{\partial x} = 0, \frac{\partial f_2}{\partial x} = 2<br>$$</p>
<p>求解这个常微分方程的代码如下:<br><figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br></pre></td><td class="code"><pre><span class="line">/<span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span></span><br><span class="line">Description</span><br><span class="line"></span><br><span class="line">d2y/dx2 = ax + b, with a=2, b=2.</span><br><span class="line">initial value: y(0) = 0; y'(0) = 0</span><br><span class="line"></span><br><span class="line">analytical solution: y = 1/3<span class="keyword">*</span>x^3 + x^2;</span><br><span class="line"><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span><span class="keyword">*</span>/</span><br><span class="line"></span><br><span class="line"><span class="comment">#include "argList.H"</span></span><br><span class="line"><span class="comment">#include "IOmanip.H"</span></span><br><span class="line"><span class="comment">#include "ODESystem.H"</span></span><br><span class="line"><span class="comment">#include "ODESolver.H"</span></span><br><span class="line"></span><br><span class="line">using namespace Foam;</span><br><span class="line"></span><br><span class="line">·// <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> //</span><br><span class="line"></span><br><span class="line">class myODE2</span><br><span class="line">:</span><br><span class="line"> public ODESystem</span><br><span class="line">{</span><br><span class="line"></span><br><span class="line"> const scalar a_; //parameter</span><br><span class="line"> const scalar b_; //parameter</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">public:</span><br><span class="line"></span><br><span class="line"> myODE2(const scalar& a, const scalar& b)</span><br><span class="line"> :ODESystem(),</span><br><span class="line"> a_(a),</span><br><span class="line"> b_(b)</span><br><span class="line"> {}</span><br><span class="line"></span><br><span class="line"> label nEqns() const // number of equations, equals to the order of ODE</span><br><span class="line"> {</span><br><span class="line"> return 2;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> void derivatives</span><br><span class="line"> (</span><br><span class="line"> const scalar x,</span><br><span class="line"> const scalarField& y,</span><br><span class="line"> scalarField& dydx</span><br><span class="line"> ) const</span><br><span class="line"> {</span><br><span class="line"> dydx[0] = y[1]; //f1</span><br><span class="line"> dydx[1] = a_<span class="keyword">*</span>x + b_; //f2</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> void jacobian // optional</span><br><span class="line"> (</span><br><span class="line"> const scalar x,</span><br><span class="line"> const scalarField& y,</span><br><span class="line"> scalarField& dfdx,</span><br><span class="line"> scalarSquareMatrix& dfdy</span><br><span class="line"> ) const</span><br><span class="line"> {</span><br><span class="line"> dfdx[0] = 0.0; //df1/dx</span><br><span class="line"> dfdx[1] = a_; //df2/dx</span><br><span class="line"></span><br><span class="line"> dfdy[0][0] = 0.0; //df1/dy1</span><br><span class="line"> dfdy[0][1] = 1.0; //df1/dy2</span><br><span class="line"></span><br><span class="line"> dfdy[1][0] = 0.0; //df2/dy1</span><br><span class="line"> dfdy[1][1] = 0.0; //df2/dy2</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">// <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> //</span><br><span class="line">// Main program:</span><br><span class="line"></span><br><span class="line">int main(int argc, char <span class="keyword">*</span>argv[])</span><br><span class="line">{</span><br><span class="line"> argList::validArgs.append(<span class="string">"ODESolver"</span>);</span><br><span class="line"> argList args(argc, argv);</span><br><span class="line"></span><br><span class="line"> const scalar a = 2.0; </span><br><span class="line"> const scalar b = 2.0; </span><br><span class="line"></span><br><span class="line"> const label n = 100; //number of steps</span><br><span class="line"> const scalar endTime = 1.0; //upper bound of the interval</span><br><span class="line"></span><br><span class="line"> // Create the ODE system</span><br><span class="line"> myODE2 ode(a, b);</span><br><span class="line"></span><br><span class="line"> dictionary dict;</span><br><span class="line"> dict.add(<span class="string">"solver"</span>, args[1]);</span><br><span class="line"></span><br><span class="line"> // Create the selected ODE system solver</span><br><span class="line"> autoPtr<span class="variable"><ODESolver></span> odeSolver = ODESolver::New(ode, dict);</span><br><span class="line"></span><br><span class="line"> // Initialise the ODE system fields</span><br><span class="line"> scalar xStart = 0.0; // lower bound of the interval</span><br><span class="line"> scalar dx = endTime/n; //step value</span><br><span class="line"></span><br><span class="line"> scalarField yStart(ode.nEqns());</span><br><span class="line"> yStart[0] = 0.0; // initial value of y</span><br><span class="line"> yStart[1] = 0.0; // initial value of y'</span><br><span class="line"></span><br><span class="line"> scalar dxEst = 0.1;</span><br><span class="line"> scalar xEnd = 0.0;</span><br><span class="line"></span><br><span class="line"> scalarField dyStart(ode.nEqns()); // dyStart[0]=f1, dyStart[1]=f2 ...</span><br><span class="line"></span><br><span class="line"> for(label i =0; i<span class="variable"><n; i++)</span><br><span class="line"> {</span><br><span class="line"> xEnd = xStart + dx;</span><br><span class="line"> ode.derivatives(xStart, yStart, dyStart);</span><br><span class="line"> odeSolver-></span>solve(xStart, xEnd, yStart, dxEst);</span><br><span class="line"> xStart = xEnd;</span><br><span class="line"> Info <span class="variable"><< xStart << " " << yStart[0] << endl; // output (x,y) for each dx.</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return 0;</span><br><span class="line">}</span></span><br></pre></td></tr></table></figure></p>
<p>编译之后,假设你的可执行程序名为 <code>TestODE</code>,则运行<br><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TestODE RKCK45 > <span class="command">log</span></span><br></pre></td></tr></table></figure></p>
<p>就得到了数值解。<br>将数值解与解析解画图如下<br><img src="/image/RKCK45.png" alt=""><br>可见在这里简单例子中,数值解与解析解吻合非常好。<br>同时注意,这个例子,用显式欧拉方法无法得到收敛的解。</p>
<p><strong>参考资料</strong>:</p>
<ol>
<li><a href="http://hassankassem.me/posts/ode/" target="_blank" rel="external">http://hassankassem.me/posts/ode/</a></li>
<li>余德浩 , 汤华中, 微分方程数值解法,科学出版社,2003</li>
</ol>
]]></content>
<summary type="html">
<![CDATA[<p>本篇介绍如何编写一个小程序来调用 OpenFOAM 的 ODE 求解器来求解任意常微分方程的初值问题。 </p>]]>
</summary>
<category term="ODE" scheme="http://xiaopingqiu.github.io/tags/ODE/"/>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/categories/OpenFOAM/"/>
</entry>
<entry>
<title><![CDATA[fixedFluxPressure 边界条件]]></title>
<link href="http://xiaopingqiu.github.io/2016/08/21/fixedFluxPressure/"/>
<id>http://xiaopingqiu.github.io/2016/08/21/fixedFluxPressure/</id>
<published>2016-08-21T06:47:12.000Z</published>
<updated>2016-08-21T07:24:00.688Z</updated>
<content type="html"><![CDATA[<p>本篇说说我对 fixedFluxPressure 边界条件的理解。</p>
<a id="more"></a>
<p>先来看 OpenFOAM-2.2.x 里的<br><figure class="highlight lasso"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">class fixedFluxPressureFvPatchScalarField</span><br><span class="line">:</span><br><span class="line"> <span class="keyword">public</span> fixedGradientFvPatchScalarField</span><br><span class="line">{</span><br><span class="line"> <span class="comment">// Private data</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">//- Name of the predicted flux transporting the field</span></span><br><span class="line"> word phiHbyAName_;</span><br><span class="line"> <span class="comment">//- Name of the flux transporting the field</span></span><br><span class="line"> word phiName_;</span><br><span class="line"> <span class="comment">//- Name of the density field used to normalise the mass flux</span></span><br><span class="line"> <span class="comment">// if neccessary</span></span><br><span class="line"> word rhoName_;</span><br><span class="line"> <span class="comment">//- Name of the pressure diffusivity field</span></span><br><span class="line"> word DpName_;</span><br><span class="line"> <span class="comment">//- Is the pressure adjoint, i.e. has the opposite sign</span></span><br><span class="line"> Switch adjoint_;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"></span><br><span class="line"> <span class="comment">//- Runtime type information</span></span><br><span class="line"> TypeName(<span class="string">"fixedFluxPressure"</span>);</span><br><span class="line"> <span class="attribute">...</span><span class="attribute">...</span></span><br><span class="line"> <span class="attribute">...</span><span class="attribute">...</span></span><br><span class="line"> <span class="comment">//- Update the coefficients associated with the patch field</span></span><br><span class="line"> virtual <span class="literal">void</span> updateCoeffs();</span><br><span class="line"> </span><br><span class="line"> <span class="attribute">...</span><span class="attribute">...</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure></p>
<p>其中 <code>updateCoeffs</code> 函数定义如下:<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">void Foam::fixedFluxPressureFvPatchScalarField::updateCoeffs()</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (updated())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">const</span> surfaceScalarField& phiHbyA =</span><br><span class="line"> <span class="keyword">db</span>().lookupObject<surfaceScalarField>(phiHbyAName_);</span><br><span class="line"> <span class="keyword">const</span> surfaceScalarField& phi =</span><br><span class="line"> <span class="keyword">db</span>().lookupObject<surfaceScalarField>(phiName_);</span><br><span class="line"> fvsPatchField<<span class="keyword">scalar</span>> phiHbyAp =</span><br><span class="line"> patch().patchField<surfaceScalarField, <span class="keyword">scalar</span>>(phiHbyA);</span><br><span class="line"> fvsPatchField<<span class="keyword">scalar</span>> phip =</span><br><span class="line"> patch().patchField<surfaceScalarField, <span class="keyword">scalar</span>>(phi);</span><br><span class="line"> <span class="keyword">const</span> scalarField *DppPtr = NULL;</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">db</span>().foundObject<volScalarField>(DpName_))</span><br><span class="line"> {</span><br><span class="line"> DppPtr =</span><br><span class="line"> &patch().lookupPatchField<volScalarField, <span class="keyword">scalar</span>>(DpName_);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">db</span>().foundObject<surfaceScalarField>(DpName_))</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">const</span> surfaceScalarField& Dp =</span><br><span class="line"> <span class="keyword">db</span>().lookupObject<surfaceScalarField>(DpName_);</span><br><span class="line"> DppPtr =</span><br><span class="line"> &patch().patchField<surfaceScalarField, <span class="keyword">scalar</span>>(Dp);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (adjoint_)</span><br><span class="line"> {</span><br><span class="line"> gradient() = (phip - phiHbyAp)/patch().magSf()/(*DppPtr);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> gradient() = (phiHbyAp - phip)/patch().magSf()/(*DppPtr);</span><br><span class="line"> }</span><br><span class="line"> fixedGradientFvPatchScalarField::updateCoeffs();</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>代码的说明如下:</p>
<p>这个边界条件,继承自 <code>fixedGradientFvPatchScalarField</code>,可见它是一个用于压力场的第二类边界条件。其用如下公式来计算边界上的压力梯度:<br>$$<br>\nabla(p) = \frac{\phi_{H/A} - \phi}{|S_f| D_p}<br>$$</p>
<p>在设置边界条件的时候,可以指定 <code>phiHbyA</code>, <code>phi</code> 和 <code>Dp</code> 对应的场,如果不指定,则三个量对应的默认场名分别是 <code>phiHbyA</code>, <code>phi</code> 和 <code>Dp</code>,这时如果你的程序中找不到这三个场,那就将出错了。</p>
<p>这个边界条件可以这样理解:<br>首先来看单相流的情形,比如 <code>icoFoam</code>,半离散化的动量方程为<br>$$<br>AU=H-\nabla p<br>$$<br>即<br>$$<br>\nabla p = H - AU<br>$$<br>在入口处,理论上当计算收敛后,压力梯度应当是0。但是在构建压力方程<br><figure class="highlight lisp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">fvScalarMatrix pEqn</span><br><span class="line"><span class="list">(</span><br><span class="line"> <span class="keyword">fvm</span>:<span class="keyword">:laplacian</span><span class="list">(<span class="keyword">rAU</span>, p)</span> == fvc:<span class="keyword">:div</span><span class="list">(<span class="keyword">phiHbyA</span>)</span></span><br><span class="line">)</span><span class="comment">;</span></span><br></pre></td></tr></table></figure></p>
<p>的时候,速度 $U$ 还没有经过修正,即这里的 $U$ 是预测值,所以,迭代过程中入口压力梯度不一定为零。将入口压力设置为等于 $H/A-U$,有助于提高计算稳定性。<br>从代码角度看,对压力方程而言,需要设置的是 inlet 边界上的 $(\nabla p)_{\bot} \cdot rAU$,<br>$$<br>(\nabla p)_{\bot} \cdot rAU = (\nabla p)_{\bot}/A_f = \frac{1}{A_f}(\nabla p \cdot \vec{n} \cdot |S_f|) = (H/A) \cdot S_f-U\cdot S_f<br>$$<br>设置的边界条件应为<br>$$<br>\nabla p \cdot \vec{n} = \frac{(H/A) \cdot S_f-U\cdot S_f}{\big |S_f \big| \cdot rAU}<br>$$</p>
<p>但实际上,<code>fixedFluxPressureFvPatchScalarField</code> 主要是用于两相流中,以 <code>twoPhaseEulerFoam</code> 为例,<br>半离散的动量方程为:<br>$$<br>U_{a}=\frac{1}{a_{p,a}}H(U_a)-\frac{\nabla p}{a_{p,a}\rho_a}+\frac{\alpha_b}{ a_{p,a} \rho_a} K U_b +\frac{1}{a_{p,a}} g<br>$$</p>
<p>$$<br>U_{b}=\frac{1}{a_{p,b}}H(U_b)-\frac{\nabla p}{a_{p,b}\rho_b}+\frac{\alpha_a}{ a_{p,b} \rho_b} K U_a +\frac{1}{a_{p,b}} g<br>$$</p>
<p>对 $U_a$ 项两边同时乘以 $\alpha_a$ ,$U_b$ 项两边同时乘以 $\alpha_b$ ,然后合并起来,得到<br>$$<br>\begin{align*}<br>\Big(\frac{\alpha_a}{a_{p,a}\rho_a}+ \frac{\alpha_b}{a_{p,b}\rho_b}\Big)\nabla p & = \alpha_a \Big[\frac{1}{a_{p,a}}H(U_a)+\frac{\alpha_b}{ a_{p,a} \rho_a} K U_b +\frac{1}{a_{p,a}} g\Big] + \alpha_b \Big[ \frac{1}{a_{p,b}}H(U_b)+\frac{\alpha_a}{ a_{p,b} \rho_b} K U_a +\frac{1}{a_{p,b}} g\Big] \\<br>& - (\alpha_a U_a + \alpha_b U_b)<br>\end{align*}<br>$$</p>
<p>转换成界面通量形式,则<br>$$<br>D_p \nabla p \cdot S_f = \alpha_a \cdot phiHbyA1 + \alpha_b \cdot phiHbyA2 - (\alpha_a \cdot phi1 + \alpha_b \cdot phi2) = phiHbyA - phi<br>$$</p>
<p>于是得到压力的边界条件为<br>$$<br>\nabla p \cdot \vec{n} = \frac{phiHbyA - phi}{Dp \cdot \big|S_f\big|}<br>$$<br>这大概就是 <code>fixedFluxPressureFvPatchScalarField</code> 的物理含义吧。</p>
<p>在 OpenFOAM-2.3.x 以后,<code>fixedFluxPressureFvPatchScalarField</code> 做了修改,不需要指定 <code>Dp</code> 等这些量的值,而是在求解器中直接指定压力梯度。<br>比如 <code>twoPhaseEulerFoam</code> 中<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">setSnGrad<fixedFluxPressureFvPatchScalarField></span><br><span class="line"> (</span><br><span class="line"> p.boundaryField(),</span><br><span class="line"> (</span><br><span class="line"> phiHbyA.boundaryField()</span><br><span class="line"> - mrfZones.relative</span><br><span class="line"> (</span><br><span class="line"> alpha1f.boundaryField()</span><br><span class="line"> *(mesh.Sf().boundaryField() & U1.boundaryField())</span><br><span class="line"> + alpha2f.boundaryField()</span><br><span class="line"> *(mesh.Sf().boundaryField() & U2.boundaryField())</span><br><span class="line"> )</span><br><span class="line"> )/(mesh.magSf().boundaryField()*rAUf.boundaryField())</span><br><span class="line"> );</span><br></pre></td></tr></table></figure></p>
<p><code>setSnGrad</code> 这个函数的定义在 <code>fixedFluxPressureFvPatchScalarField</code> 中定义:<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> GradBC></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="keyword">void</span> <span class="title">setSnGrad</span></span><br><span class="line"> <span class="params">(</span><br><span class="line"> volScalarField::GeometricBoundaryField& bf,</span><br><span class="line"> <span class="keyword">const</span> FieldField<fvsPatchField, scalar>& snGrad</span><br><span class="line"> )</span></span><br><span class="line"> </span>{</span><br><span class="line"> forAll(bf, patchi)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (isA<GradBC>(bf[patchi]))</span><br><span class="line"> {</span><br><span class="line"> refCast<GradBC>(bf[patchi]).updateCoeffs(snGrad[patchi]);<span class="comment">// 调用带一个参数的 updateCoeffs 函数</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="comment">// 实际调用的是这个函数,这个函数调用完以后,curTimeIndex_ 将等于当前时间步的标签。</span></span><br><span class="line"><span class="keyword">void</span> Foam::fixedFluxPressureFvPatchScalarField::updateCoeffs</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> scalarField& snGradp</span><br><span class="line">)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (updated())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> curTimeIndex_ = <span class="keyword">this</span>->db().time().timeIndex();</span><br><span class="line"></span><br><span class="line"> gradient() = snGradp;</span><br><span class="line"> fixedGradientFvPatchScalarField::updateCoeffs();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 但是,很多其他地方仍然需要不带参数的 updateCoeffs 函数接口。</span></span><br><span class="line"><span class="comment">// 这个函数将不起实质作用,但是,如果在调用这个无参的 updateCoeffs 函数之前,没有先调用带一个参数的 updateCoeffs 函数,</span></span><br><span class="line"><span class="comment">// curTimeIndex_ 也没有更新到当前的时间步标签,那就报错,表明不适合使用这个边界条件。</span></span><br><span class="line"><span class="keyword">void</span> Foam::fixedFluxPressureFvPatchScalarField::updateCoeffs()</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (updated())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (curTimeIndex_ != <span class="keyword">this</span>->db().time().timeIndex())</span><br><span class="line"> {</span><br><span class="line"> FatalErrorIn(<span class="string">"fixedFluxPressureFvPatchScalarField::updateCoeffs()"</span>)</span><br><span class="line"> << <span class="string">"updateCoeffs(const scalarField& snGradp) MUST be called before"</span></span><br><span class="line"> <span class="string">" updateCoeffs() or evaluate() to set the boundary gradient."</span></span><br><span class="line"> << <span class="built_in">exit</span>(FatalError);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>因此,显然,从 2.3 开始,只有在求解器中显式地调用带一个参数的 updateCoeffs 函数来指定 p 的边界条件时,该求解器的算例才能使用 <code>fixedFluxPressure</code> 这个边界条件。 </p>
]]></content>
<summary type="html">
<![CDATA[<p>本篇说说我对 fixedFluxPressure 边界条件的理解。</p>]]>
</summary>
<category term="Boundary conditions" scheme="http://xiaopingqiu.github.io/tags/Boundary-conditions/"/>
<category term="Code Explained" scheme="http://xiaopingqiu.github.io/tags/Code-Explained/"/>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/categories/OpenFOAM/"/>
</entry>
<entry>
<title><![CDATA[OpenFOAM 中用手动并行分块的方法]]></title>
<link href="http://xiaopingqiu.github.io/2016/08/21/ManualDecomposition/"/>
<id>http://xiaopingqiu.github.io/2016/08/21/ManualDecomposition/</id>
<published>2016-08-21T06:34:46.000Z</published>
<updated>2016-08-21T06:45:29.922Z</updated>
<content type="html"><![CDATA[<p>OpenFOAM 提供了许多并行区域划分的方法,常用的有 simple,scotch 等。但是,有时候希望能手动地将指定区域指派给一个进程,幸运的是 OpenFOAM 提供了这样的功能。本篇就来介绍一下如何进行手动并行分块。</p>
<a id="more"></a>
<p>以自带的 dambreak 算例为例,首先,将分块方法设置为 simple,<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">numberOfSubdomains <span class="number">4</span>;</span><br><span class="line"></span><br><span class="line">method simple;</span><br><span class="line"></span><br><span class="line">simpleCoeffs</span><br><span class="line">{</span><br><span class="line"> n ( <span class="number">2</span> <span class="number">2</span> <span class="number">1</span> );</span><br><span class="line"> delta <span class="number">0.001</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>然后,运行<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">decomposePar -cellDist</span><br></pre></td></tr></table></figure></p>
<p>于是便在 0 下面得到一个 <code>volScalarField</code>:<code>cellDist</code>。<br><figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">FoamFile</span><br><span class="line">{</span><br><span class="line"> version 2.0;</span><br><span class="line"> format ascii;</span><br><span class="line"> class volScalarField;</span><br><span class="line"> location <span class="string">"0"</span>;</span><br><span class="line"> object cellDist;</span><br><span class="line">}</span><br><span class="line">// <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> //</span><br><span class="line"></span><br><span class="line">dimensions [0 0 0 0 0 0 0];</span><br><span class="line"></span><br><span class="line">internalField nonuniform List<span class="variable"><scalar></span> </span><br><span class="line">2268</span><br><span class="line">(</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">0</span><br><span class="line">0</span><br><span class="line">0</span><br><span class="line">0</span><br><span class="line">...</span><br><span class="line">);</span><br><span class="line">boundaryField</span><br><span class="line">{</span><br><span class="line"> ......</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>注意,上面可以看到, <code>cellDist</code> 的值是 1 和 0 等,这个值,对应着将来该网格将被分配到的 processor 的id。</p>
<p>所以,如果将 <code>cellDist</code> 当成是一个标量场,然后用设置初始场的工具对其值进行初始化,将来就能将对应网格手动分配到 <code>cellDist</code> 的值对应的进程。</p>
<p>OpenFOAM 自带的设置初始场的工具是 <code>setFields</code> , <code>swak4Foam</code> 中的 <code>funkySetField</code> 也是可以的。这里介绍 <code>setFields</code> 的用法。</p>
<p>使用 <code>setFields</code> ,需要编写 <code>setFieldsDict</code>,示例如下<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">defaultFieldValues</span><br><span class="line">(</span><br><span class="line"> volScalarFieldValue cellDist <span class="number">0</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">regions</span><br><span class="line">(</span><br><span class="line"> boxToCell</span><br><span class="line"> {</span><br><span class="line"> box (<span class="number">0</span> <span class="number">0</span> -<span class="number">1</span>) (<span class="number">0.2</span> <span class="number">0.2</span> <span class="number">1</span>);</span><br><span class="line"> fieldValues</span><br><span class="line"> (</span><br><span class="line"> volScalarFieldValue cellDist <span class="number">1</span></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line"> boxToCell</span><br><span class="line"> {</span><br><span class="line"> box (<span class="number">0</span> <span class="number">0.2</span> -<span class="number">1</span>) (<span class="number">0.2</span> <span class="number">0.6</span> <span class="number">1</span>);</span><br><span class="line"> fieldValues</span><br><span class="line"> (</span><br><span class="line"> volScalarFieldValue cellDist <span class="number">2</span></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line"> boxToCell</span><br><span class="line"> {</span><br><span class="line"> box (<span class="number">0.2</span> <span class="number">0.2</span> -<span class="number">1</span>) (<span class="number">0.6</span> <span class="number">0.6</span> <span class="number">1</span>);</span><br><span class="line"> fieldValues</span><br><span class="line"> (</span><br><span class="line"> volScalarFieldValue cellDist <span class="number">3</span></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">);</span><br></pre></td></tr></table></figure></p>
<p>这里,用的是最简单的 <code>boxToCell</code>,即指定一个 box 中的网格的 <code>cellDist</code> 值。 <code>setFields</code> 还有很多种方式来设置初始值。这里再举一个例子,可以先用 <code>topoSet</code> 来将指定区域的网格先提取到 <code>cellSet</code> ,然后,对整个 <code>cellSet</code> 的网格的 <code>cellDist</code> 值进行指定,示例如下:<br><figure class="highlight lisp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">defaultFieldValues <span class="list">( <span class="keyword">volScalarFieldValue</span> cellDist <span class="number">0</span> )</span><span class="comment">;</span></span><br><span class="line"></span><br><span class="line">regions </span><br><span class="line"><span class="list">(</span><br><span class="line"> <span class="keyword">cellToCell</span></span><br><span class="line"> {</span><br><span class="line"> set cellSet1 <span class="comment">; </span></span><br><span class="line"> fieldValues</span><br><span class="line"> <span class="list">( </span><br><span class="line"> <span class="keyword">volScalarFieldValue</span> cellDist <span class="number">1</span></span><br><span class="line"> )</span><span class="comment">;</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> cellToCell1</span><br><span class="line"> {</span><br><span class="line"> set cellSet2 <span class="comment">; </span></span><br><span class="line"> fieldValues</span><br><span class="line"> <span class="list">( </span><br><span class="line"> <span class="keyword">volScalarFieldValue</span> cellDist <span class="number">2</span></span><br><span class="line"> )</span><span class="comment">;</span></span><br><span class="line"> }</span><br><span class="line">)</span><span class="comment">;</span></span><br></pre></td></tr></table></figure></p>
<p><code>topoSet</code> 的用法这里不举例了,有很多花样,详细的信息可以参考 <code>applications/utilities/mesh/manipulation/topoSet/topoSetDict</code> 中的说明。</p>
<p>设置好 <code>setFieldDict</code>以后,运行 <code>setFields</code>,便对 <code>cellDist</code> 的值进行了修改,可视化如下</p>
<p><img src="/image/cellDistValue.png" alt=""></p>
<p>下一步,需要根据 <code>cellDist</code> 的值来创建一个 <code>labelList</code>,因为手动分块的时候,需要的是一个 <code>labelList</code> 。<br>在constant下创建一个文件, <code>cellDecomposition</code> ,内容如下<br><figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line">FoamFile</span><br><span class="line">{</span><br><span class="line"> version 2.0;</span><br><span class="line"> format ascii;</span><br><span class="line"> class labelList;</span><br><span class="line"> location <span class="string">"constant"</span>;</span><br><span class="line"> object cellDecomposition;</span><br><span class="line">}</span><br><span class="line">// <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> <span class="keyword">*</span> //</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">2268</span><br><span class="line">(</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">0</span><br><span class="line">0</span><br><span class="line">0</span><br><span class="line">0</span><br><span class="line">0</span><br><span class="line">0</span><br><span class="line">0</span><br><span class="line">1</span><br><span class="line">1</span><br><span class="line">......</span><br><span class="line">)</span><br></pre></td></tr></table></figure></p>
<p>注意文件头的写法。 <code>()</code> 内的内容与 <code>cellDist</code> 文件中 <code>()</code> 内的内容一样。</p>
<p>再下一步,就是修改 <code>decomposeParDict</code><br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">numberOfSubdomains <span class="number">4</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">method</span> manual;</span><br><span class="line"></span><br><span class="line">manualCoeffs</span><br><span class="line">{</span><br><span class="line"> dataFile <span class="string">"cellDecomposition"</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>然后再运行 <code>decomposePar -force</code>,这样就得到了根据 <code>cellDist</code> 值来指定的分块方式,如下</p>
<p><img src="/image/decomposition.png" alt=""></p>
<p>注意看这里的进程边界,跟上图中 <code>cellDist</code> 的值的边界是一样的。</p>
]]></content>
<summary type="html">
<![CDATA[<p>OpenFOAM 提供了许多并行区域划分的方法,常用的有 simple,scotch 等。但是,有时候希望能手动地将指定区域指派给一个进程,幸运的是 OpenFOAM 提供了这样的功能。本篇就来介绍一下如何进行手动并行分块。</p>]]>
</summary>
<category term="Preprocessing" scheme="http://xiaopingqiu.github.io/tags/Preprocessing/"/>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/categories/OpenFOAM/"/>
</entry>
<entry>
<title><![CDATA[LES 中的 commutation error]]></title>
<link href="http://xiaopingqiu.github.io/2016/08/21/commutationError/"/>
<id>http://xiaopingqiu.github.io/2016/08/21/commutationError/</id>
<published>2016-08-21T03:27:48.000Z</published>
<updated>2016-08-21T06:27:37.355Z</updated>
<content type="html"><![CDATA[<p>大涡模拟不仅对网格的解析度有要求,而且对网格质量也有更高的要求。本文介绍一种由网格带来的误差,commutation error,并简单分析其对结果的影响。</p>
<a id="more"></a>
<p>在 LES 模拟的程序中,常用的一种过滤方法是隐式过滤,即,用当地网格的尺度作为该处的过滤尺度。这种方法在各种类型的网格上实现起来都相对简单。只是,稍微复杂一点的几何构体,生成的网格的尺度总是不可能一样,这也就意味着过滤尺度是变化的。如果相邻网格的尺度变化很大,这也将引起相邻网格的过滤尺度相差很大,这时就会带来严重的 commutation error。</p>
<p>Commutation error 产生的根本原因是,当相邻网格过滤尺度不一样时,,$\overline{\tfrac{\partial \phi}{\partial x}} \neq \tfrac{\partial \overline{\phi}}{\partial x}$。下面举一个例子来说明:<br>假设有一个场量,解析值为<br>$$<br>\phi = 1-x^2<br>$$<br>其导数为<br>$$<br>\frac{\partial \phi}{\partial x} = -2x<br>$$<br>在一个如下图的网格中来进行过滤</p>
<p><img src="/image/LES/filterGrid.png" alt=""></p>
<p>第一次,我们对点 $P$ 和 $N_1$ 处进行过滤,过滤直径都是 $\Delta_1 = 1$,使用 top hat 过滤函数,即</p>
<p>$$<br>G(x,\Delta)=<br>\begin{cases}<br>\frac{1}{\Delta} & if(|x’\le\frac{\Delta}{2}|) \\<br>0 & otherwise<br>\end{cases}<br>$$</p>
<p>则<br>$$<br>\overline{\phi}_P = \oint G(x,x\prime;\Delta)\,f(x\prime) dx\prime = \int _{-\infty} ^{-1} 0\cdot \phi(x\prime) dx\prime + \int_{-1}^{0} \frac{1}{\Delta_1} \cdot \phi(x\prime)dx\prime + \int _{0} ^{\infty} 0\cdot \phi(x\prime) dx\prime = \frac{2}{3}<br>$$<br>类似地,<br>$$<br>\overline{\phi}_{N_1} = \int_0^1 \frac{1}{\Delta_1} \cdot \phi(x\prime) dx\prime = \frac{2}{3}<br>$$</p>
<p>另一方面,对梯度使用过滤,得<br>$$<br>\Bigg(\overline{\frac{\partial \phi}{\partial x}} \Bigg)_0= \int_{-0.5}^{0.5} \frac{1}{\Delta_1}\cdot(-2x)dx = 0<br>$$<br>而<br>$$<br>\frac{\partial \overline{\phi}}{\partial x} = \frac{\overline{\phi}_{N1}-\overline{\phi}_P}{x_{N1}-x_{P}} = 0<br>$$</p>
<p>这说明,当相邻网格的过滤尺度一致时,commutation error 为零。但是,当过滤尺度不一致时,考虑右边的网格中心为 $N_2$ 的情形,此时<br>$$<br>\overline{\phi}_{N2} = \int_{0}^{0.5} \frac{1}{\Delta_2} \cdot \phi dx = \frac{11}{12}<br>$$</p>
<p>$$<br>\frac{\partial \overline{\phi}}{\partial x} = \frac{\overline{\phi}_{N2}-\overline{\phi}_P}{x_{N2}-x_{P}} = \frac{1}{6} \neq 0<br>$$<br>这时就产生了 commutation error。</p>
<p>所以,网格尺度不均匀现象严重的区域就会出现显著的 commutation error。边界层是容易出现网格尺度不一致的区域,在壁面上,严格来说,过滤尺度必须是零,否则将破坏无滑移条件。这种情况还可以通过 DES 这样的方法来处理。但是,核心区也可能出现相邻网格不一致的情形。局部网格加密是一种实用的节省计算量的方法,这种方法只需要在重要区域进行加密,不必全局加密。但是局部加密就导致了相邻网格尺度不一致,由此就带来了显著的 commutation error。所以,使用局部加密时,要注意<strong>不要让相邻两种等级的网格的边界落在重要区域</strong>。</p>
<p>局部加密效应可以从下图看出</p>
<p><img src="/image/LES/localRefinement.png" alt=""></p>
<p>当从细网格向粗网格过渡时,会出现亚格子粘度的突降;当从粗网格过渡到细网格时,亚格子粘度会突然上升。有一种办法是对过滤尺度进行光滑处理:</p>
<p>$$<br>\Delta P=max(\Delta P, \Delta N/C_{\Delta s})<br>$$</p>
<p><img src="/image/LES/smoothedDelta.png" alt=""></p>
<p>$C_{\Delta s}$ 的取值约为 1.5。</p>
<p>用这种方法可让局部加密带来的问题得到部分缓解。亚格子粘度在粗细网格交接附近的过渡也更光滑。</p>
<p><img src="/image/LES/smoothedViscosity.png" alt=""></p>
<p>误差总是无可避免的,降低误差的技术也有很多。从“计算性价比”(即为了得到一定准确度的结果所耗费的计算量) 的角度看,没有哪个结果就一定是严格地错误或者正确,只是“计算性价比”不同。有时候为了降低计算量,在一些区域即便产生了严重的误差,也是可以接受的。关键是要对误差差生的原因有清楚的认识,尽量不要让很大的误差出现在重要的区域。</p>
<p>本篇的图,文,公式,完全取材整理自 Eugene de Villiers 的博士论文 “The Potential of Large Eddy Simulation for the Modeling of Wall Bounded Flows”,特此声明。</p>
]]></content>
<summary type="html">
<![CDATA[<p>大涡模拟不仅对网格的解析度有要求,而且对网格质量也有更高的要求。本文介绍一种由网格带来的误差,commutation error,并简单分析其对结果的影响。</p>]]>
</summary>
<category term="LES" scheme="http://xiaopingqiu.github.io/tags/LES/"/>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/categories/OpenFOAM/"/>
</entry>
<entry>
<title><![CDATA[OpenFOAM 中的热物理类之添加新模型]]></title>
<link href="http://xiaopingqiu.github.io/2016/06/25/thermophysics5/"/>
<id>http://xiaopingqiu.github.io/2016/06/25/thermophysics5/</id>
<published>2016-06-25T13:27:55.000Z</published>
<updated>2016-06-25T13:30:51.827Z</updated>
<content type="html"><![CDATA[<p>本篇探讨如何增加一个新的热物理模型。</p>
<a id="more"></a>
<p>有了前面的基础,增加一个模型应该不在话下了,这里给出一个例子。<br>关键在调用 <code>makeThermo</code> 宏函数,来将各个子模型组合起来,形成一个新的热物理模型,并添加到合适的 hashTable 里。</p>
<p>这里只看看怎么来增加状态方程模型,transport 模型(描述黏度 随温度的变化),thermo 模型(描述 cp 随温度的变化),energy 模型。将 <code>perfectGas</code>, <code>constTransport</code>, <code>hConstThermo</code>,以及 <code>sensibleInternalEnergy</code> 拷贝出来到一个目录下,并分别重命名为 <code>my+原始模型名</code> 的形式。同时,修改各个模型的typeName,比如, <code>perfectGas</code> 修改为 <code>myperfectGas</code>, <code>myperfectGas.H</code> 的 <code>typeName</code> 修改为:<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> word <span class="title">typeName</span><span class="params">()</span></span><br><span class="line"></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"myperfectGas<"</span> + word(Specie::typeName_()) + <span class="string">'>'</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>注意,这里 <code>typeName</code> 一定要改,否则,将在运行算例的时候,出现 <code>duplicate entry</code> 的错误,根本原因在于,将模型添加到 hashTable 的时候,hashTable 的 key 是由 <code>typeName</code> 组合而成的,如果新模型使用了跟旧模型一样的 <code>typeName</code> 就可能会在 hashTable 出现两个一个一样的 key,即 <code>duplicate entry</code>。</p>
<p>然后,将 <code>src/thermophysicalModels/basic/rhoThermo</code> 目录下的 <code>rhoThermos.C</code> 拷贝到新模型所在目录下,并修改为:<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "rhoThermo.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "makeThermo.H"</span></span><br><span class="line"></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "specie.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "perfectGas.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "myperfectGas.H" <span class="comment">// 新加的</span></span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "incompressiblePerfectGas.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "rhoConst.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "perfectFluid.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "PengRobinsonGas.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "adiabaticPerfectFluid.H"</span></span><br><span class="line"></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "hConstThermo.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "myhConstThermo.H" <span class="comment">// 新加的</span></span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "janafThermo.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "sensibleEnthalpy.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "sensibleInternalEnergy.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "mysensibleInternalEnergy.H" <span class="comment">// 新加的</span></span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "thermo.H"</span></span><br><span class="line"></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "constTransport.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "myconstTransport.H" <span class="comment">// 新加的</span></span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "sutherlandTransport.H"</span></span><br><span class="line"></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "icoPolynomial.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "hPolynomialThermo.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "polynomialTransport.H"</span></span><br><span class="line"></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "heRhoThermo.H"</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> "pureMixture.H"</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> Foam</span><br><span class="line">{</span><br><span class="line"></span><br><span class="line">makeThermo</span><br><span class="line">(</span><br><span class="line"> rhoThermo,</span><br><span class="line"> heRhoThermo,</span><br><span class="line"> pureMixture,</span><br><span class="line"> myconstTransport,</span><br><span class="line"> mysensibleInternalEnergy,</span><br><span class="line"> myhConstThermo,</span><br><span class="line"> myperfectGas,</span><br><span class="line"> specie</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">} <span class="comment">// End namespace Foam</span></span><br></pre></td></tr></table></figure></p>
<p>注意,头文件里有四个是新加的。 <code>makeThermo</code> 宏只调用了一次,即这里只增加了一个模型。其他的组合当然也是可以的,比如像这样<br><figure class="highlight lisp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">makeThermo</span><br><span class="line"><span class="list">(</span><br><span class="line"> <span class="keyword">rhoThermo</span>,</span><br><span class="line"> heRhoThermo,</span><br><span class="line"> pureMixture,</span><br><span class="line"> constTransport,</span><br><span class="line"> sensibleInternalEnergy,</span><br><span class="line"> hConstThermo,</span><br><span class="line"> myperfectGas,</span><br><span class="line"> specie</span><br><span class="line">)</span><span class="comment">;</span></span><br></pre></td></tr></table></figure></p>
<p>灵活组合就好了。</p>
<p>最后,将 <code>src/thermophysicalModels/basic</code> 目录下的 <code>Make</code> 拷贝到新模型所在目录下。并将 <code>files</code> 和 <code>options</code> 如下:</p>
<ul>
<li><p>files</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">rhoThermos.C</span><br><span class="line"></span><br><span class="line"><span class="constant">LIB</span> = <span class="variable">$(FOAM_USER_LIBBIN)</span>/libMyTestfluidThermophysicalModels</span><br></pre></td></tr></table></figure>
</li>
<li><p>options</p>
<figure class="highlight haml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">EXE_INC = \</span><br><span class="line"> -<span class="ruby"><span class="constant">I</span><span class="variable">$(</span><span class="constant">LIB_SRC</span>)/finiteVolume/lnInclude \</span><br><span class="line"></span> -<span class="ruby"><span class="constant">I</span><span class="variable">$(</span><span class="constant">LIB_SRC</span>)/thermophysicalModels/specie/lnInclude \</span><br><span class="line"></span> -<span class="ruby"><span class="constant">I</span><span class="variable">$(</span><span class="constant">LIB_SRC</span>)/thermophysicalModels/basic/lnInclude \</span><br><span class="line"></span> -<span class="ruby"><span class="constant">I</span><span class="variable">$(</span><span class="constant">LIB_SRC</span>)/meshTools/lnInclude </span><br><span class="line"></span></span><br><span class="line"></span><br><span class="line">LIB_LIBS = \</span><br><span class="line"> -<span class="ruby">lfiniteVolume \</span><br><span class="line"></span> -<span class="ruby">lspecie \</span><br><span class="line"></span> -<span class="ruby">lfluidThermophysicalModels</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>注意,这里也作了修改, <code>EXE_INC</code> 里增加了 <code>-I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \</code> ; <code>LIB_LIBS</code> 里增加了两条: <code>-lspecie</code> 和 <code>-lfluidThermophysicalModels</code> 。</p>
<p>有了这些,就万事具备了,下面给出一个目录树:<br><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">├── const</span><br><span class="line">│ ├── myconstTransport<span class="class">.C</span></span><br><span class="line">│ ├── myconstTransport<span class="class">.H</span></span><br><span class="line">│ └── myconstTransportI<span class="class">.H</span></span><br><span class="line">├── hConst</span><br><span class="line">│ ├── myhConstThermo<span class="class">.C</span></span><br><span class="line">│ ├── myhConstThermo<span class="class">.H</span></span><br><span class="line">│ └── myhConstThermoI<span class="class">.H</span></span><br><span class="line">├── Make</span><br><span class="line">│ ├── files</span><br><span class="line">│ └── options</span><br><span class="line">├── perfectGas</span><br><span class="line">│ ├── myperfectGas<span class="class">.C</span></span><br><span class="line">│ ├── myperfectGas<span class="class">.H</span></span><br><span class="line">│ └── myperfectGasI<span class="class">.H</span></span><br><span class="line">├── rhoThermos<span class="class">.C</span></span><br><span class="line">└── sensibleInternalEnergy</span><br><span class="line"> └── mysensibleInternalEnergy.H</span><br></pre></td></tr></table></figure></p>
<p>运行 <code>wmake libso</code>,就能编译得到一个新的库了。</p>
<p>那么怎么调用新增的模型呢?分两步:</p>
<ol>
<li>修改 controlDict,增加一条 <code>libs ( "libMyTestfluidThermophysicalModels.so" );</code> </li>
<li>修改 <code>constant/thermophysicalProperties</code>,改为如下<figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="title">thermoType</span></span><br><span class="line">{</span><br><span class="line"> <span class="title">type</span> heRhoThermo;</span><br><span class="line"> <span class="title">mixture</span> pureMixture;</span><br><span class="line"> <span class="title">transport</span> myconst;</span><br><span class="line"> <span class="title">thermo</span> myhConst;</span><br><span class="line"> <span class="title">equationOfState</span> myperfectGas;</span><br><span class="line"> <span class="title">specie</span> specie;</span><br><span class="line"> <span class="title">energy</span> mysensibleInternalEnergy;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="title">pRef</span> <span class="number">100000</span>;</span><br><span class="line"></span><br><span class="line"><span class="title">mixture</span></span><br><span class="line">{</span><br><span class="line"> <span class="title">specie</span></span><br><span class="line"> {</span><br><span class="line"> <span class="title">nMoles</span> <span class="number">1</span>;</span><br><span class="line"> <span class="title">molWeight</span> <span class="number">28</span>.<span class="number">9</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="title">thermodynamics</span></span><br><span class="line"> {</span><br><span class="line"> <span class="title">Cp</span> <span class="number">1000</span>;</span><br><span class="line"> <span class="title">Hf</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="title">transport</span></span><br><span class="line"> {</span><br><span class="line"> <span class="title">mu</span> <span class="number">1</span>.8e-<span class="number">05</span>;</span><br><span class="line"> <span class="title">Pr</span> <span class="number">0</span>.<span class="number">7</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>这样改好以后,新模型就会被调用了。当运行求解器的时候出现如下内容,<br><figure class="highlight asciidoc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="code">......</span><br><span class="line">......</span><br><span class="line">Reading thermophysical properties</span><br><span class="line"></span><br><span class="line">Selecting thermodynamics package </span><br><span class="line">{</span><br><span class="line"> type heRhoThermo;</span><br><span class="line"> mixture pureMixture;</span><br><span class="line"> transport myconst;</span><br><span class="line"> thermo myhConst;</span><br><span class="line"> equationOfState myperfectGas;</span><br><span class="line"> specie specie;</span><br><span class="line"> energy mysensibleInternalEnergy;</span><br><span class="line">}</span><br><span class="line">.......</span></span><br><span class="line">.......</span><br></pre></td></tr></table></figure></p>
<p>就表示新模型调用成功了。</p>
<p>最后提醒一下,这里的测试,只是将原有模型原封不动地拷贝出来了,只是改了 <code>tpeName</code>。实际应用场景肯定会比这个复杂,这里只是给出一个最基本的流程来供大家参考。</p>
]]></content>
<summary type="html">
<![CDATA[<p>本篇探讨如何增加一个新的热物理模型。</p>]]>
</summary>
<category term="Code Explained" scheme="http://xiaopingqiu.github.io/tags/Code-Explained/"/>
<category term="thermophysicalModels" scheme="http://xiaopingqiu.github.io/tags/thermophysicalModels/"/>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/categories/OpenFOAM/"/>
</entry>
<entry>
<title><![CDATA[一个具体能量方程的解析]]></title>
<link href="http://xiaopingqiu.github.io/2016/06/25/thermophysics4/"/>
<id>http://xiaopingqiu.github.io/2016/06/25/thermophysics4/</id>
<published>2016-06-25T07:48:02.000Z</published>
<updated>2016-06-25T08:03:40.062Z</updated>
<content type="html"><![CDATA[<p>本篇来看一个具体的能量方程,以 <code>twoPhaseEulerFoam</code> 的 <code>EEqn.H</code> 为例。</p>
<a id="more"></a>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> volScalarField& he1 = thermo1.he();</span><br><span class="line"> volScalarField& he2 = thermo2.he();</span><br><span class="line"></span><br><span class="line"> <span class="function">volScalarField <span class="title">Cpv1</span><span class="params">("Cpv1", thermo1.Cpv()</span>)</span>;</span><br><span class="line"> <span class="function">volScalarField <span class="title">Cpv2</span><span class="params">("Cpv2", thermo2.Cpv()</span>)</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function">volScalarField <span class="title">heatTransferCoeff</span><span class="params">(fluid.heatTransferCoeff()</span>)</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function">fvScalarMatrix <span class="title">he1Eqn</span></span><br><span class="line"> <span class="params">(</span><br><span class="line"> fvm::ddt(alpha1, rho1, he1)</span> + fvm::<span class="title">div</span><span class="params">(alphaRhoPhi1, he1)</span></span><br><span class="line"> - fvm::<span class="title">Sp</span><span class="params">(contErr1, he1)</span></span><br><span class="line"></span><br><span class="line"> + fvc::<span class="title">ddt</span><span class="params">(alpha1, rho1, K1)</span> + fvc::<span class="title">div</span><span class="params">(alphaRhoPhi1, K1)</span></span><br><span class="line"> - contErr1*K1</span><br><span class="line"> + <span class="params">(</span><br><span class="line"> he1.name()</span> </span>== thermo1.phasePropertyName(<span class="string">"e"</span>)</span><br><span class="line"> ? fvc::ddt(alpha1)*p + fvc::div(alphaPhi1, p)</span><br><span class="line"> : -alpha1*dpdt</span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line"> - fvm::laplacian</span><br><span class="line"> (</span><br><span class="line"> fvc::interpolate(alpha1)</span><br><span class="line"> *fvc::interpolate(thermo1.alphaEff(phase1.turbulence().mut())),</span><br><span class="line"> he1</span><br><span class="line"> )</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> he1Eqn.relax();</span><br><span class="line"></span><br><span class="line"> he1Eqn -=</span><br><span class="line"> (</span><br><span class="line"> heatTransferCoeff*(thermo2.T() - thermo1.T())</span><br><span class="line"> + heatTransferCoeff*he1/Cpv1</span><br><span class="line"> - fvm::Sp(heatTransferCoeff/Cpv1, he1)</span><br><span class="line"> + fvOptions(alpha1, rho1, he1)</span><br><span class="line"> );</span><br></pre></td></tr></table></figure>
<p>对应的能量方程为(忽略fvOptions)<br>$$<br>\alpha \rho \frac{\partial (\mathrm{he})}{\partial t} + \alpha \rho U\cdot \nabla(\mathrm{he}) + \alpha \rho \frac{\partial (\mathrm{K})}{\partial t} + \alpha \rho U\cdot \nabla\mathrm{K} + \\<br>\begin{cases}<br>p\cdot\dfrac{\partial \alpha}{\partial t} + \nabla \cdot (\alpha U p) , & \mbox{ if } he.name == \mbox{“e”} \\<br>-\alpha \dfrac{\partial p}{\partial t}, & \mbox{ if } he.name == \mbox{“h”}<br>\end{cases} \\<br>-\nabla \cdot \big(\alpha \cdot \alpha_{eff} \nabla (\mathrm{he}) \big) - \gamma(T_2 - T_1) = 0<br>$$</p>
<p>代码里剩下的两项,<br><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">+ heatTransferCoeff*he1/Cpv1</span><br><span class="line">- fvm::<span class="function"><span class="title">Sp</span><span class="params">(heatTransferCoeff/Cpv1, he1)</span></span></span><br></pre></td></tr></table></figure></p>
<p>含义暂不明。这两项,其实是同一个公式,只是前者是显示处理,后者用了隐式源项,估计是为了数值稳定性的目的而构建的。</p>
<p>前面提过,对于如下设置,<br><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="title">thermoType</span></span><br><span class="line">{</span><br><span class="line"> <span class="title">type</span> heRhoThermo;</span><br><span class="line"> <span class="title">mixture</span> pureMixture;</span><br><span class="line"> <span class="title">transport</span> const;</span><br><span class="line"> <span class="title">thermo</span> hConst;</span><br><span class="line"> <span class="title">equationOfState</span> perfectGas;</span><br><span class="line"> <span class="title">specie</span> specie;</span><br><span class="line"> <span class="title">energy</span> sensibleInternalEnergy;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>最终,<code>thermo</code> 指针指向的是 <code>heRhoThermo</code> 类的对象,所以,从 <code>heRhoThermo</code> 类的构造函数看起:<br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class <span class="type">BasicPsiThermo</span>, class <span class="type">MixtureType</span>></span><br><span class="line"><span class="type">Foam</span>::heRhoThermo<<span class="type">BasicPsiThermo</span>, <span class="type">MixtureType</span>>::heRhoThermo</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> fvMesh& mesh,</span><br><span class="line"> <span class="keyword">const</span> word& phaseName</span><br><span class="line">)</span><br><span class="line">:</span><br><span class="line"> heThermo<<span class="type">BasicPsiThermo</span>, <span class="type">MixtureType</span>>(mesh, phaseName)</span><br><span class="line">{</span><br><span class="line"> calculate(); // 构造函数调用 calculate 函数来初始化所有的热物理相关量</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>可见,构造函数里调用了 <code>calculate</code> 函数,前面提过,这个函数的作用是更新各个热物理相关量。</p>
<p>接下来一个一个来看里面涉及到的函数。</p>
<h5 id="he"><code>he</code></h5><p><code>he</code> 其实是 “h or e”,具体是焓,还是内能,取决于 <code>energy</code> 这一项的设置。 <code>he</code> 函数在 <code>heThermo</code> 类中定义,返回的是数据成员 <code>he_</code>,所以这里需要看一下数据成员 <code>he_</code> 的初始化:<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> BasicThermo, <span class="keyword">class</span> MixtureType></span><br><span class="line">Foam::heThermo<BasicThermo, MixtureType>::heThermo</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> fvMesh& mesh,</span><br><span class="line"> <span class="keyword">const</span> dictionary& dict,</span><br><span class="line"> <span class="keyword">const</span> word& phaseName</span><br><span class="line">)</span><br><span class="line">:</span><br><span class="line"> BasicThermo(mesh, dict, phaseName),</span><br><span class="line"> MixtureType(*<span class="keyword">this</span>, mesh),</span><br><span class="line"></span><br><span class="line"> he_</span><br><span class="line"> (</span><br><span class="line"> IOobject</span><br><span class="line"> (</span><br><span class="line"> BasicThermo::phasePropertyName</span><br><span class="line"> (</span><br><span class="line"> MixtureType::thermoType::heName()</span><br><span class="line"> ),</span><br><span class="line"> mesh.time().timeName(),</span><br><span class="line"> mesh,</span><br><span class="line"> IOobject::NO_READ,</span><br><span class="line"> IOobject::NO_WRITE</span><br><span class="line"> ),</span><br><span class="line"> mesh,</span><br><span class="line"> dimEnergy/dimMass,</span><br><span class="line"> <span class="keyword">this</span>->heBoundaryTypes(),</span><br><span class="line"> <span class="keyword">this</span>->heBoundaryBaseTypes()</span><br><span class="line"> )</span><br><span class="line">{</span><br><span class="line"> init();</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这里调用的 <code>init</code> 函数的内容为<br><figure class="highlight ocaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">template<<span class="keyword">class</span> <span class="type">BasicThermo</span>, <span class="keyword">class</span> <span class="type">MixtureType</span>></span><br><span class="line">void <span class="type">Foam</span>::heThermo<<span class="type">BasicThermo</span>, <span class="type">MixtureType</span>>::init<span class="literal">()</span></span><br><span class="line">{</span><br><span class="line"> scalarField& heCells = he_.internalField<span class="literal">()</span>;</span><br><span class="line"> const scalarField& pCells = this->p_.internalField<span class="literal">()</span>;</span><br><span class="line"> const scalarField& <span class="type">TCells</span> = this-><span class="type">T_</span>.internalField<span class="literal">()</span>;</span><br><span class="line"></span><br><span class="line"> forAll(heCells, celli)</span><br><span class="line"> {</span><br><span class="line"> heCells[celli] =</span><br><span class="line"> this->cellMixture(celli).<span class="type">HE</span>(pCells[celli], <span class="type">TCells</span>[celli]);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> forAll(he_.boundaryField<span class="literal">()</span>, patchi)</span><br><span class="line"> {</span><br><span class="line"> he_.boundaryField<span class="literal">()</span>[patchi] == he</span><br><span class="line"> (</span><br><span class="line"> this->p_.boundaryField<span class="literal">()</span>[patchi],</span><br><span class="line"> this-><span class="type">T_</span>.boundaryField<span class="literal">()</span>[patchi],</span><br><span class="line"> patchi</span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> this->heBoundaryCorrection(he_);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这里调用了 <code>HE</code> 函数来初始化 <code>he_</code> 的内部场,并对调用另一个三个数的 <code>he</code> 函数其边界条件进行了修正:<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> BasicThermo, <span class="keyword">class</span> MixtureType></span><br><span class="line">Foam::tmp<Foam::scalarField> Foam::heThermo<BasicThermo, MixtureType>::he</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> scalarField& p,</span><br><span class="line"> <span class="keyword">const</span> scalarField& T,</span><br><span class="line"> <span class="keyword">const</span> label patchi</span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> tmp<scalarField> the(<span class="keyword">new</span> scalarField(T.size()));</span><br><span class="line"> scalarField& he = the();</span><br><span class="line"></span><br><span class="line"> forAll(T, facei)</span><br><span class="line"> {</span><br><span class="line"> he[facei] =</span><br><span class="line"> <span class="keyword">this</span>->patchFaceMixture(patchi, facei).HE(p[facei], T[facei]);</span><br><span class="line"> <span class="comment">// 本质上还是调用了 HE 函数</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> the;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>再来看 <code>HE</code> 函数,这个函数看名字和参数,应该是根据压力和温度来计算能量的,其定义在 <code>species::thermo</code> 类:<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Thermo, <span class="keyword">template</span><<span class="keyword">class</span>> <span class="keyword">class</span> Type></span><br><span class="line"><span class="keyword">inline</span> Foam::scalar</span><br><span class="line">Foam::species::thermo<Thermo, Type>::HE(<span class="keyword">const</span> scalar p, <span class="keyword">const</span> scalar T) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> Type<thermo<Thermo, Type> >::HE(*<span class="keyword">this</span>, p, T);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这里,由于能量最终是什么形式,取决于 <code>energy</code> 关键字对应的类,所以,这里也是调用了定义在前面提到的 <code>energy variable</code> 类中的 <code>HE</code> 函数,以 <code>sensibleInternalEnergy</code> 为例:<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">scalar</span> <span class="keyword">HE</span></span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> Thermo& thermo,</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">scalar</span> p,</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">scalar</span> T</span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> thermo.Es(p, T);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>可见,其返回的是 <code>species::thermo</code> 类的 <code>Es</code> 函数,<br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class <span class="type">Thermo</span>, <span class="keyword">template</span><class> class <span class="type">Type</span>></span><br><span class="line">inline <span class="type">Foam</span>::scalar</span><br><span class="line"><span class="type">Foam</span>::species::thermo<<span class="type">Thermo</span>, <span class="type">Type</span>>::<span class="type">Es</span>(<span class="keyword">const</span> scalar p, <span class="keyword">const</span> scalar T) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> this->es(p, T)/this->W();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span><class <span class="type">Thermo</span>, <span class="keyword">template</span><class> class <span class="type">Type</span>></span><br><span class="line">inline <span class="type">Foam</span>::scalar</span><br><span class="line"><span class="type">Foam</span>::species::thermo<<span class="type">Thermo</span>, <span class="type">Type</span>>::es(<span class="keyword">const</span> scalar p, <span class="keyword">const</span> scalar T) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> this->hs(p, T) - p*this->W()/this->rho(p, T);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p> <code>hs</code> 函数定义在 <code>thermo</code> 类型的类中,以 <code>hConstThermo</code> 类为例:<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> equationOfState></span><br><span class="line"><span class="keyword">inline</span> Foam::scalar Foam::hConstThermo<equationOfState>::hs</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> scalar p, <span class="keyword">const</span> scalar T</span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> Cp_*T;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p><code>hs</code> 表示的是显焓,等于 <code>Cp_*T</code> 。 <code>es</code> 是内能,根据焓的定义,$H=U+pV$。代码中的 <code>hs</code> 和 <code>es</code> 都是 <code>J/kMol</code> 的量纲,所以,$es=hs-pV/n$ 。以理想气体状态方程为例,$pV=nRT$,或者写成 $pM=\rho RT$,得 $pV/n = RT = pM/\rho$ 。</p>
<p>注意,这里的 <code>Cp_</code>,在字典文件里给的是 <code>J/(kg.K)</code> 量纲的,但是在构造函数中,将其转成了 <code>J/(kmol.K)</code> 的量纲:<br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class equationOfState></span><br><span class="line"><span class="type">Foam</span>::hConstThermo<equationOfState>::hConstThermo(<span class="keyword">const</span> dictionary& dict)</span><br><span class="line">:</span><br><span class="line"> equationOfState(dict),</span><br><span class="line"> <span class="type">Cp_</span>(readScalar(dict.subDict(<span class="string">"thermodynamics"</span>).lookup(<span class="string">"Cp"</span>))),</span><br><span class="line"> <span class="type">Hf_</span>(readScalar(dict.subDict(<span class="string">"thermodynamics"</span>).lookup(<span class="string">"Hf"</span>)))</span><br><span class="line">{</span><br><span class="line"> <span class="type">Cp_</span> *= this->W();</span><br><span class="line"> <span class="type">Hf_</span> *= this->W();</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>所以,<code>hs</code>, <code>es</code> 是 <code>J/kmol</code> ; <code>Es</code>, <code>HE</code> 是 <code>J/kg</code>。</p>
<h5 id="Cpv">Cpv</h5><p>这个函数定义在 <code>heThermo</code> 类中。<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> BasicThermo, <span class="keyword">class</span> MixtureType></span><br><span class="line">Foam::tmp<Foam::volScalarField></span><br><span class="line">Foam::heThermo<BasicThermo, MixtureType>::Cpv() <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">const</span> fvMesh& mesh = <span class="keyword">this</span>->T_.mesh();</span><br><span class="line"></span><br><span class="line"> tmp<volScalarField> tCpv</span><br><span class="line"> (</span><br><span class="line"> <span class="keyword">new</span> volScalarField</span><br><span class="line"> (</span><br><span class="line"> IOobject</span><br><span class="line"> (</span><br><span class="line"> <span class="string">"Cpv"</span>,</span><br><span class="line"> mesh.time().timeName(),</span><br><span class="line"> mesh,</span><br><span class="line"> IOobject::NO_READ,</span><br><span class="line"> IOobject::NO_WRITE</span><br><span class="line"> ),</span><br><span class="line"> mesh,</span><br><span class="line"> dimEnergy/dimMass/dimTemperature</span><br><span class="line"> )</span><br><span class="line"> );</span><br><span class="line"> volScalarField& cpv = tCpv();</span><br><span class="line"></span><br><span class="line"> forAll(<span class="keyword">this</span>->T_, celli)</span><br><span class="line"> {</span><br><span class="line"> cpv[celli] =</span><br><span class="line"> <span class="keyword">this</span>->cellMixture(celli).Cpv(<span class="keyword">this</span>->p_[celli], <span class="keyword">this</span>->T_[celli]);</span><br><span class="line"> }</span><br><span class="line"> forAll(<span class="keyword">this</span>->T_.boundaryField(), patchi)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">const</span> fvPatchScalarField& pp = <span class="keyword">this</span>->p_.boundaryField()[patchi];</span><br><span class="line"> <span class="keyword">const</span> fvPatchScalarField& pT = <span class="keyword">this</span>->T_.boundaryField()[patchi];</span><br><span class="line"> fvPatchScalarField& pCpv = cpv.boundaryField()[patchi];</span><br><span class="line"></span><br><span class="line"> forAll(pT, facei)</span><br><span class="line"> {</span><br><span class="line"> pCpv[facei] =</span><br><span class="line"> <span class="keyword">this</span>->patchFaceMixture(patchi, facei).Cpv(pp[facei], pT[facei]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> tCpv;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这个函数,创建了一个 <code>tmp<volScalarField></code>,然后调用定义在 <code>species::thermo</code> 类中的两参数 <code>Cpv</code> 函数来对场量进行初始化,这个函数的形式如下<br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class <span class="type">Thermo</span>, <span class="keyword">template</span><class> class <span class="type">Type</span>></span><br><span class="line">inline <span class="type">Foam</span>::scalar</span><br><span class="line"><span class="type">Foam</span>::species::thermo<<span class="type">Thermo</span>, <span class="type">Type</span>>::<span class="type">Cpv</span>(<span class="keyword">const</span> scalar p, <span class="keyword">const</span> scalar T) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> this->cpv(p, T)/this->W();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span><class <span class="type">Thermo</span>, <span class="keyword">template</span><class> class <span class="type">Type</span>></span><br><span class="line">inline <span class="type">Foam</span>::scalar</span><br><span class="line"><span class="type">Foam</span>::species::thermo<<span class="type">Thermo</span>, <span class="type">Type</span>>::cpv(<span class="keyword">const</span> scalar p, <span class="keyword">const</span> scalar T) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> <span class="type">Type</span><thermo<<span class="type">Thermo</span>, <span class="type">Type</span>> >::cpv(*this, p, T);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p><code>cpv</code> 函数返回的是定义在 <code>energy variable</code> 类中的三参数 <code>cpv</code> 函数,对于 <code>sensibleInternalEnergy</code>,<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">scalar</span> cpv</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> Thermo& thermo,</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">scalar</span> p,</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">scalar</span> T</span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> thermo.cv(p, T);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这里返回的是 <code>species::thermo</code> 类的 <code>cv</code> 函数,<br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class <span class="type">Thermo</span>, <span class="keyword">template</span><class> class <span class="type">Type</span>></span><br><span class="line">inline <span class="type">Foam</span>::scalar</span><br><span class="line"><span class="type">Foam</span>::species::thermo<<span class="type">Thermo</span>, <span class="type">Type</span>>::cv(<span class="keyword">const</span> scalar p, <span class="keyword">const</span> scalar T) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> this->cp(p, T) - this->cpMcv(p, T);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这里的 <code>cp</code> 函数定义在 <code>thermo</code> 类型的类中,以 <code>hConst</code> 为例<br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class equationOfState></span><br><span class="line">inline <span class="type">Foam</span>::scalar <span class="type">Foam</span>::hConstThermo<equationOfState>::cp</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> scalar p,</span><br><span class="line"> <span class="keyword">const</span> scalar T</span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> <span class="type">Cp_</span>; // 量纲是 J/(kmol.K)</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p><code>cpMcv</code> 的定义在状态方程类中,以 <code>perfectGas</code> 为例<br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class <span class="type">Specie</span>></span><br><span class="line">inline <span class="type">Foam</span>::scalar <span class="type">Foam</span>::perfectGas<<span class="type">Specie</span>>::cpMcv(scalar, scalar) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> this-><span class="type">RR</span>; // 量纲是 J/(kmol.K),所以值应该是 <span class="number">8314</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h5 id="alphaEff">alphaEff</h5><p>这个函数需要一个参数,其定义在 <code>heThermo</code> 类中<br><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">template<class <span class="constant">BasicThermo,</span> class <span class="constant">MixtureType></span></span><br><span class="line"><span class="constant">Foam:</span><span class="symbol">:tmp<Foam</span><span class="symbol">:</span><span class="symbol">:volScalarField></span></span><br><span class="line"><span class="constant">Foam:</span><span class="symbol">:heThermo<BasicThermo</span>, <span class="constant">MixtureType></span><span class="symbol">:</span><span class="symbol">:alphaEff</span></span><br><span class="line">(</span><br><span class="line"> const volScalarField& alphat</span><br><span class="line">) const</span><br><span class="line">{</span><br><span class="line"> tmp<<span class="constant">Foam:</span><span class="symbol">:volScalarField></span> alphaEff(this-><span class="constant">CpByCpv(</span>)*(this->alpha<span class="constant">_</span> + alphat));</span><br><span class="line"> alphaEff().rename(<span class="string">"alphaEff"</span>);</span><br><span class="line"> <span class="keyword">return</span> alphaEff;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这里, 无参数的 <code>CpByCpv</code> 函数定义在 <code>species::thermo</code> 类中,最终调用的是 <code>energy varialble</code> 类中的 <code>CpByCpv</code> 函数,如果是内能形式的,则返回 <code>thermo.gamma(p, T)</code> ,焓形式则返回 <code>1</code>。 <code>gamma</code> 的定义在 <code>species::thermo</code><br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class <span class="type">Thermo</span>, <span class="keyword">template</span><class> class <span class="type">Type</span>></span><br><span class="line">inline <span class="type">Foam</span>::scalar</span><br><span class="line"><span class="type">Foam</span>::species::thermo<<span class="type">Thermo</span>, <span class="type">Type</span>>::gamma(<span class="keyword">const</span> scalar p, <span class="keyword">const</span> scalar T) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> scalar cp = this->cp(p, T);</span><br><span class="line"> <span class="keyword">return</span> cp/(cp - this->cpMcv(p, T));</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p><code>alpha_</code> 是层流能量扩散系数,定义在 <code>basicThermo</code> 类,并在该类的构造函数中初始化为零。在 <code>heRhoThermo</code> 类的 <code>calculate</code> 函数中,对其进行了更新<br><figure class="highlight prolog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="atom">scalarField</span>& <span class="atom">alphaCells</span> = <span class="atom">this</span>-><span class="atom">alpha_</span>.<span class="atom">internalField</span>();</span><br><span class="line"><span class="atom">alphaCells</span>[<span class="atom">celli</span>] = <span class="atom">mixture_</span>.<span class="atom">alphah</span>(<span class="atom">pCells</span>[<span class="atom">celli</span>], <span class="name">TCells</span>[<span class="atom">celli</span>]);</span><br><span class="line"></span><br><span class="line"><span class="atom">fvPatchScalarField</span>& <span class="atom">palpha</span> = <span class="atom">this</span>-><span class="atom">alpha_</span>.<span class="atom">boundaryField</span>()[<span class="atom">patchi</span>];</span><br><span class="line"><span class="atom">palpha</span>[<span class="atom">facei</span>] = <span class="atom">mixture_</span>.<span class="atom">alphah</span>(<span class="atom">pp</span>[<span class="atom">facei</span>], <span class="atom">pT</span>[<span class="atom">facei</span>]);</span><br></pre></td></tr></table></figure></p>
<p>可见, <code>alpha_</code> 的值是通过 <code>alphah</code> 函数来计算更新的,这个函数的定义在 <code>trasnport</code> 模型里,以 <code>constTransport</code> 为例<br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class <span class="type">Thermo</span>></span><br><span class="line">inline <span class="type">Foam</span>::scalar <span class="type">Foam</span>::constTransport<<span class="type">Thermo</span>>::alphah</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> scalar p,</span><br><span class="line"> <span class="keyword">const</span> scalar T</span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> mu(p, T)*rPr_;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>返回粘度与普朗特数的比值。<br>至于 <code>alphat</code> ,则是函数 <code>alphaEff</code> 的参数,根据开头的代码可知, <code>alphat</code> 其实是 <code>mut</code> 。<br>只是,暂时不知道为什么有效热扩散系数 <code>alphaEff = CpByCpv * (alpha + alphat)</code>。</p>
<p>构建起能量方程后,就该对其进行求解了。<br><figure class="highlight ocaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">fvOptions.constrain(he1Eqn);</span><br><span class="line"> he1Eqn.solve<span class="literal">()</span>;</span><br><span class="line"></span><br><span class="line"> fvOptions.constrain(he2Eqn);</span><br><span class="line"> he2Eqn.solve<span class="literal">()</span>;</span><br><span class="line"></span><br><span class="line"> thermo1.correct<span class="literal">()</span>;</span><br><span class="line"> <span class="type">Info</span><< <span class="string">"min "</span> << thermo1.<span class="type">T</span><span class="literal">()</span>.name<span class="literal">()</span></span><br><span class="line"> << <span class="string">" "</span> << min(thermo1.<span class="type">T</span><span class="literal">()</span>).<span class="keyword">value</span><span class="literal">()</span> << endl;</span><br><span class="line"></span><br><span class="line"> thermo2.correct<span class="literal">()</span>;</span><br><span class="line"> <span class="type">Info</span><< <span class="string">"min "</span> << thermo2.<span class="type">T</span><span class="literal">()</span>.name<span class="literal">()</span></span><br><span class="line"> << <span class="string">" "</span> << min(thermo2.<span class="type">T</span><span class="literal">()</span>).<span class="keyword">value</span><span class="literal">()</span> << endl;</span><br></pre></td></tr></table></figure></p>
<p>这里, <code>solve</code> 函数值得细说,重点是看 <code>correct()</code> 函数,以及 <code>T()</code> 函数。</p>
<p><code>corretc()</code> 函数指的是定义在 <code>heRhoThermo</code> 类中的 <code>correct()</code> 函数:<br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class <span class="type">BasicPsiThermo</span>, class <span class="type">MixtureType</span>></span><br><span class="line"><span class="type">void</span> <span class="type">Foam</span>::heRhoThermo<<span class="type">BasicPsiThermo</span>, <span class="type">MixtureType</span>>::correct()</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (debug)</span><br><span class="line"> {</span><br><span class="line"> <span class="type">Info</span><< <span class="string">"entering heRhoThermo<MixtureType>::correct()"</span> << endl;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> calculate();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (debug)</span><br><span class="line"> {</span><br><span class="line"> <span class="type">Info</span><< <span class="string">"exiting heRhoThermo<MixtureType>::correct()"</span> << endl;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>可见, <code>correct()</code> 函数,其实就是对 <code>calculate</code> 函数进行了一次调用而已。<br>看来最核心最关键的就在 <code>calculate</code> 函数中了。在仔细看这个函数之前,先把 <code>T()</code> 的定义看完。 <code>T()</code> 定义在 <code>basicThermo</code> 类中,其作用仅是返回同样定义在 <code>basicThermo</code> 类中定义的数据成员 <code>T_</code> 而已。</p>
<p>下面深入分析一下 <code>heRhoThermo</code> 类中的 <code>calculate</code> 函数,这里再将它列出来一次:<br><figure class="highlight prolog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="atom">template</span><<span class="atom">class</span> <span class="name">BasicPsiThermo</span>, <span class="atom">class</span> <span class="name">MixtureType</span>></span><br><span class="line"><span class="atom">void</span> <span class="name">Foam</span>::<span class="atom">heRhoThermo</span><<span class="name">BasicPsiThermo</span>, <span class="name">MixtureType</span>>::<span class="atom">calculate</span>()</span><br><span class="line">{</span><br><span class="line"> <span class="atom">const</span> <span class="atom">scalarField</span>& <span class="atom">hCells</span> = <span class="atom">this</span>-><span class="atom">he</span>().<span class="atom">internalField</span>();</span><br><span class="line"> <span class="atom">const</span> <span class="atom">scalarField</span>& <span class="atom">pCells</span> = <span class="atom">this</span>-><span class="atom">p_</span>.<span class="atom">internalField</span>();</span><br><span class="line"></span><br><span class="line"> <span class="atom">scalarField</span>& <span class="name">TCells</span> = <span class="atom">this</span>-><span class="name">T_</span>.<span class="atom">internalField</span>();</span><br><span class="line"> <span class="atom">scalarField</span>& <span class="atom">psiCells</span> = <span class="atom">this</span>-><span class="atom">psi_</span>.<span class="atom">internalField</span>();</span><br><span class="line"> <span class="atom">scalarField</span>& <span class="atom">rhoCells</span> = <span class="atom">this</span>-><span class="atom">rho_</span>.<span class="atom">internalField</span>();</span><br><span class="line"> <span class="atom">scalarField</span>& <span class="atom">muCells</span> = <span class="atom">this</span>-><span class="atom">mu_</span>.<span class="atom">internalField</span>();</span><br><span class="line"> <span class="atom">scalarField</span>& <span class="atom">alphaCells</span> = <span class="atom">this</span>-><span class="atom">alpha_</span>.<span class="atom">internalField</span>();</span><br><span class="line"></span><br><span class="line"> <span class="atom">forAll</span>(<span class="name">TCells</span>, <span class="atom">celli</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="atom">const</span> <span class="atom">typename</span> <span class="name">MixtureType</span>::<span class="atom">thermoType</span>& <span class="atom">mixture_</span> =</span><br><span class="line"> <span class="atom">this</span>-><span class="atom">cellMixture</span>(<span class="atom">celli</span>);</span><br><span class="line"></span><br><span class="line"> <span class="name">TCells</span>[<span class="atom">celli</span>] = <span class="atom">mixture_</span>.<span class="name">THE</span></span><br><span class="line"> (</span><br><span class="line"> <span class="atom">hCells</span>[<span class="atom">celli</span>],</span><br><span class="line"> <span class="atom">pCells</span>[<span class="atom">celli</span>],</span><br><span class="line"> <span class="name">TCells</span>[<span class="atom">celli</span>]</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> <span class="atom">psiCells</span>[<span class="atom">celli</span>] = <span class="atom">mixture_</span>.<span class="atom">psi</span>(<span class="atom">pCells</span>[<span class="atom">celli</span>], <span class="name">TCells</span>[<span class="atom">celli</span>]);</span><br><span class="line"> <span class="atom">rhoCells</span>[<span class="atom">celli</span>] = <span class="atom">mixture_</span>.<span class="atom">rho</span>(<span class="atom">pCells</span>[<span class="atom">celli</span>], <span class="name">TCells</span>[<span class="atom">celli</span>]);</span><br><span class="line"></span><br><span class="line"> <span class="atom">muCells</span>[<span class="atom">celli</span>] = <span class="atom">mixture_</span>.<span class="atom">mu</span>(<span class="atom">pCells</span>[<span class="atom">celli</span>], <span class="name">TCells</span>[<span class="atom">celli</span>]);</span><br><span class="line"> <span class="atom">alphaCells</span>[<span class="atom">celli</span>] = <span class="atom">mixture_</span>.<span class="atom">alphah</span>(<span class="atom">pCells</span>[<span class="atom">celli</span>], <span class="name">TCells</span>[<span class="atom">celli</span>]);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="atom">forAll</span>(<span class="atom">this</span>-><span class="name">T_</span>.<span class="atom">boundaryField</span>(), <span class="atom">patchi</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="atom">fvPatchScalarField</span>& <span class="atom">pp</span> = <span class="atom">this</span>-><span class="atom">p_</span>.<span class="atom">boundaryField</span>()[<span class="atom">patchi</span>];</span><br><span class="line"> <span class="atom">fvPatchScalarField</span>& <span class="atom">pT</span> = <span class="atom">this</span>-><span class="name">T_</span>.<span class="atom">boundaryField</span>()[<span class="atom">patchi</span>];</span><br><span class="line"> <span class="atom">fvPatchScalarField</span>& <span class="atom">ppsi</span> = <span class="atom">this</span>-><span class="atom">psi_</span>.<span class="atom">boundaryField</span>()[<span class="atom">patchi</span>];</span><br><span class="line"> <span class="atom">fvPatchScalarField</span>& <span class="atom">prho</span> = <span class="atom">this</span>-><span class="atom">rho_</span>.<span class="atom">boundaryField</span>()[<span class="atom">patchi</span>];</span><br><span class="line"></span><br><span class="line"> <span class="atom">fvPatchScalarField</span>& <span class="atom">ph</span> = <span class="atom">this</span>-><span class="atom">he</span>().<span class="atom">boundaryField</span>()[<span class="atom">patchi</span>];</span><br><span class="line"></span><br><span class="line"> <span class="atom">fvPatchScalarField</span>& <span class="atom">pmu</span> = <span class="atom">this</span>-><span class="atom">mu_</span>.<span class="atom">boundaryField</span>()[<span class="atom">patchi</span>];</span><br><span class="line"> <span class="atom">fvPatchScalarField</span>& <span class="atom">palpha</span> = <span class="atom">this</span>-><span class="atom">alpha_</span>.<span class="atom">boundaryField</span>()[<span class="atom">patchi</span>];</span><br><span class="line"></span><br><span class="line"> <span class="atom">if</span> (<span class="atom">pT</span>.<span class="atom">fixesValue</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="atom">forAll</span>(<span class="atom">pT</span>, <span class="atom">facei</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="atom">const</span> <span class="atom">typename</span> <span class="name">MixtureType</span>::<span class="atom">thermoType</span>& <span class="atom">mixture_</span> =</span><br><span class="line"> <span class="atom">this</span>-><span class="atom">patchFaceMixture</span>(<span class="atom">patchi</span>, <span class="atom">facei</span>);</span><br><span class="line"></span><br><span class="line"> <span class="atom">ph</span>[<span class="atom">facei</span>] = <span class="atom">mixture_</span>.<span class="name">HE</span>(<span class="atom">pp</span>[<span class="atom">facei</span>], <span class="atom">pT</span>[<span class="atom">facei</span>]);</span><br><span class="line"></span><br><span class="line"> <span class="atom">ppsi</span>[<span class="atom">facei</span>] = <span class="atom">mixture_</span>.<span class="atom">psi</span>(<span class="atom">pp</span>[<span class="atom">facei</span>], <span class="atom">pT</span>[<span class="atom">facei</span>]);</span><br><span class="line"> <span class="atom">prho</span>[<span class="atom">facei</span>] = <span class="atom">mixture_</span>.<span class="atom">rho</span>(<span class="atom">pp</span>[<span class="atom">facei</span>], <span class="atom">pT</span>[<span class="atom">facei</span>]);</span><br><span class="line"> <span class="atom">pmu</span>[<span class="atom">facei</span>] = <span class="atom">mixture_</span>.<span class="atom">mu</span>(<span class="atom">pp</span>[<span class="atom">facei</span>], <span class="atom">pT</span>[<span class="atom">facei</span>]);</span><br><span class="line"> <span class="atom">palpha</span>[<span class="atom">facei</span>] = <span class="atom">mixture_</span>.<span class="atom">alphah</span>(<span class="atom">pp</span>[<span class="atom">facei</span>], <span class="atom">pT</span>[<span class="atom">facei</span>]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="atom">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="atom">forAll</span>(<span class="atom">pT</span>, <span class="atom">facei</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="atom">const</span> <span class="atom">typename</span> <span class="name">MixtureType</span>::<span class="atom">thermoType</span>& <span class="atom">mixture_</span> =</span><br><span class="line"> <span class="atom">this</span>-><span class="atom">patchFaceMixture</span>(<span class="atom">patchi</span>, <span class="atom">facei</span>);</span><br><span class="line"></span><br><span class="line"> <span class="atom">pT</span>[<span class="atom">facei</span>] = <span class="atom">mixture_</span>.<span class="name">THE</span>(<span class="atom">ph</span>[<span class="atom">facei</span>], <span class="atom">pp</span>[<span class="atom">facei</span>], <span class="atom">pT</span>[<span class="atom">facei</span>]);</span><br><span class="line"></span><br><span class="line"> <span class="atom">ppsi</span>[<span class="atom">facei</span>] = <span class="atom">mixture_</span>.<span class="atom">psi</span>(<span class="atom">pp</span>[<span class="atom">facei</span>], <span class="atom">pT</span>[<span class="atom">facei</span>]);</span><br><span class="line"> <span class="atom">prho</span>[<span class="atom">facei</span>] = <span class="atom">mixture_</span>.<span class="atom">rho</span>(<span class="atom">pp</span>[<span class="atom">facei</span>], <span class="atom">pT</span>[<span class="atom">facei</span>]);</span><br><span class="line"> <span class="atom">pmu</span>[<span class="atom">facei</span>] = <span class="atom">mixture_</span>.<span class="atom">mu</span>(<span class="atom">pp</span>[<span class="atom">facei</span>], <span class="atom">pT</span>[<span class="atom">facei</span>]);</span><br><span class="line"> <span class="atom">palpha</span>[<span class="atom">facei</span>] = <span class="atom">mixture_</span>.<span class="atom">alphah</span>(<span class="atom">pp</span>[<span class="atom">facei</span>], <span class="atom">pT</span>[<span class="atom">facei</span>]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这个函数是在对几个热物理相关的量来进行更新,先更新内部场,再更新边界值。一个一个来看:</p>
<ul>
<li><p>he<br>he 前面讲了,这里需要注意的是其边界值的更新。由于 <code>he</code> 没有IO,其内部场量通过求解能量方程来更新,边界则需要根据情况特殊处理。两种情况,一种是设定了边界的温度值(pT.fixesValue()),这时需要更新边界上的 <code>he</code> 值: <code>ph[facei] = mixture_.HE(pp[facei], pT[facei]);</code> 否则,则边界上的 <code>he</code> 不需要特殊地更新。</p>
</li>
<li><p>psi<br>这个直接调用两参数的 <code>psi</code> 函数来更新,这个函数的定义在状态方程里,以 <code>perfaceGas</code> 为例,</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Specie></span><br><span class="line"><span class="keyword">inline</span> Foam::scalar Foam::perfectGas<Specie>::psi(scalar, scalar T) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1.0</span>/(<span class="keyword">this</span>->R()*T);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p><code>psi</code> 是压缩因子,返回 $\frac{1}{RT}$。</p>
<ul>
<li>rho<br>这个调用的是两参数的 <code>rho</code> 函数,定义在状态方程类中,用于密度的更新,同样以 <code>perfaceGas</code> 为例,<figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class <span class="type">Specie</span>></span><br><span class="line">inline <span class="type">Foam</span>::scalar <span class="type">Foam</span>::perfectGas<<span class="type">Specie</span>>::rho(scalar p, scalar T) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> p/(this->R()*T);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>返回 $\frac{p}{RT}$。</p>
<ul>
<li>mu<br>这个调用的是两参数的 <code>mu</code> 函数,其定义在 transport 类中,以 <code>constTransport</code> 为例,这个返回的是场量的层流粘度<figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class <span class="type">Thermo</span>></span><br><span class="line">inline <span class="type">Foam</span>::scalar <span class="type">Foam</span>::constTransport<<span class="type">Thermo</span>>::mu</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> scalar p,</span><br><span class="line"> <span class="keyword">const</span> scalar T</span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> mu_; // 常量</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>alphah 上面说过了,不再重复。</p>
<p>最后,最复杂的就是温度的更新了</p>
<ul>
<li>T<br>温度的更新,调用的是三参数的 <code>THE</code> 函数,这个函数定义在 <code>species::thermo</code> 类中,<figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class <span class="type">Thermo</span>, <span class="keyword">template</span><class> class <span class="type">Type</span>></span><br><span class="line">inline <span class="type">Foam</span>::scalar <span class="type">Foam</span>::species::thermo<<span class="type">Thermo</span>, <span class="type">Type</span>>::<span class="type">THE</span></span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> scalar he,</span><br><span class="line"> <span class="keyword">const</span> scalar p,</span><br><span class="line"> <span class="keyword">const</span> scalar <span class="type">T0</span></span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> <span class="type">Type</span><thermo<<span class="type">Thermo</span>, <span class="type">Type</span>> >::<span class="type">THE</span>(*this, he, p, <span class="type">T0</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>这里,调用的是 <code>energy variable</code> 类的 <code>THE</code> 函数,以 <code>sensibleInternalEnergy</code> 为例,<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">scalar</span> THE</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> Thermo& thermo,</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">scalar</span> <span class="keyword">e</span>,</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">scalar</span> p,</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">scalar</span> T0</span><br><span class="line"> ) <span class="keyword">const</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> thermo.<span class="keyword">TEs</span>(<span class="keyword">e</span>, p, T0);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></p>
<p>可见,对于 <code>sensibleInternalEnergy</code> , <code>THE</code> 函数实际上返回的是 <code>species::thermo</code> 类的 <code>TEs</code> 函数。<br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class <span class="type">Thermo</span>, <span class="keyword">template</span><class> class <span class="type">Type</span>></span><br><span class="line">inline <span class="type">Foam</span>::scalar <span class="type">Foam</span>::species::thermo<<span class="type">Thermo</span>, <span class="type">Type</span>>::<span class="type">TEs</span></span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> scalar es,</span><br><span class="line"> <span class="keyword">const</span> scalar p,</span><br><span class="line"> <span class="keyword">const</span> scalar <span class="type">T0</span></span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> T</span><br><span class="line"> (</span><br><span class="line"> es,</span><br><span class="line"> p,</span><br><span class="line"> <span class="type">T0</span>,</span><br><span class="line"> &thermo<<span class="type">Thermo</span>, <span class="type">Type</span>>::<span class="type">Es</span>,</span><br><span class="line"> &thermo<<span class="type">Thermo</span>, <span class="type">Type</span>>::<span class="type">Cv</span>,</span><br><span class="line"> &thermo<<span class="type">Thermo</span>, <span class="type">Type</span>>::limit</span><br><span class="line"> );</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这里,终于来到了这个六参数的 <code>T</code> 函数:<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 声明</span></span><br><span class="line"> inline <span class="keyword">scalar</span> T</span><br><span class="line"> (</span><br><span class="line"> <span class="keyword">scalar</span> f,</span><br><span class="line"> <span class="keyword">scalar</span> p,</span><br><span class="line"> <span class="keyword">scalar</span> T0,</span><br><span class="line"> <span class="keyword">scalar</span> (thermo::*F)(<span class="keyword">const</span> <span class="keyword">scalar</span>, <span class="keyword">const</span> <span class="keyword">scalar</span>) <span class="keyword">const</span>,</span><br><span class="line"> <span class="keyword">scalar</span> (thermo::*dFdT)(<span class="keyword">const</span> <span class="keyword">scalar</span>, <span class="keyword">const</span> <span class="keyword">scalar</span>) <span class="keyword">const</span>,</span><br><span class="line"> <span class="keyword">scalar</span> (thermo::*limit)(<span class="keyword">const</span> <span class="keyword">scalar</span>) <span class="keyword">const</span></span><br><span class="line"> ) <span class="keyword">const</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//实现</span></span><br><span class="line">template<<span class="keyword">class</span> Thermo, template<<span class="keyword">class</span>> <span class="keyword">class</span> <span class="keyword">Type</span>></span><br><span class="line">inline Foam::<span class="keyword">scalar</span> Foam::species::thermo<Thermo, <span class="keyword">Type</span>>::T</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">scalar</span> f,</span><br><span class="line"> <span class="keyword">scalar</span> p,</span><br><span class="line"> <span class="keyword">scalar</span> T0,</span><br><span class="line"> <span class="keyword">scalar</span> (thermo<Thermo, <span class="keyword">Type</span>>::*F)(<span class="keyword">const</span> <span class="keyword">scalar</span>, <span class="keyword">const</span> <span class="keyword">scalar</span>) <span class="keyword">const</span>,</span><br><span class="line"> <span class="keyword">scalar</span> (thermo<Thermo, <span class="keyword">Type</span>>::*dFdT)(<span class="keyword">const</span> <span class="keyword">scalar</span>, <span class="keyword">const</span> <span class="keyword">scalar</span>)</span><br><span class="line"> <span class="keyword">const</span>,</span><br><span class="line"> <span class="keyword">scalar</span> (thermo<Thermo, <span class="keyword">Type</span>>::*limit)(<span class="keyword">const</span> <span class="keyword">scalar</span>) <span class="keyword">const</span></span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">scalar</span> <span class="keyword">Test</span> = T0;</span><br><span class="line"> <span class="keyword">scalar</span> Tnew = T0;</span><br><span class="line"> <span class="keyword">scalar</span> Ttol = T0*tol_;</span><br><span class="line"> int iter = 0;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">do</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">Test</span> = Tnew;</span><br><span class="line"> Tnew =</span><br><span class="line"> (this->*limit)</span><br><span class="line"> (<span class="keyword">Test</span> - ((this->*F)(p, <span class="keyword">Test</span>) - f)/(this->*dFdT)(p, <span class="keyword">Test</span>));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (iter++ > maxIter_)</span><br><span class="line"> {</span><br><span class="line"> FatalErrorIn</span><br><span class="line"> (</span><br><span class="line"> <span class="string">"thermo<Thermo, Type>::T(scalar f, scalar T0, "</span></span><br><span class="line"> <span class="string">"scalar (thermo<Thermo, Type>::*F)"</span></span><br><span class="line"> <span class="string">"(const scalar) const, "</span></span><br><span class="line"> <span class="string">"scalar (thermo<Thermo, Type>::*dFdT)"</span></span><br><span class="line"> <span class="string">"(const scalar) const, "</span></span><br><span class="line"> <span class="string">"scalar (thermo<Thermo, Type>::*limit)"</span></span><br><span class="line"> <span class="string">"(const scalar) const"</span></span><br><span class="line"> <span class="string">") const"</span></span><br><span class="line"> ) << <span class="string">"Maximum number of iterations exceeded"</span></span><br><span class="line"> << abort(FatalError);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">while</span> (mag(Tnew - <span class="keyword">Test</span>) > Ttol);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> Tnew;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这个函数,前三个参数是普通的 scalar 类型变量,后三个参数,是函数指针,并且都指向当前类 <code>species::thermo</code> 的成员函数。以 <code>TEs</code> 为例,后三个参数分别代入的是 <code>Es</code> , <code>Cv</code> 以及 <code>limit</code> 三个函数。 <code>Es</code> 和 <code>Cv</code> 前面都看过了, <code>limit</code> 定义在 thermo 类中,以 <code>hConst</code> 为例,<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> EquationOfState></span><br><span class="line"><span class="keyword">inline</span> Foam::scalar Foam::hConstThermo<EquationOfState>::limit</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> scalar T</span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> T;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>直接返回温度 <code>T</code> 。事实上,除了 <code>janaf</code> 模型,其他的都是返回 <code>T</code> 。 <code>janaf</code> 模型中, 如果温度没有超出 [Tlow,Thigh],则会出来警告信息,并且,若 <code>T < Tlow</code> 则返回 <code>Tlow</code>,而 <code>T > Thigh</code> 时,则返回 <code>Thigh</code>。</p>
<p>下面仔细来分析六参数 <code>T</code> 函数的核心部分。经过摸索,发现这个其实是一个牛顿迭代的过程,目的是根据 <code>Es</code> 函数,从内能 <code>es</code> 来计算温度 <code>T</code>,即求解 $E_s(p,T) - E_s = 0$ 。令 $F(T)= E_s(p,T) - E_s $,则牛顿迭代法的递推公式为<br>$$<br>T_{New} = T_{old} - \dfrac{F(T_{old})}{F\prime(T_{old})} = T_{old} - \dfrac{E_s(p, T_{old)} - E_s}{dE_s(p,T)/dT |_{T=T_{old}}}<br>$$<br>对于 <code>sensibleInternalEnergy</code> ,$dE_s(p,T)/dT = C_v(p,T)$<br>所以最终得到递推公式为<br>$$<br>T_{New} = T_{old} - \dfrac{E_s(p, T_{old)} - E_s}{C_v(p, T_{old})}<br>$$<br>这里设置了最大迭代次数为 100,超过将报那个涉及到能量的模拟中最容易见到的崩溃信息:”Maximum number of iterations exceeded” 。</p>
<p>当能量变量是焓时,则 $E_s$ 要换成 $H_s$, $C_v$ 要换成 $C_p$ 。 </p>
<p>至此便分析完了一个具体的能量方程实例。</p>
]]></content>
<summary type="html">
<![CDATA[<p>本篇来看一个具体的能量方程,以 <code>twoPhaseEulerFoam</code> 的 <code>EEqn.H</code> 为例。</p>]]>
</summary>
<category term="Code Explained" scheme="http://xiaopingqiu.github.io/tags/Code-Explained/"/>
<category term="thermophysicalModels" scheme="http://xiaopingqiu.github.io/tags/thermophysicalModels/"/>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/categories/OpenFOAM/"/>
</entry>
<entry>
<title><![CDATA[OpenFOAM 中的热物理类之继承派生关系]]></title>
<link href="http://xiaopingqiu.github.io/2016/06/25/thermophysics3/"/>
<id>http://xiaopingqiu.github.io/2016/06/25/thermophysics3/</id>
<published>2016-06-25T07:14:28.000Z</published>
<updated>2016-06-25T07:44:54.491Z</updated>
<content type="html"><![CDATA[<p>根据上一篇的介绍,我们已经知道<br><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="title">thermoType</span></span><br><span class="line">{</span><br><span class="line"> <span class="title">type</span> heRhoThermo;</span><br><span class="line"> <span class="title">mixture</span> pureMixture;</span><br><span class="line"> <span class="title">transport</span> const;</span><br><span class="line"> <span class="title">thermo</span> hConst;</span><br><span class="line"> <span class="title">equationOfState</span> perfectGas;</span><br><span class="line"> <span class="title">specie</span> specie;</span><br><span class="line"> <span class="title">energy</span> sensibleInternalEnergy;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这个设置对应的是下述类:<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">heRhoThermo </span><br><span class="line">< </span><br><span class="line"> rhoThermo, </span><br><span class="line"> pureMixture</span><br><span class="line"> <</span><br><span class="line"> constTransport<<span class="symbol">species:</span><span class="symbol">:thermo<hConstThermo<perfectGas<specie>></span>,sensibleInternalEnergy<span class="prompt">>></span><br><span class="line"> </span>> </span><br><span class="line">></span><br></pre></td></tr></table></figure></p>
<p>接下来就能来看看具体的类的继承派生关系了。</p>
<a id="more"></a>
<p>经过前面的分析,最终指针 <code>thermo_</code> 指向的是 <code>heRhoThermo</code> 类的对象,所以先来看一下 <code>heRhoThermo</code> 类。<br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class <span class="type">BasicPsiThermo</span>, class <span class="type">MixtureType</span>></span><br><span class="line">class heRhoThermo</span><br><span class="line">:</span><br><span class="line"> public heThermo<<span class="type">BasicPsiThermo</span>, <span class="type">MixtureType</span>></span><br><span class="line">{</span><br><span class="line"> // <span class="type">Private</span> <span class="type">Member</span> <span class="type">Functions</span></span><br><span class="line"></span><br><span class="line"> //- <span class="type">Calculate</span> the thermo variables</span><br><span class="line"> <span class="type">void</span> calculate();</span><br><span class="line"></span><br><span class="line"> //- <span class="type">Construct</span> <span class="keyword">as</span> copy (<span class="keyword">not</span> implemented)</span><br><span class="line"> heRhoThermo(<span class="keyword">const</span> heRhoThermo<<span class="type">BasicPsiThermo</span>, <span class="type">MixtureType</span>>&);</span><br></pre></td></tr></table></figure></p>
<p><code>heRhoThermo</code> 类很简单,它继承自 <code>heThermo</code> 类,并且和 <code>heThermo</code> 类用同样的模板参数。<br>接下来看看 <code>heThermo</code> 类:<br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><class <span class="type">BasicThermo</span>, class <span class="type">MixtureType</span>></span><br><span class="line">class heThermo</span><br><span class="line">:</span><br><span class="line"> public <span class="type">BasicThermo</span>,</span><br><span class="line"> public <span class="type">MixtureType</span></span><br><span class="line">{</span><br><span class="line">protected:</span><br><span class="line"></span><br><span class="line"> // <span class="type">Protected</span> data</span><br><span class="line"></span><br><span class="line"> //- <span class="type">Energy</span> field</span><br><span class="line"> volScalarField he_;</span><br></pre></td></tr></table></figure></p>
<p>这里,前面多次提到的“继承其模板参数代表的类”这种模式又出现了。有了前两篇分析的基础,我们已经知晓了 <code>thermophysicalProperties</code> 文件里的设置将对应着怎么的一个具体的模型,所有的模板参数都一目了然。知道了模板参数,就能将模板类实例化,再分析其继承派生关系就不是问题了。探索的中间过程这里不详述了,只列出文章开头的那个实例对应的继承派生关系:</p>
<p><img src="/image/thermos/thermo.png" alt="继承派生关系"></p>
<p>注意几点:</p>
<ol>
<li>上图中有两个继承派生关系,其中 <code>constTransport</code> 这个类是作为 <code>pureMixture</code> 类的模板参数的,从而将这两个部分联系起来。</li>
<li><code>species::thermo</code> 中, <code>species</code> 是命名空间, <code>thermo</code> 是类名,具体定义在 <code>src/thermophysicalModels/specie/thermo/thermo/thermo.H</code>。</li>
<li><code>sensibleInternalEnergy</code> 类的模板参数中,某种程度上讲,包含了它自己!</li>
<li>mixture,transport,thermo,equationOfstate,specie,energy 这 6 个子模型有哪些可选的,这一点在 UserGuide 的第 7 章已经介绍得很清楚了,这里就不再重复了。</li>
</ol>
<p>了解了这些,就能理解热物理类的框架了。下一部分将针对 <code>twoPhaseEulerFoam</code> 的热物理相关的模块,来梳理一下热物理模型的流程,主要是,能量方程的构建,如何从能量来得到温度,其他依赖于温度的量包括粘度、密度、压力等又是如何更新的,希望能对传热的模拟有些指导作用,尤其是当出问题的时候,能大概知道可能的原因。</p>
]]></content>
<summary type="html">
<![CDATA[<p>根据上一篇的介绍,我们已经知道<br><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="title">thermoType</span></span><br><span class="line">{</span><br><span class="line"> <span class="title">type</span> heRhoThermo;</span><br><span class="line"> <span class="title">mixture</span> pureMixture;</span><br><span class="line"> <span class="title">transport</span> const;</span><br><span class="line"> <span class="title">thermo</span> hConst;</span><br><span class="line"> <span class="title">equationOfState</span> perfectGas;</span><br><span class="line"> <span class="title">specie</span> specie;</span><br><span class="line"> <span class="title">energy</span> sensibleInternalEnergy;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这个设置对应的是下述类:<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">heRhoThermo </span><br><span class="line">< </span><br><span class="line"> rhoThermo, </span><br><span class="line"> pureMixture</span><br><span class="line"> <</span><br><span class="line"> constTransport<<span class="symbol">species:</span><span class="symbol">:thermo<hConstThermo<perfectGas<specie>></span>,sensibleInternalEnergy<span class="prompt">>></span><br><span class="line"> </span>> </span><br><span class="line">></span><br></pre></td></tr></table></figure></p>
<p>接下来就能来看看具体的类的继承派生关系了。</p>]]>
</summary>
<category term="Code Explained" scheme="http://xiaopingqiu.github.io/tags/Code-Explained/"/>
<category term="thermophysicalModels" scheme="http://xiaopingqiu.github.io/tags/thermophysicalModels/"/>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/categories/OpenFOAM/"/>
</entry>
<entry>
<title><![CDATA[OpenFOAM 中的热物理类之 hashTable 的创建]]></title>
<link href="http://xiaopingqiu.github.io/2016/06/25/thermophysics2/"/>
<id>http://xiaopingqiu.github.io/2016/06/25/thermophysics2/</id>
<published>2016-06-25T06:46:48.000Z</published>
<updated>2016-09-02T10:25:56.259Z</updated>
<content type="html"><![CDATA[<p>这一篇来看一下热物理类是如何编译并创建储存了可选模型的 hashTable 的。</p>
<a id="more"></a>
<p>根据以前的经验,编译和构建 hashTable 肯定是跟这个源文件有关:<code>src/thermophysicalModels/basic/rhoThermo/rhoThermos</code>。<br>这个文件里,全部都是在调用宏函数。而且,从宏函数的参数来看,似乎就是个排列组合的游戏,把所有可用的组合都写了一遍。<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">makeThermo</span><br><span class="line">(</span><br><span class="line"> rhoThermo,</span><br><span class="line"> heRhoThermo,</span><br><span class="line"> pureMixture,</span><br><span class="line"> constTransport,</span><br><span class="line"> sensibleInternalEnergy,</span><br><span class="line"> hConstThermo,</span><br><span class="line"> perfectGas,</span><br><span class="line"> specie</span><br><span class="line">);</span><br><span class="line">......</span><br></pre></td></tr></table></figure></p>
<p>为了弄清这部分内容,需要先理解 <code>makeThermo</code> 这个宏函数的定义,见 <code>src/thermophysicalModels/basic/fluidThermo/makeThermo.H</code>:<br><figure class="highlight livescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#define makeThermoTypedefs(BaseThermo,Cthermo,Mixture,Transport,Type,Thermo,EqnOfState,Specie)\</span></span><br><span class="line"> <span class="string">\</span></span><br><span class="line">typedef <span class="string">\</span></span><br><span class="line"> Transport <span class="string">\</span></span><br><span class="line"> < <span class="string">\</span></span><br><span class="line"> <span class="attribute">species</span>::thermo <span class="string">\</span></span><br><span class="line"> < <span class="string">\</span></span><br><span class="line"> Thermo <span class="string">\</span></span><br><span class="line"> < <span class="string">\</span></span><br><span class="line"> EqnOfState <span class="string">\</span></span><br><span class="line"> < <span class="string">\</span></span><br><span class="line"> Specie <span class="string">\</span></span><br><span class="line"> > <span class="string">\</span></span><br><span class="line"> >, <span class="string">\</span></span><br><span class="line"> Type <span class="string">\</span></span><br><span class="line"> > <span class="string">\</span></span><br><span class="line"> > Transport<span class="comment">##Type##Thermo##EqnOfState##Specie; \</span></span><br><span class="line"> <span class="string">\</span></span><br><span class="line">typedef <span class="string">\</span></span><br><span class="line"> Cthermo <span class="string">\</span></span><br><span class="line"> < <span class="string">\</span></span><br><span class="line"> BaseThermo, <span class="string">\</span></span><br><span class="line"> Mixture<Transport<span class="comment">##Type##Thermo##EqnOfState##Specie> \</span></span><br><span class="line"> > Cthermo<span class="comment">##Mixture##Transport##Type##Thermo##EqnOfState##Specie; \</span></span><br><span class="line"> <span class="string">\</span></span><br><span class="line">defineTemplateTypeNameAndDebugWithName <span class="string">\</span></span><br><span class="line">( <span class="string">\</span></span><br><span class="line"> Cthermo<span class="comment">##Mixture##Transport##Type##Thermo##EqnOfState##Specie, \</span></span><br><span class="line"> ( <span class="string">\</span></span><br><span class="line"> <span class="comment">#Cthermo"<"#Mixture"<" \</span></span><br><span class="line"> + Transport<span class="comment">##Type##Thermo##EqnOfState##Specie::typeName() \</span></span><br><span class="line"> + <span class="string">">>"</span> <span class="string">\</span></span><br><span class="line"> ).c_str(), <span class="string">\</span></span><br><span class="line"> <span class="number">0</span> <span class="string">\</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">#define makeThermo(BaseThermo,Cthermo,Mixture,Transport,Type,Thermo,EqnOfState,Specie)\</span></span><br><span class="line"> <span class="string">\</span></span><br><span class="line">makeThermoTypedefs <span class="string">\</span></span><br><span class="line">( <span class="string">\</span></span><br><span class="line"> BaseThermo, <span class="string">\</span></span><br><span class="line"> Cthermo, <span class="string">\</span></span><br><span class="line"> Mixture, <span class="string">\</span></span><br><span class="line"> Transport, <span class="string">\</span></span><br><span class="line"> Type, <span class="string">\</span></span><br><span class="line"> Thermo, <span class="string">\</span></span><br><span class="line"> EqnOfState, <span class="string">\</span></span><br><span class="line"> Specie <span class="string">\</span></span><br><span class="line">) <span class="string">\</span></span><br><span class="line"> <span class="string">\</span></span><br><span class="line">addToRunTimeSelectionTable <span class="string">\</span></span><br><span class="line">( <span class="string">\</span></span><br><span class="line"> basicThermo, <span class="string">\</span></span><br><span class="line"> Cthermo<span class="comment">##Mixture##Transport##Type##Thermo##EqnOfState##Specie, \</span></span><br><span class="line"> fvMesh <span class="string">\</span></span><br><span class="line">); <span class="string">\</span></span><br><span class="line"> <span class="string">\</span></span><br><span class="line">addToRunTimeSelectionTable <span class="string">\</span></span><br><span class="line">( <span class="string">\</span></span><br><span class="line"> fluidThermo, <span class="string">\</span></span><br><span class="line"> Cthermo<span class="comment">##Mixture##Transport##Type##Thermo##EqnOfState##Specie, \</span></span><br><span class="line"> fvMesh <span class="string">\</span></span><br><span class="line">); <span class="string">\</span></span><br><span class="line"> <span class="string">\</span></span><br><span class="line">addToRunTimeSelectionTable <span class="string">\</span></span><br><span class="line">( <span class="string">\</span></span><br><span class="line"> BaseThermo, <span class="string">\</span></span><br><span class="line"> Cthermo<span class="comment">##Mixture##Transport##Type##Thermo##EqnOfState##Specie, \</span></span><br><span class="line"> fvMesh <span class="string">\</span></span><br><span class="line">);</span><br></pre></td></tr></table></figure></p>
<p>可见,在 <code>makeThermo</code> 这个宏函数里,先调用了 <code>makeThermoTypedefs</code> 宏函数,然后调用 <code>addToRunTimeSelectionTable</code> 函数。按照之前对 RTS 机制的理解,调用 <code>addToRunTimeSelectionTable</code> 函数的作用是往 hashTable 里插入元素,细节不需再赘述。这里主要来看看 <code>makeThermoTypedefs</code> 函数的功能,以上文列举的这个实例为例。先来看第一个 typedef:将实例中的参数代入后,<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">typedef \</span><br><span class="line"> constTransport<<span class="symbol">species:</span><span class="symbol">:thermo<hConstThermo<perfectGas<specie>></span>,sensibleInternalEnergy<span class="prompt">>> </span>\</span><br><span class="line"> constTransportsensibleEnthalpyhConstThermoperfectGasspecie;</span><br></pre></td></tr></table></figure></p>
<p>第二个 typedef<br><figure class="highlight livescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">typedef <span class="string">\</span></span><br><span class="line"> heRhoThermo <span class="string">\</span></span><br><span class="line"> < <span class="string">\</span></span><br><span class="line"> rhoThermo, <span class="string">\</span></span><br><span class="line"> pureMixture<constTransportsensibleEnthalpyhConstThermoperfectGasspecie> <span class="string">\</span></span><br><span class="line"> > heRhoThermopureMixtureconstTransportsensibleEnthalpyhConstThermoperfectGasspecie;</span><br></pre></td></tr></table></figure></p>
<p>除了这两个 typedef,还调用了 <code>defineTemplateTypeNameAndDebugWithName</code> 宏函数,这个函数的定义在 <code>src/OpenFOAM/db/typeInfo/className.H</code>:</p>
<figure class="highlight fortran"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">#define defineTemplateTypeNameAndDebugWithName(<span class="keyword">Type</span>, <span class="keyword">Name</span>, DebugSwitch) \</span><br><span class="line"> defineTemplateTypeNameWithName(<span class="keyword">Type</span>, <span class="keyword">Name</span>); \</span><br><span class="line"> defineTemplateDebugSwitchWithName(<span class="keyword">Type</span>, <span class="keyword">Name</span>, DebugSwitch)</span><br><span class="line"></span><br><span class="line">#define defineTemplateTypeNameWithName(<span class="keyword">Type</span>, <span class="keyword">Name</span>) \</span><br><span class="line"> defineTypeNameWithName(<span class="keyword">Type</span>, <span class="keyword">Name</span>)</span><br><span class="line"></span><br><span class="line">#define defineTypeNameWithName(<span class="keyword">Type</span>, <span class="keyword">Name</span>) \</span><br><span class="line"> const ::Foam::word <span class="keyword">Type</span>::typeName(<span class="keyword">Name</span>)</span><br></pre></td></tr></table></figure>
<p>很显然,这个宏函数的作用是修改类对应的 <code>typeName</code> 和 debug 选项。在 OpenFOAM 中,很多类中都会调用 <code>TypeName("typename")</code>,这里的 <code>TypeName</code> 也是一个宏函数,定义在 <code>src/OpenFOAM/db/typeInfo/className.H</code>:</p>
<figure class="highlight vala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="preprocessor">#define TypeName(TypeNameString) \</span></span><br><span class="line"> ClassName(TypeNameString); \</span><br><span class="line"> virtual <span class="keyword">const</span> word& type() <span class="keyword">const</span> { <span class="keyword">return</span> typeName; }</span><br><span class="line"></span><br><span class="line"><span class="preprocessor">#define ClassName(TypeNameString) \</span></span><br><span class="line"> ClassNameNoDebug(TypeNameString); \</span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">int</span> debug</span><br><span class="line"> </span><br><span class="line"><span class="preprocessor">#define ClassNameNoDebug(TypeNameString) \</span></span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">const</span> <span class="keyword">char</span>* typeName_() { <span class="keyword">return</span> TypeNameString; } \</span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">const</span> ::Foam::word typeName</span><br></pre></td></tr></table></figure>
<p>可见, <code>TypeName</code> 这个宏函数,声明了一个类静态变量 <code>typeName</code>,定义了一个函数 <code>type</code> 用于返回 <code>typeName</code> 的值,并定义了一个静态变量 <code>debug</code> 用于存储 debug 选项。这里与 RTS 机制有关的是 <code>typeName</code> 这个变量。</p>
<p>绕了半圈,回到 <code>defineTemplateTypeNameAndDebugWithName</code> 函数。了解了 <code>typeName</code> 这个变量的定义,很容易就能看出来, <code>defineTemplateTypeNameAndDebugWithName</code> 这个函数其实就是在对类的静态变量 <code>typeName</code> 进行赋值。根据上文的实例提供的参数,宏函数 <code>defineTemplateTypeNameAndDebugWithName</code> 可以理解为:对 <code>heRhoThermopureMixtureconstTransportsensibleEnthalpyhConstThermoperfectGasspecie</code> 对应的类的静态变量 <code>typeName</code> 进行赋值,赋值结果为:<br><code>heRhoThermo<pureMixture< + constTransport<species::thermo<hConstThermo<perfectGas<specie>>,sensibleInternalEnergy>>::typeName() + >></code><br>。这里调用了 <code>constTransport</code> 类的成员函数 <code>typeName()</code>。<br>经过一番冗长的函数调用,得到的最终结果是:将 <code>heRhoThermopureMixtureconstTransportsensibleEnthalpyhConstThermoperfectGasspecie</code> 对应的类的静态变量 <code>typeName</code> 赋值为:<code>heRhoThermo<pureMixture<const<hConst<perfectGas<specie>>,sensiblesensibleEnthalpy>>></code>。</p>
<p>至此,经过一番宏函数的调用,得到了 <code>addToRunTimeSelectionTable</code> 宏函数的参数。前面 RTS 机制部分讲过,这个函数的作用就是对 hashTable 增加元素,以</p>
<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">addToRunTimeSelectionTable</span> \</span><br><span class="line">( \</span><br><span class="line"> <span class="tag">BaseThermo</span>, \</span><br><span class="line"> <span class="tag">Cthermo</span>#<span class="id">#Mixture</span>#<span class="id">#Transport</span>#<span class="id">#Type</span>#<span class="id">#Thermo</span>#<span class="id">#EqnOfState</span>#<span class="id">#Specie</span>, \</span><br><span class="line"> <span class="tag">fvMesh</span> \</span><br><span class="line">);</span><br></pre></td></tr></table></figure>
<p>为例,第一个参数,表示元素将增加到 <code>BaseThermo</code> 类(这里是 <code>rhoThermo</code> )中声明的 hashTable,第二个参数,表示将要添加的类,添加成功以后,这个类的 <code>typeName</code> 将是 hashTable 的 key,而返回这个类的对象的一个函数,将是 hashTable 的 value。第三个参数对应着 hashTable 对象的名字,fvMesh 对应的 hashTable 对象名为 <code>fvMeshConstructorTable</code>,这与在 <code>rhoThermo</code> 中声明的名字是对应的。</p>
<p>最后总结如下:<br>宏函数</p>
<figure class="highlight lisp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">makeThermo</span><br><span class="line"><span class="list">(</span><br><span class="line"> <span class="keyword">rhoThermo</span>,</span><br><span class="line"> heRhoThermo,</span><br><span class="line"> pureMixture,</span><br><span class="line"> constTransport,</span><br><span class="line"> sensibleInternalEnergy,</span><br><span class="line"> hConstThermo,</span><br><span class="line"> perfectGas,</span><br><span class="line"> specie</span><br><span class="line">)</span><span class="comment">;</span></span><br></pre></td></tr></table></figure>
<p>调用以后,向 <code>rhoThermo</code> 类中声明的 hashTable 中增加了一组元素,其 key 为 <code>heRhoThermo<pureMixture<const<hConst<perfectGas<specie>>,sensibleInternalEnergy>>></code> ,value 对应的函数返回的是类</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">heRhoThermo </span><br><span class="line">< </span><br><span class="line"> rhoThermo, </span><br><span class="line"> pureMixture</span><br><span class="line"> <</span><br><span class="line"> constTransport<<span class="symbol">species:</span><span class="symbol">:thermo<hConstThermo<perfectGas<specie>></span>,sensibleInternalEnergy<span class="prompt">>></span><br><span class="line"> </span>> </span><br><span class="line">></span><br></pre></td></tr></table></figure>
<p>的对象。</p>
<p>每调用一次 <code>makeThermo</code> 函数,就增加了一个新组元素,也即增加了一个可选的模型。不同的参数,其实对应的是不同的模板实例。</p>
<p>至此,就知道了在 <code>twoPhaseEulerFoam</code> 的 <code>phaseModel</code> 中定义的热物理类接口 <code>thermo_</code> 最终指向的是 <code>heRhoThermo</code> 类的对象。虽然代入的模板数很复杂,但整个架构仍然是基于 RTS 机制的。</p>
<p>接下来,要想理解能量方程,理解温度,粘度,压力等这些热物理相关的量是怎么计算更新的,就需要仔细看一下 <code>heRhoThermo</code> 类的继承派生关系了。</p>
]]></content>
<summary type="html">
<![CDATA[<p>这一篇来看一下热物理类是如何编译并创建储存了可选模型的 hashTable 的。</p>]]>
</summary>
<category term="Code Explained" scheme="http://xiaopingqiu.github.io/tags/Code-Explained/"/>
<category term="thermophysicalModels" scheme="http://xiaopingqiu.github.io/tags/thermophysicalModels/"/>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/categories/OpenFOAM/"/>
</entry>
<entry>
<title><![CDATA[OpenFOAM 中的热物理类之接口]]></title>
<link href="http://xiaopingqiu.github.io/2016/06/25/thermophysics1/"/>
<id>http://xiaopingqiu.github.io/2016/06/25/thermophysics1/</id>
<published>2016-06-25T06:27:14.000Z</published>
<updated>2016-06-25T06:38:57.428Z</updated>
<content type="html"><![CDATA[<p>本系列来看一下 OpenFOAM 中的热物理类。热物理类比较繁杂,这里先看一下纯物质的热物理模型。本篇先来看看热物理类在求解器中的接口,以2.3.x 版的 <code>twoPhaseEulerFoam</code> 为例。</p>
<a id="more"></a>
<p><code>twoPhaseEulerFoam</code> 中的热物理类的接口在 <code>phaseModel</code> 类中声明:<br><figure class="highlight lisp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">//- Thermophysical properties</span><br><span class="line">autoPtr<rhoThermo> thermo_<span class="comment">;</span></span><br><span class="line"></span><br><span class="line">thermo_<span class="list">(<span class="keyword">rhoThermo</span>:<span class="keyword">:New</span><span class="list">(<span class="keyword">fluid</span>.mesh<span class="list">()</span>, name_)</span>)</span></span><br></pre></td></tr></table></figure></p>
<p>可见,接口是 <code>rhoThermo</code> 类的指针。</p>
<p>接着看 <code>rhoThermo</code> 类的 <code>New</code> 函数。<br><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//- Selector</span></span><br><span class="line"><span class="keyword">static</span> autoPtr<rhoThermo> <span class="keyword">New</span></span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> fvMesh&,</span><br><span class="line"> <span class="keyword">const</span> word& phaseName=word::null</span><br><span class="line">);</span><br><span class="line"> </span><br><span class="line">Foam::autoPtr<Foam::rhoThermo> Foam::rhoThermo::New</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> fvMesh& mesh,</span><br><span class="line"> <span class="keyword">const</span> word& phaseName</span><br><span class="line">)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> basicThermo::New<rhoThermo>(mesh, phaseName);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这里调用的是 <code>basicThermo</code> 类的 <code>New</code> 函数。 这里先提一下继承关系,后面再细说:<code>rhoThermo</code> 类继承自 <code>fluidThermo</code> , <code>fluidThermo</code> 类继承自 <code>basicThermo</code>。</p>
<figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">//- <span class="type">Generic</span> <span class="type">New</span> <span class="keyword">for</span> each <span class="keyword">of</span> the related thermodynamics packages</span><br><span class="line">// basicThermo.C</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span><class <span class="type">Thermo</span>></span><br><span class="line"><span class="keyword">static</span> autoPtr<<span class="type">Thermo</span>> <span class="type">New</span></span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> fvMesh&,</span><br><span class="line"> <span class="keyword">const</span> word& phaseName=word::null</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span><class <span class="type">Thermo</span>></span><br><span class="line"><span class="type">Foam</span>::autoPtr<<span class="type">Thermo</span>> <span class="type">Foam</span>::basicThermo::<span class="type">New</span></span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> fvMesh& mesh,</span><br><span class="line"> <span class="keyword">const</span> word& phaseName</span><br><span class="line">)</span><br><span class="line">{</span><br><span class="line"> <span class="type">IOdictionary</span> thermoDict</span><br><span class="line"> (</span><br><span class="line"> <span class="type">IOobject</span></span><br><span class="line"> (</span><br><span class="line"> phasePropertyName(dictName, phaseName),</span><br><span class="line"> mesh.time().constant(),</span><br><span class="line"> mesh,</span><br><span class="line"> <span class="type">IOobject</span>::<span class="type">MUST_READ_IF_MODIFIED</span>,</span><br><span class="line"> <span class="type">IOobject</span>::<span class="type">NO_WRITE</span>,</span><br><span class="line"> <span class="literal">false</span></span><br><span class="line"> )</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> typename <span class="type">Thermo</span>::fvMeshConstructorTable::<span class="keyword">iterator</span> cstrIter =</span><br><span class="line"> lookupThermo<<span class="type">Thermo</span>, typename <span class="type">Thermo</span>::fvMeshConstructorTable></span><br><span class="line"> (</span><br><span class="line"> thermoDict,</span><br><span class="line"> <span class="type">Thermo</span>::fvMeshConstructorTablePtr_</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> autoPtr<<span class="type">Thermo</span>>(cstrIter()(mesh, phaseName));</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>根据 RTS 机制的惯例, <code>New</code> 函数的功能是模型选择(<code>selector</code>),即根据用户指定的关键字来选择对应的模型。 <code>New</code> 函数中先定义了一个 <code>IOdictionary</code> 类的对象, <code>thermoDict</code>,这个对象对应的正是热物理类的配置文件 <code>thermophysicalProperties</code>。<code>New</code> 函数里调用了 <code>lookupThermo</code> 函数,这个函数是关键:<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// basicThermoTemplates.C</span></span><br><span class="line">template<<span class="keyword">class</span> Thermo, <span class="keyword">class</span> <span class="keyword">Table</span>></span><br><span class="line">typename <span class="keyword">Table</span>::iterator Foam::basicThermo::lookupThermo</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> dictionary& thermoDict,</span><br><span class="line"> <span class="keyword">Table</span>* tablePtr</span><br><span class="line">)</span><br><span class="line">{</span><br><span class="line"> word thermoTypeName;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (thermoDict.isDict(<span class="string">"thermoType"</span>))</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">const</span> dictionary& thermoTypeDict(thermoDict.subDict(<span class="string">"thermoType"</span>));</span><br><span class="line"></span><br><span class="line"> Info<< <span class="string">"Selecting thermodynamics package "</span> << thermoTypeDict << endl;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> int nCmpt = 7;</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">char</span>* cmptNames[nCmpt] =</span><br><span class="line"> {</span><br><span class="line"> <span class="string">"type"</span>,</span><br><span class="line"> <span class="string">"mixture"</span>,</span><br><span class="line"> <span class="string">"transport"</span>,</span><br><span class="line"> <span class="string">"thermo"</span>,</span><br><span class="line"> <span class="string">"equationOfState"</span>,</span><br><span class="line"> <span class="string">"specie"</span>,</span><br><span class="line"> <span class="string">"energy"</span></span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Construct the name of the thermo package from the components</span></span><br><span class="line"> thermoTypeName =</span><br><span class="line"> <span class="literal">word</span>(thermoTypeDict.<span class="keyword">lookup</span>(<span class="string">"type"</span>)) + '<'</span><br><span class="line"> + <span class="literal">word</span>(thermoTypeDict.<span class="keyword">lookup</span>(<span class="string">"mixture"</span>)) + '<'</span><br><span class="line"> + <span class="literal">word</span>(thermoTypeDict.<span class="keyword">lookup</span>(<span class="string">"transport"</span>)) + '<'</span><br><span class="line"> + <span class="literal">word</span>(thermoTypeDict.<span class="keyword">lookup</span>(<span class="string">"thermo"</span>)) + '<'</span><br><span class="line"> + <span class="literal">word</span>(thermoTypeDict.<span class="keyword">lookup</span>(<span class="string">"equationOfState"</span>)) + '<'</span><br><span class="line"> + <span class="literal">word</span>(thermoTypeDict.<span class="keyword">lookup</span>(<span class="string">"specie"</span>)) + <span class="string">">>,"</span></span><br><span class="line"> + <span class="literal">word</span>(thermoTypeDict.<span class="keyword">lookup</span>(<span class="string">"energy"</span>)) + <span class="string">">>>"</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Lookup the thermo package</span></span><br><span class="line"> typename <span class="keyword">Table</span>::iterator cstrIter = tablePtr->find(thermoTypeName);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Print error message if package not found in the table</span></span><br><span class="line"> <span class="keyword">if</span> (cstrIter == tablePtr->end())</span><br><span class="line"> {</span><br><span class="line"> FatalErrorIn(Thermo::typeName + <span class="string">"::New"</span>)</span><br><span class="line"> << <span class="string">"Unknown "</span> << Thermo::typeName << <span class="string">" type "</span> << <span class="keyword">nl</span></span><br><span class="line"> << <span class="string">"thermoType"</span> << thermoTypeDict << <span class="keyword">nl</span> << <span class="keyword">nl</span></span><br><span class="line"> << <span class="string">"Valid "</span> << Thermo::typeName << <span class="string">" types are:"</span> << <span class="keyword">nl</span> << <span class="keyword">nl</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Get the list of all the suitable thermo packages available</span></span><br><span class="line"> wordList validThermoTypeNames</span><br><span class="line"> (</span><br><span class="line"> tablePtr->sortedToc()</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Build a table of the thermo packages constituent parts</span></span><br><span class="line"> <span class="comment">// Note: row-0 contains the names of constituent parts</span></span><br><span class="line"> <span class="keyword">List</span><wordList> validThermoTypeNameCmpts</span><br><span class="line"> (</span><br><span class="line"> validThermoTypeNames.size() + 1</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> validThermoTypeNameCmpts[0].setSize(nCmpt);</span><br><span class="line"> forAll(validThermoTypeNameCmpts[0], j)</span><br><span class="line"> {</span><br><span class="line"> validThermoTypeNameCmpts[0][j] = cmptNames[j];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Split the thermo package names into their constituent parts</span></span><br><span class="line"> forAll(validThermoTypeNames, i)</span><br><span class="line"> {</span><br><span class="line"> validThermoTypeNameCmpts[i+1] =</span><br><span class="line"> Thermo::splitThermoName(validThermoTypeNames[i], nCmpt);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Print the table of available packages</span></span><br><span class="line"> <span class="comment">// in terms of their constituent parts</span></span><br><span class="line"> printTable(validThermoTypeNameCmpts, FatalError);</span><br><span class="line"></span><br><span class="line"> FatalError<< <span class="keyword">exit</span>(FatalError);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> cstrIter;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> thermoTypeName = <span class="literal">word</span>(thermoDict.<span class="keyword">lookup</span>(<span class="string">"thermoType"</span>));</span><br><span class="line"></span><br><span class="line"> Info<< <span class="string">"Selecting thermodynamics package "</span> << thermoTypeName << endl;</span><br><span class="line"></span><br><span class="line"> typename <span class="keyword">Table</span>::iterator cstrIter = tablePtr->find(thermoTypeName);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (cstrIter == tablePtr->end())</span><br><span class="line"> {</span><br><span class="line"> FatalErrorIn(Thermo::typeName + <span class="string">"::New"</span>)</span><br><span class="line"> << <span class="string">"Unknown "</span> << Thermo::typeName << <span class="string">" type "</span></span><br><span class="line"> << thermoTypeName << <span class="keyword">nl</span> << <span class="keyword">nl</span></span><br><span class="line"> << <span class="string">"Valid "</span> << Thermo::typeName << <span class="string">" types are:"</span> << <span class="keyword">nl</span></span><br><span class="line"> << tablePtr->sortedToc() << <span class="keyword">nl</span></span><br><span class="line"> << <span class="keyword">exit</span>(FatalError);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> cstrIter;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>可见, <code>loopupThermo</code> 分两种情况处理,一种是 <code>thermophysicalProperties</code> 文件里有一个名为 <code>thermoType</code> 的 <code>subdict</code>,例如<br><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="title">thermoType</span></span><br><span class="line">{</span><br><span class="line"> <span class="title">type</span> heRhoThermo;</span><br><span class="line"> <span class="title">mixture</span> pureMixture;</span><br><span class="line"> <span class="title">transport</span> const;</span><br><span class="line"> <span class="title">thermo</span> hConst;</span><br><span class="line"> <span class="title">equationOfState</span> perfectGas;</span><br><span class="line"> <span class="title">specie</span> specie;</span><br><span class="line"> <span class="title">energy</span> sensibleInternalEnergy;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这种情况下, <code>subdict</code> 里的 7 个关键字将逐一读入,最终将合并起来,得到一个字符串,并赋值给 <code>thermoTypeName</code><br>以上面的那种情况为例,最终得到的<code>thermoTypeName</code> 为<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">heRhoThermo<pureMixture<const<hConst<perfectGas<specie<span class="prompt">>></span>,sensibleInternalEnergy>>></span><br></pre></td></tr></table></figure></p>
<p>然后,根据这个关键词,从 hashTable 中找到对应的元素。如果找不到对应的,则报错,并输出所有可选的方案(由 <code>splitThermoName</code> 和 <code>printTable</code> 两个函数完成,细节这里暂且不表)。</p>
<p>另一种情况,直接从 <code>thermophysicalProperties</code> 读取 <code>thermoType</code> 对应的字符串并赋值给 <code>thermoTypeName</code>,然后据此来从 hashTable 中找到对应的元素。</p>
<p>OpenFOAM 自带的算例中,<code>thermophysicalProperties</code> 文件绝大部分采用前一种方式,因为更直观。后一种方式我在 OpenFOAM-2.3.x 版中只找到一个例子:tutorials/mesh/foamyQuadMesh/OpenCFD/constant/thermophysicalProperties<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">thermoType hePsiThermo<pureMixture<const<hConst<perfectGas<specie<span class="prompt">>></span>,sensibleEnthalpy>>>;</span><br></pre></td></tr></table></figure></p>
<p>至此,大致就知道热物理类的接口定义是怎么回事了。但是,这个存储了可选模型的 hashTable 里有哪些内容,又是怎么构建起来的,还有待进一步深入探索。另外,从 <code>thermoType</code> 对应的字符串的样式,能猜到最终热物理类的接口 <code>thermo_</code> 指向的可能是类似 <code>heRhoThermo</code> 类的对象,而且这些类多半是模板类,并有着复杂的继承派生关系,这部分也还有待深入探索。</p>
]]></content>
<summary type="html">
<![CDATA[<p>本系列来看一下 OpenFOAM 中的热物理类。热物理类比较繁杂,这里先看一下纯物质的热物理模型。本篇先来看看热物理类在求解器中的接口,以2.3.x 版的 <code>twoPhaseEulerFoam</code> 为例。</p>]]>
</summary>
<category term="Code Explained" scheme="http://xiaopingqiu.github.io/tags/Code-Explained/"/>
<category term="thermophysicalModels" scheme="http://xiaopingqiu.github.io/tags/thermophysicalModels/"/>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/categories/OpenFOAM/"/>
</entry>
<entry>
<title><![CDATA[涡结构提取]]></title>
<link href="http://xiaopingqiu.github.io/2016/05/22/QAndLambda/"/>
<id>http://xiaopingqiu.github.io/2016/05/22/QAndLambda/</id>
<published>2016-05-22T11:35:16.000Z</published>
<updated>2016-05-22T14:31:52.155Z</updated>
<content type="html"><![CDATA[<p>为了研究湍流的涡结构,需要有一些方法来将涡结构提取出来,比图在文章中常见类似这种图:<br><img src="/image/vortex/Lambda2.png" alt="涡结构"></p>
<p>本篇介绍怎么在 OpenFOAM 中提取涡结构。</p>
<a id="more"></a>
<p>历史上曾用过的涡结构提取有以下几种:</p>
<ol>
<li><p>压强的局部极小值<br>在形成涡的地方,通常伴随着压强的极小值。比如:<br><img src="/image/vortex/p.png" alt=""><br>这种方法的缺点在于,缺乏客观的压力阈值来捕捉所有的涡结构,而且,压力出现极值的地方不见得就真的有涡。</p>
</li>
<li><p>流线<br>通过流线的封闭来显示涡的结构也是一种常见方法,比如<br><img src="/image/vortex/s.png" alt=""><br>这种方法有一个最明显的缺点是,流线不满足伽利略不变性,即,如果换一个参考系,则可能显示出来的“涡结构”就完全不一样了。另外,这种方法也难以分辨两个很靠近的涡。</p>
</li>
<li><p>涡量的模<br>用涡量的模来显示涡结构是一种很常用的方法,类似这样<br><img src="/image/vortex/magVor.png" alt=""><br>这种方法在自由剪切流中很有效,不过,对于壁面束缚流动则不太适用,原因是背景流动的剪切性导致的涡量模可以达到跟涡结构处的涡量的模差不多大小,这就使得涡结构难以从背景流动中分离出来了。并且,涡量的模的最大值通常发生在壁面上,而涡的核心显然不可能出现在壁面上。所以这种方法不适合用于提取边界层附近的涡结构。</p>
<p>OpenFOAM 中提供了两种方法来提取涡结构:Q 和 Lambda2。</p>
</li>
</ol>
<ul>
<li>速度梯度张量的二阶不变量<br>速度梯度 $\nabla \mathbf{U}$ 的二阶不变量 $Q$ 的定义为<br>$$<br>Q = \frac{1}{2}\Big ( ||\mathbf{W}||^2 - ||\mathbf{S}||^2 \Big )<br>$$<br>其中<br>$$<br>\mathbf{W} = \frac{1}{2} \Big ( \nabla \mathbf{U} - (\nabla \mathbf{U}) ^{\mathrm{T}} \Big ) \\<br>||\mathbf{W}|| = (\mathbf{W}:\mathbf{W})^{1/2} \\<br>\mathbf{S} = \frac{1}{2} \Big ( \nabla \mathbf{U} + (\nabla \mathbf{U}) ^{\mathrm{T}} \Big ) \\<br>||\mathbf{S}|| = (\mathbf{S}:\mathbf{S})^{1/2}<br>$$</li>
</ul>
<p>可以用 $Q > 0$ 来作为涡结构存在的盘踞。<br>在 OpenFOAM 中,有一个程序用来计算 $Q$,名字就叫 <code>Q</code>。在流场计算完毕以后,可以运行 <code>Q</code>,然后在 paraview 中显示 <code>Q</code> 值大于 0 的等值面来显示涡的结构。只是,OpenFOAM 中 $Q$ 的计算用的是另一种方法:</p>
<figure class="highlight scss"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Q.C </span></span><br><span class="line">volTensorField <span class="function">gradU</span>(fvc<span class="value">::<span class="function">grad</span>(U));</span></span><br><span class="line"></span><br><span class="line">volScalarField <span class="tag">Q</span></span><br><span class="line">(</span><br><span class="line"> IOobject</span><br><span class="line"> (</span><br><span class="line"> "<span class="tag">Q</span>",</span><br><span class="line"> runTime<span class="class">.timeName</span>(),</span><br><span class="line"> mesh,</span><br><span class="line"> IOobject<span class="value">::NO_READ,</span><br><span class="line"> IOobject::NO_WRITE</span><br><span class="line"> ),</span><br><span class="line"> <span class="number">0.5</span>*(<span class="function">sqr</span>(<span class="function">tr</span>(gradU)) - <span class="function">tr</span>(((gradU)&(gradU))))</span><br><span class="line">);</span></span><br></pre></td></tr></table></figure>
<p>代码里注释说这是另一种计算 $Q$ 的方法,与上面公式的计算方法差别很小。</p>
<ul>
<li>张量 $\mathbf{W} \cdot \mathbf{W} + \mathbf{S} \cdot \mathbf{S}$ 的第二大特征值</li>
</ul>
<p>另一种判据是 $\mathbf{W} \cdot \mathbf{W} + \mathbf{S} \cdot \mathbf{S}$ 的第二大特征值 $\lambda _ 2 < 0$。<br>在 OpenFOAM 中有一个程序用来计算 $\lambda _ 2$ :<code>Lambda2</code>。<br><figure class="highlight scss"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Lambda2.C</span></span><br><span class="line"> const volTensorField <span class="function">gradU</span>(fvc<span class="value">::<span class="function">grad</span>(U));</span></span><br><span class="line"></span><br><span class="line"> volTensorField SSplusWW</span><br><span class="line"> (</span><br><span class="line"> (<span class="function">symm</span>(gradU) & <span class="function">symm</span>(gradU)) + (<span class="function">skew</span>(gradU) & <span class="function">skew</span>(gradU))</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> volScalarField Lambda2</span><br><span class="line"> (</span><br><span class="line"> IOobject</span><br><span class="line"> (</span><br><span class="line"> "Lambda2",</span><br><span class="line"> runTime<span class="class">.timeName</span>(),</span><br><span class="line"> mesh,</span><br><span class="line"> IOobject<span class="value">::NO_READ,</span><br><span class="line"> IOobject::NO_WRITE</span><br><span class="line"> ),</span><br><span class="line"> <span class="function">-eigenValues</span>(SSplusWW)().<span class="function">component</span>(vector::Y)</span><br><span class="line"> );</span></span><br><span class="line"></span><br><span class="line"> Info<< " Writing -Lambda2" << endl;</span><br><span class="line"> Lambda2<span class="class">.write</span>();</span><br></pre></td></tr></table></figure></p>
<p>注意,OpenFOAM 返回的是 $- \lambda _ 2$,所以,在计算了 <code>Lambda2</code> 后,需要通过 <code>Lambda2</code> 大于 0 的等值面来显示涡结构。本篇开头第一张图片,显示的是圆柱绕流的 <code>Lambda2 = 500</code> 等值面。</p>
<p><strong>参考</strong><br>Eugene de Villiers, The Potential of Large Eddy Simulation for the Modeling of Wall Bounded Flows, Ph.D Thesis, Imperial College of Science, 2005.</p>
]]></content>
<summary type="html">
<![CDATA[<p>为了研究湍流的涡结构,需要有一些方法来将涡结构提取出来,比图在文章中常见类似这种图:<br><img src="/image/vortex/Lambda2.png" alt="涡结构"></p>
<p>本篇介绍怎么在 OpenFOAM 中提取涡结构。</p>]]>
</summary>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/tags/OpenFOAM/"/>
<category term="Postprocessing" scheme="http://xiaopingqiu.github.io/tags/Postprocessing/"/>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/categories/OpenFOAM/"/>
</entry>
<entry>
<title><![CDATA[OpenFOAM 不可压缩湍流模型的 divDevReff 函数]]></title>
<link href="http://xiaopingqiu.github.io/2016/05/03/divDevReff/"/>
<id>http://xiaopingqiu.github.io/2016/05/03/divDevReff/</id>
<published>2016-05-03T05:39:44.000Z</published>
<updated>2016-05-03T05:58:35.645Z</updated>
<content type="html"><![CDATA[<p>3.0 版本之前,OpenFOAM 的单相流求解器如 pisoFoam 的动量方程中调用的是湍流模型的 <code>divDevReff</code> 函数来考虑雷诺应力项的作用。只是,细究起来,这个函数似乎有点小问题,本篇来探讨一下这些小问题。</p>
<a id="more"></a>
<p>OpenFOAM 中单相不可压缩求解器中,雷诺应力项调用的是湍流模型中的 <code>divDevReff</code> 函数。这个函数的返回值为<br>$$<br>\nabla \cdot(\nu_{eff}\nabla U)+\nabla \cdot\left [\nu_{eff}\nabla U^\mathrm{T}-\frac{1}{3} \nu_{eff} (\nabla \cdot U) \mathbf{I} \right ]<br>$$<br>这里有两个疑问,第一是为什么是 $\frac{1}{3}$ 而不是 $\frac{2}{3}$,对应到代码,即为什么用 <code>dev</code> 函数而不是 <code>dev2</code> 函数?第二个问题,根据涡粘度的 Boussinesq approximation,雷诺应力项<br>$$<br>\overline{u’_iu’_j}= -\nu_t \left( \frac{\partial \bar{u}_i}{\partial x_j} + \frac{\partial \bar{u}_j}{\partial x_i} \right) + \frac{2}{3}k \delta_{ij}<br>$$<br>中应该还包含湍动能 $k$,而 OpenFOAM 中的 <code>divDefReff</code> 函数是没有 $k$ 这一项的。<br>这个话题,在 cfd-online 上的<a href="http://www.cfd-online.com/Forums/openfoam-solving/58214-calculating-divdevreff-2.html" target="_blank" rel="external">一篇帖子</a>里有深入的讨论。</p>
<p>对于第一个问题,我跟<a href="http://www.holzmann-cfd.de/index.php/en/tutorials-en" target="_blank" rel="external">Holtzmann CFD</a> 博客的博主 Tobias Holzmann 持同样观点,即$\frac{1}{3}$ 或 $\frac{2}{3}$ 不重要,因为对于不可压缩流动,连续方程为<br>$$<br>\nabla \cdot U = 0<br>$$<br>所以,收敛以后,$\frac{1}{3} \nu_{eff} (\nabla \cdot U)$ 这一项等于0. 但是在开始阶段,或者说还没有达到满足连续性的流场之前,这一项不为零。这里加上这一项是出于数值稳定性以及收敛速度的考虑,这一项不对收敛后的结果几乎没有影响。所以,$\frac{1}{3}$ 或 $\frac{2}{3}$ 不是很重要。<br>但是,可压缩湍流模型里必须是 $\frac{2}{3}$ ,因为这个 $\frac{2}{3}$ 是从 N-S 方程中严格推导而来的,而且,在可压缩的情形下,即使收敛以后,也有 $\nabla \cdot U \neq 0$ 。在 OpenFOAM=3.0 以后的版本里,不可压和可压缩湍流模型纳入到一个框架下了,两种情形下,都是用的 $\frac{2}{3}$ 这个系数。</p>
<p>对于第二个问题,有两种观点,一种认为 $k$ 的值相对很小,可以直接忽略不计。另一种观点认为,$k$ 被放到了压力项里,即,动量方程中的压力是雷诺时均压力与雷诺应力的各向同性分量(即 $\frac{2}{3}k$)之和:<br>$$<br>\bar{u}_j\frac{\partial\bar{u}_i}{\partial\bar{u}_j} =<br>-\frac{1}{\rho}\frac{\partial}{\partial x_i} \underbrace{\left[p + \frac{2}{3}k \right]}_{p^\prime}<br>+ \frac{\partial}{\partial x_j} \left[(\nu+\nu_{t}) \left( \frac{\partial \bar{u}_i}{\partial x_j} + \frac{\partial \bar{u}_j}{\partial x_i}\right) \right]<br>$$<br>这种观点可以在 Pope 2000 书第 88 页找到依据。在 “ The Finite Volume Method in Computational Fluid Dynamics: An Advanced Introduction with OpenFOAM® and Matlab®” 这本书的第 699 页,也提到 $k$ 是被放到压力项里去了,目的在于使动量方程中只含有 $\nu_t$ 这一个跟湍流有关的未知量。</p>
<p>不过,Tobias Holzmann 最后仍持前一种观点,即 $k$ 项被忽略了。理由是 OpenFOAM 中似乎找不到关于修改的压力场的代码,而且 OpenFOAM 那边也没见有人讨论说 OpenFOAM 中使用的是修改的压力场。<br>第二个问题目前还没有确切的结论,也尚不清楚这样处理对结果有多大影响。</p>
]]></content>
<summary type="html">
<![CDATA[<p>3.0 版本之前,OpenFOAM 的单相流求解器如 pisoFoam 的动量方程中调用的是湍流模型的 <code>divDevReff</code> 函数来考虑雷诺应力项的作用。只是,细究起来,这个函数似乎有点小问题,本篇来探讨一下这些小问题。</p>]]>
</summary>
<category term="turbulence model" scheme="http://xiaopingqiu.github.io/tags/turbulence-model/"/>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/categories/OpenFOAM/"/>
</entry>
<entry>
<title><![CDATA[LIGGGHTS tips]]></title>
<link href="http://xiaopingqiu.github.io/2016/05/03/liggghts-howto/"/>
<id>http://xiaopingqiu.github.io/2016/05/03/liggghts-howto/</id>
<published>2016-05-03T04:38:31.000Z</published>
<updated>2016-05-25T12:49:30.143Z</updated>
<content type="html"><![CDATA[<p>本篇介绍几个 LIGGGHTS 技巧,read_data,freeze,move,modify_timing,neigh_modify。</p>
<a id="more"></a>
<p>LIGGGHTS 中可以用 STL 格式的几何面来模拟复杂边界的问题。如果想用冻结粒子当作壁面,可以采用如下方法。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">read</span>_data test.dat</span><br><span class="line"></span><br><span class="line">group Par_wall id <> <span class="number">1</span> <span class="number">1000</span> </span><br><span class="line">fix fr Par_wall freeze</span><br></pre></td></tr></table></figure></p>
<p>上述代码中,第一行是从外部文件中读取颗粒的信息;第二行是将ID在 1 到 1000 的粒子放到一个 group 里;第三行是将 Par_wall 这个 group 里的粒子冻结起来,具体的操作其实是将这些粒子的力归零,这样粒子将保持最初始的速度。如果将壁面粒子预先生成好,并将其初始速度设置为 0,便可以实现冻结粒子壁面了。</p>
<p>test.data 文件的数据格式如下,每一列数据的含义见注释:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">LAMMPS data file via write_data, version Version LIGGGHTS-PUBLIC <span class="number">3.2</span>.<span class="number">0</span>, git commit <span class="number">6</span>de550fbf3b8451f51246aa3c76374012e935340 based on LAMMPS <span class="number">23</span> Nov <span class="number">2013</span>, timestep = <span class="number">0</span> <span class="comment">## 第一行随便是什么</span></span><br><span class="line"></span><br><span class="line"><span class="number">5</span> atoms <span class="comment">## 颗粒数</span></span><br><span class="line"><span class="number">1</span> atom types <span class="comment">## 颗粒的 type 数</span></span><br><span class="line"></span><br><span class="line"><span class="comment">## 模拟区域的大小</span></span><br><span class="line">-<span class="number">5.0009999999999999</span>e-<span class="number">01</span> <span class="number">5.0009999999999999</span>e-<span class="number">01</span> xlo xhi</span><br><span class="line">-<span class="number">2.0004000000000002</span>e-<span class="number">01</span> <span class="number">2.0004000000000002</span>e-<span class="number">01</span> ylo yhi</span><br><span class="line">-<span class="number">2.0005500000000001</span>e-<span class="number">01</span> <span class="number">3.4999999999999998</span>e-<span class="number">01</span> zlo zhi</span><br><span class="line"></span><br><span class="line">Atoms</span><br><span class="line"><span class="comment">#id type diameter density x y z i j k</span></span><br><span class="line"><span class="number">1</span> <span class="number">1</span> <span class="number">2.9999999999999999</span>e-<span class="number">02</span> <span class="number">2.5000000000000005</span>e+<span class="number">03</span> -<span class="number">2.9626205235821884</span>e-<span class="number">01</span> -<span class="number">1.7191257603378007</span>e-<span class="number">01</span> -<span class="number">5.2585560979625336</span>e-<span class="number">02</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span></span><br><span class="line"><span class="number">2</span> <span class="number">1</span> <span class="number">2.9999999999999999</span>e-<span class="number">02</span> <span class="number">2.5000000000000005</span>e+<span class="number">03</span> -<span class="number">3.1357080694177836</span>e-<span class="number">01</span> -<span class="number">8.1292507237863978</span>e-<span class="number">02</span> -<span class="number">3.0941241635135643</span>e-<span class="number">02</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span></span><br><span class="line"><span class="number">3</span> <span class="number">1</span> <span class="number">2.9999999999999999</span>e-<span class="number">02</span> <span class="number">2.5000000000000005</span>e+<span class="number">03</span> -<span class="number">3.4986005571676082</span>e-<span class="number">01</span> -<span class="number">4.6564797686740017</span>e-<span class="number">02</span> -<span class="number">5.0161637377833301</span>e-<span class="number">02</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span></span><br><span class="line"><span class="number">4</span> <span class="number">1</span> <span class="number">2.9999999999999999</span>e-<span class="number">02</span> <span class="number">2.5000000000000005</span>e+<span class="number">03</span> -<span class="number">3.2901105748658366</span>e-<span class="number">01</span> <span class="number">1.1629149478965480</span>e-<span class="number">01</span> -<span class="number">2.8537062345934828</span>e-<span class="number">02</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span></span><br><span class="line"><span class="number">5</span> <span class="number">1</span> <span class="number">5.0000000000000003</span>e-<span class="number">02</span> <span class="number">2.5000000000000000</span>e+<span class="number">03</span> -<span class="number">3.9692279707164302</span>e-<span class="number">01</span> <span class="number">1.5000972515153915</span>e-<span class="number">01</span> -<span class="number">3.5647118241865984</span>e-<span class="number">02</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Velocities <span class="comment">## 如果粒子的初始速度为零,这一段可以删去。</span></span><br><span class="line"><span class="comment">#id vx vy vz omegax omegay omegaz</span></span><br><span class="line"><span class="number">1</span> -<span class="number">1.5290519507823870</span>e+<span class="number">00</span> <span class="number">1.0245516532619933</span>e-<span class="number">01</span> -<span class="number">1.1594445288149451</span>e+<span class="number">00</span> <span class="number">6.3791250045904881</span>e+<span class="number">00</span> <span class="number">2.0674456758001139</span>e+<span class="number">02</span> <span class="number">1.0276923966595568</span>e+<span class="number">02</span></span><br><span class="line"><span class="number">2</span> -<span class="number">2.1385398568904033</span>e+<span class="number">00</span> -<span class="number">1.8858415304542153</span>e-<span class="number">01</span> -<span class="number">9.4897293591801291</span>e-<span class="number">01</span> <span class="number">1.2732686070189061</span>e+<span class="number">01</span> <span class="number">1.9114652955524940</span>e+<span class="number">02</span> -<span class="number">4.8862922016708987</span>e+<span class="number">00</span></span><br><span class="line"><span class="number">3</span> -<span class="number">2.1931823490540205</span>e+<span class="number">00</span> <span class="number">1.2314081721772643</span>e-<span class="number">01</span> -<span class="number">1.1305039942880526</span>e+<span class="number">00</span> -<span class="number">7.7211996358126047</span>e+<span class="number">00</span> <span class="number">1.8655504536271400</span>e+<span class="number">02</span> -<span class="number">3.5674698533544941</span>e+<span class="number">01</span></span><br><span class="line"><span class="number">4</span> -<span class="number">2.3661710510727509</span>e+<span class="number">00</span> <span class="number">6.5301832663338024</span>e-<span class="number">03</span> -<span class="number">9.2367025774174294</span>e-<span class="number">01</span> -<span class="number">5.7926985652143115</span>e-<span class="number">01</span> <span class="number">1.7594397127744105</span>e+<span class="number">02</span> <span class="number">6.1151183183219171</span>e+<span class="number">00</span></span><br><span class="line"><span class="number">5</span> -<span class="number">2.6032940321288258</span>e+<span class="number">00</span> <span class="number">1.7791968545582579</span>e-<span class="number">01</span> -<span class="number">1.0893683893889663</span>e+<span class="number">00</span> -<span class="number">1.6450273309025711</span>e+<span class="number">01</span> <span class="number">6.8599979334439681</span>e+<span class="number">01</span> <span class="number">3.4617478295022179</span>e+<span class="number">00</span></span><br></pre></td></tr></table></figure></p>
<p>上述能实现静止的壁面,如果希望用粒子来实现运动壁面(比如旋转),则可以用 move 命令:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">group rotateWall id <> <span class="number">1001</span> <span class="number">2000</span> <span class="comment"># 将 1001 <= id <= 2000 的粒子放到 group rotateWall 里</span></span><br><span class="line">fix mov rotateWall move rotate -<span class="number">19.8</span> <span class="number">0</span> <span class="number">0</span> <span class="number">1</span> <span class="number">0</span> <span class="number">0</span> <span class="number">8</span></span><br></pre></td></tr></table></figure></p>
<p>move 命令有不同的模式,这里用的是 rotate,用这个命令以后,rotateWall 这个 group 里的粒子,将按照指定的参数来进行旋转运动,而不再是根据其受力来更新速度和位置。参数的含义分别为:起始点坐标(x,y,z);旋转轴的指向(x,y,z);周期(转一圈的时间)。</p>
<p>最后再介绍几个小 tips:</p>
<ol>
<li>有时候想知道程序中哪一部分耗时最多,并据此来优化程序,这时可以在输入脚本的最开头,添加一句 modify_timing on ,之后在程序运行结束后会统计出每一条 fix 命令的耗时信息。</li>
<li>上述提到的冻结粒子壁面,在使用中会有一个问题:壁面粒子之间的距离通常是很小的,在建立粒子碰撞对的时候,壁面粒子之间通常会形成碰撞对,但壁面粒子之间没必要建立碰撞对,如果壁面粒子很多,这个建立过程是很耗时的。这种情况下,可以通过修改 neigh_modify 命令的参数来防止壁面粒子之间建立碰撞对:<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">neigh_modify delay <span class="number">0</span> exclude group Par_wall Par_wall</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>这条命令将防止在 Par_wall 这个 group 里的粒子彼此之间建立碰撞对。</p>
]]></content>
<summary type="html">
<![CDATA[<p>本篇介绍几个 LIGGGHTS 技巧,read_data,freeze,move,modify_timing,neigh_modify。</p>]]>
</summary>
<category term="LIGGGHTS" scheme="http://xiaopingqiu.github.io/tags/LIGGGHTS/"/>
<category term="DEM" scheme="http://xiaopingqiu.github.io/categories/DEM/"/>
</entry>
<entry>
<title><![CDATA[OpenFOAM 中的壁面函数(四)]]></title>
<link href="http://xiaopingqiu.github.io/2016/04/25/wallFunctions4/"/>
<id>http://xiaopingqiu.github.io/2016/04/25/wallFunctions4/</id>
<published>2016-04-24T16:43:40.000Z</published>
<updated>2016-04-25T03:14:35.521Z</updated>
<content type="html"><![CDATA[<p>这篇来看看可能是最关键的 $\nu_t$ 的壁面函数。</p>
<a id="more"></a>
<h5 id="5-_湍流粘度_$\nu_t$_的壁面函数">5. 湍流粘度 $\nu_t$ 的壁面函数</h5><p>这个类型的壁面函数,结构比较简单,计算的是每一个壁面边界面上的湍流粘度 $\nu_t$。<br><code>nutWallFunction</code> 是虚基类,其中定义了一个纯虚函数 <code>calcNut</code><br><figure class="highlight cs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">virtual</span> tmp<scalarField> <span class="title">calcNut</span><span class="params">()</span> <span class="keyword">const</span> </span>= <span class="number">0</span>;</span><br></pre></td></tr></table></figure></p>
<p>并且在 <code>updateCoeffs</code> 函数中,将 <code>calcNut</code> 的返回值赋值给边界面<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span> nutWallFunctionFvPatchScalarField::updateCoeffs()</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (updated())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">operator</span>==(calcNut());</span><br><span class="line"></span><br><span class="line"> fixedValueFvPatchScalarField::updateCoeffs();</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这样,在具体的那些计算 $\nu_t$ 的壁面函数中,只需要看 <code>calcNut</code> 的返回值就可以了。</p>
<ul>
<li>(1). nutkWallFunction<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">tmp<scalarField> nutkWallFunctionFvPatchScalarField::calcNut() <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">label</span> patchi = patch().<span class="literal">index</span>();</span><br><span class="line"> <span class="keyword">const</span> turbulenceModel& turbModel =</span><br><span class="line"> <span class="keyword">db</span>().lookupObject<turbulenceModel>(<span class="string">"turbulenceModel"</span>);</span><br><span class="line"> <span class="keyword">const</span> scalarField& y = turbModel.<span class="literal">y</span>()[patchi];</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tk = turbModel.k();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& k = tk();</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnu = turbModel.nu();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& nu = tnu();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nuw = nu.boundaryField()[patchi];</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">scalar</span> Cmu25 = pow025(Cmu_);</span><br><span class="line"> tmp<scalarField> tnutw(new scalarField(patch().size(), 0.0));</span><br><span class="line"> scalarField& nutw = tnutw();</span><br><span class="line"> forAll(nutw, faceI)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">label</span> faceCellI = patch().faceCells()[faceI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">scalar</span> yPlus = Cmu25*y[faceI]*<span class="literal">sqrt</span>(k[faceCellI])/nuw[faceI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (yPlus > yPlusLam_)</span><br><span class="line"> {</span><br><span class="line"> nutw[faceI] = nuw[faceI]*(yPlus*kappa_/<span class="literal">log</span>(E_*yPlus) - 1.0);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> tnutw;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>这里,仍然是分情况处理<br><code>yPlus < yPlusLam_</code> 时,壁面上的 <code>nut</code> 设为0;<br><code>yPlus > yPlusLam_</code> 时<br>$$<br>\nu_t = \nu \cdot \left( \frac{\kappa y^+}{\ln(Ey^+)}-1 \right)<br>$$<br>这里实现的其实就是标准壁面函数。理论上讲,这里的计算只在粘性底层和对数区是有效的,所以,使用这个壁面条件的时候,要尽量壁面网格落在过渡区,否则可能会引入较大误差。</p>
<p>顺带提一下,这里还定义了一个 <code>yPlus</code> 函数,用来计算 $y^+$,这个函数在这里没有调用,不过在其他代码中需要 $y^+$ 的时候会调用这个函数。比如,计算 $y^+$ 的应用 <code>yPlusRAS</code> 就是调用这里的 <code>yPlus</code> 函数来计算 $y^+$。<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">tmp<scalarField> nutkWallFunctionFvPatchScalarField::yPlus() <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">label</span> patchi = patch().<span class="literal">index</span>();</span><br><span class="line"> <span class="keyword">const</span> turbulenceModel& turbModel =</span><br><span class="line"> <span class="keyword">db</span>().lookupObject<turbulenceModel>(<span class="string">"turbulenceModel"</span>);</span><br><span class="line"> <span class="keyword">const</span> scalarField& y = turbModel.<span class="literal">y</span>()[patchi];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tk = turbModel.k();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& k = tk();</span><br><span class="line"> tmp<scalarField> kwc = k.boundaryField()[patchi].patchInternalField();</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnu = turbModel.nu();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& nu = tnu();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nuw = nu.boundaryField()[patchi];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> pow025(Cmu_)*y*<span class="literal">sqrt</span>(kwc)/nuw;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<ul>
<li>(2). nutUWallFunction<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line">tmp<scalarField> nutUWallFunctionFvPatchScalarField::calcNut() <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">label</span> patchi = patch().<span class="literal">index</span>();</span><br><span class="line"> <span class="keyword">const</span> turbulenceModel& turbModel =</span><br><span class="line"> <span class="keyword">db</span>().lookupObject<turbulenceModel>(<span class="string">"turbulenceModel"</span>);</span><br><span class="line"> <span class="keyword">const</span> fvPatchVectorField& Uw = turbModel.<span class="keyword">U</span>().boundaryField()[patchi];</span><br><span class="line"> <span class="keyword">const</span> scalarField magUp(mag(Uw.patchInternalField() - Uw));</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnu = turbModel.nu();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& nu = tnu();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nuw = nu.boundaryField()[patchi];</span><br><span class="line"> tmp<scalarField> tyPlus = calcYPlus(magUp);</span><br><span class="line"> scalarField& yPlus = tyPlus();</span><br><span class="line"> tmp<scalarField> tnutw(new scalarField(patch().size(), 0.0));</span><br><span class="line"> scalarField& nutw = tnutw();</span><br><span class="line"></span><br><span class="line"> forAll(yPlus, facei)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (yPlus[facei] > yPlusLam_)</span><br><span class="line"> {</span><br><span class="line"> nutw[facei] =</span><br><span class="line"> nuw[facei]*(yPlus[facei]*kappa_/<span class="literal">log</span>(E_*yPlus[facei]) - 1.0);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> tnutw;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">tmp<scalarField> nutUWallFunctionFvPatchScalarField::calcYPlus</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> scalarField& magUp</span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">label</span> patchi = patch().<span class="literal">index</span>();</span><br><span class="line"> <span class="keyword">const</span> turbulenceModel& turbModel =</span><br><span class="line"> <span class="keyword">db</span>().lookupObject<turbulenceModel>(<span class="string">"turbulenceModel"</span>);</span><br><span class="line"> <span class="keyword">const</span> scalarField& y = turbModel.<span class="literal">y</span>()[patchi];</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnu = turbModel.nu();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& nu = tnu();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nuw = nu.boundaryField()[patchi];</span><br><span class="line"> tmp<scalarField> tyPlus(new scalarField(patch().size(), 0.0));</span><br><span class="line"> scalarField& yPlus = tyPlus();</span><br><span class="line"> forAll(yPlus, facei)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">scalar</span> kappaRe = kappa_*magUp[facei]*y[facei]/nuw[facei];</span><br><span class="line"> <span class="keyword">scalar</span> yp = yPlusLam_;</span><br><span class="line"> <span class="keyword">scalar</span> ryPlusLam = 1.0/yp;</span><br><span class="line"> int iter = 0;</span><br><span class="line"> <span class="keyword">scalar</span> yPlusLast = 0.0;</span><br><span class="line"> <span class="keyword">do</span></span><br><span class="line"> {</span><br><span class="line"> yPlusLast = yp;</span><br><span class="line"> yp = (kappaRe + yp)/(1.0 + <span class="literal">log</span>(E_*yp));</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">while</span> (mag(ryPlusLam*(yp - yPlusLast)) > 0.01 && ++iter < 10 );</span><br><span class="line"></span><br><span class="line"> yPlus[facei] = <span class="literal">max</span>(0.0, yp);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> tyPlus;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>这个壁函数的 $y^+$ 的计算方式跟 <code>nutkWallFunction</code> 有点区别。经过摸索,这里 <code>calcYPlus</code> 函数中的那段 <code>do ... while</code> 循环的原理如下:<br>对数律可以表达如下:<br>$$<br>U^+ = \frac{U_p}{u_\tau}=\frac{1}{\kappa}\ln(Ey^+)<br>$$<br>其中 $U_p$ 等于壁面上的速度减去壁面所属网格中心的速度。<br>经过简单变形<br>$$<br>\frac{U_p}{ y u_\tau/\nu }\cdot (y/\nu)=\frac{U_p}{ y^+}\cdot (y/\nu)=\frac{1}{\kappa}\ln(Ey^+)<br>$$<br>整理得<br>$$<br>y^+ \ln(Ey^+) - \frac{\kappa y U_p}{\nu}=0<br>$$<br>这是一个 $y^+$ 的一元方程,可以通过牛顿迭代来求解<br>$$<br>y^+_{n+1} = y^+_{n} - \frac{f(y^+)}{f^{\prime}(y+)} = y^+_{n}-\frac{y_n^+ \ln(Ey_n^+) - \frac{\kappa y U_p}{\nu}}{1+\ln(Ey_n^+)} = \frac{y_n^+ + \frac{\kappa y U_p}{\nu}}{1+\ln(Ey_n^+)}<br>$$<br>上面代码里的 <code>do ... while</code> 循环,正是在做这个迭代求解,初始值选择的是 <code>yPlusLam</code>,这个值在前面提过了。<br>求出 $y^+$ 以后,$\nu_t$ 计算如下<br>$$<br>\nu_t = \nu \cdot \left( \frac{\kappa y^+}{\ln(Ey^+)}-1 \right)<br>$$<br>与 <code>nutkWallFunction</code> 形式是一样的。</p>
<p>这个壁面函数,求壁面上的 $\nu_t$ 时使用的对数律方程,所以,理论上这个壁面函数应该只适用于第一层网格落在对数层的情形。</p>
<ul>
<li>(3). nutLowReWallFunction<br>这个壁面函数直接将壁面上的 $\nu_t$ 的值设为0。<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">tmp</span><<span class="tag">scalarField</span>> <span class="rule"><span class="attribute">nutLowReWallFunctionFvPatchScalarField</span>:<span class="value">:<span class="function">calcNut</span>() const</span><br><span class="line">{</span><br><span class="line"> return tmp<scalarField>(new <span class="function">scalarField</span>(<span class="function">patch</span>().<span class="function">size</span>(), <span class="number">0.0</span>))</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>$y^+$ 的计算也值得注意:<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">tmp<scalarField> nutLowReWallFunctionFvPatchScalarField::yPlus() <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">label</span> patchi = patch().<span class="literal">index</span>();</span><br><span class="line"> <span class="keyword">const</span> turbulenceModel& turbModel =</span><br><span class="line"> <span class="keyword">db</span>().lookupObject<turbulenceModel>(<span class="string">"turbulenceModel"</span>);</span><br><span class="line"> <span class="keyword">const</span> scalarField& y = turbModel.<span class="literal">y</span>()[patchi];</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnu = turbModel.nu();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& nu = tnu();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nuw = nu.boundaryField()[patchi];</span><br><span class="line"> <span class="keyword">const</span> fvPatchVectorField& Uw = turbModel.<span class="keyword">U</span>().boundaryField()[patchi];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> y*<span class="literal">sqrt</span>(nuw*mag(Uw.snGrad()))/nuw;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>$$<br>y^+ = \frac{y\sqrt{\nu \cdot |\frac{U_w-U_c}{d}|}}{\nu}<br>$$<br>注意由于 $\nu_t = 0$ ,所以 $\frac{\tau_w}{\rho} = \nu \cdot |\frac{U_w-U_c}{d}|$,所以,$\sqrt{\nu \cdot |\frac{U_w-U_c}{d}|}=\sqrt{\frac{\tau_w}{\rho}}=u_\tau$ 。</p>
<ul>
<li>(4). nutUSpaldingWallFunction<br>这个壁函数基于 Spalding 提出的一个拟合的 $y^+$ 与 $u^+$ 的关系式,见文献 <em>A Single Formula for the “Law of the Wall” </em> 。<br>$$<br>y^+ = u^+ + \frac{1}{E}\left[ e^{\kappa u^+} -1-\kappa u^+ -\frac{1}{2}(\kappa u^+)^2 - \frac{1}{6}(\kappa u^+)^3 \right]<br>$$<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line">tmp<scalarField> nutUSpaldingWallFunctionFvPatchScalarField::calcNut() <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">label</span> patchI = patch().<span class="literal">index</span>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> turbulenceModel& turbModel =</span><br><span class="line"> <span class="keyword">db</span>().lookupObject<turbulenceModel>(<span class="string">"turbulenceModel"</span>);</span><br><span class="line"> <span class="keyword">const</span> fvPatchVectorField& Uw = turbModel.<span class="keyword">U</span>().boundaryField()[patchI];</span><br><span class="line"> <span class="keyword">const</span> scalarField magGradU(mag(Uw.snGrad()));</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnu = turbModel.nu();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& nu = tnu();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nuw = nu.boundaryField()[patchI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">max</span></span><br><span class="line"> (</span><br><span class="line"> <span class="literal">scalar</span>(0),</span><br><span class="line"> sqr(calcUTau(magGradU))/(magGradU + ROOTVSMALL) - nuw</span><br><span class="line"> );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">tmp<scalarField> nutUSpaldingWallFunctionFvPatchScalarField::calcUTau</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> scalarField& magGradU</span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">label</span> patchI = patch().<span class="literal">index</span>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> turbulenceModel& turbModel =</span><br><span class="line"> <span class="keyword">db</span>().lookupObject<turbulenceModel>(<span class="string">"turbulenceModel"</span>);</span><br><span class="line"> <span class="keyword">const</span> scalarField& y = turbModel.<span class="literal">y</span>()[patchI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> fvPatchVectorField& Uw = turbModel.<span class="keyword">U</span>().boundaryField()[patchI];</span><br><span class="line"> <span class="keyword">const</span> scalarField magUp(mag(Uw.patchInternalField() - Uw));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnu = turbModel.nu();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& nu = tnu();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nuw = nu.boundaryField()[patchI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> scalarField& nutw = *this;</span><br><span class="line"></span><br><span class="line"> tmp<scalarField> tuTau(new scalarField(patch().size(), 0.0));</span><br><span class="line"> scalarField& uTau = tuTau();</span><br><span class="line"></span><br><span class="line"> forAll(uTau, faceI)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">scalar</span> ut = <span class="literal">sqrt</span>((nutw[faceI] + nuw[faceI])*magGradU[faceI]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ut > ROOTVSMALL)</span><br><span class="line"> {</span><br><span class="line"> int iter = 0;</span><br><span class="line"> <span class="keyword">scalar</span> <span class="keyword">err</span> = GREAT;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">do</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">scalar</span> kUu = <span class="literal">min</span>(kappa_*magUp[faceI]/ut, 50);</span><br><span class="line"> <span class="keyword">scalar</span> fkUu = <span class="literal">exp</span>(kUu) - 1 - kUu*(1 + 0.5*kUu);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">scalar</span> f =</span><br><span class="line"> - ut*y[faceI]/nuw[faceI]</span><br><span class="line"> + magUp[faceI]/ut</span><br><span class="line"> + 1/E_*(fkUu - 1.0/6.0*kUu*sqr(kUu));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">scalar</span> df =</span><br><span class="line"> y[faceI]/nuw[faceI]</span><br><span class="line"> + magUp[faceI]/sqr(ut)</span><br><span class="line"> + 1/E_*kUu*fkUu/ut;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">scalar</span> uTauNew = ut + f/df;</span><br><span class="line"> <span class="keyword">err</span> = mag((ut - uTauNew)/ut);</span><br><span class="line"> ut = uTauNew;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">while</span> (ut > ROOTVSMALL && <span class="keyword">err</span> > 0.01 && ++iter < 10);</span><br><span class="line"></span><br><span class="line"> uTau[faceI] = <span class="literal">max</span>(0.0, ut);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> tuTau;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p><code>calcUtau</code> 函数,其实是在用牛顿法迭代求解 $y^+$,进而得到 $u_\tau$ 的值。<code>calcNut</code> 函数中<br>$$<br>\frac{u_\tau ^2}{|\frac{U_w-U_c}{d}|} - \nu = \frac{\tau_w}{|\frac{U_w-U_c}{d}|} -\nu = \nu_{eff} - \nu = \nu_t<br>$$</p>
<p>这个壁面函数使用的是从粘性底层连续变化到对数层的 $y^+ \text{-} u^+$ 关系式,所以,这个可以认为是网格无关的,即不管第一层网格落在哪个区,都是有效的。如果网格无法做到全部位于粘性层或者对数区,建议用这个壁面条件。</p>
<ul>
<li>(5). nutUTabulatedWallFunction</li>
</ul>
<p>这个壁面函数,需要从外部读取一个 $U^+ \text{-}\,Re_y$ 数据表,通过从这个数据表插值来得到 $U^+$ 的值。其中 $Re_y=yU/\nu$ 。<br><figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 构造函数</span></span><br><span class="line">nutUTabulatedWallFunctionFvPatchScalarField::</span><br><span class="line">nutUTabulatedWallFunctionFvPatchScalarField</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> fvPatch& p,</span><br><span class="line"> <span class="keyword">const</span> DimensionedField<scalar, volMesh>& iF,</span><br><span class="line"> <span class="keyword">const</span> dictionary& dict</span><br><span class="line">)</span><br><span class="line">:</span><br><span class="line"> nutWallFunctionFvPatchScalarField(p, iF, dict),</span><br><span class="line"> uPlusTableName_(dict.lookup(<span class="string">"uPlusTable"</span>)),</span><br><span class="line"> uPlusTable_</span><br><span class="line"> (</span><br><span class="line"> IOobject</span><br><span class="line"> (</span><br><span class="line"> uPlusTableName_,</span><br><span class="line"> patch().boundaryMesh().mesh().time().constant(),</span><br><span class="line"> patch().boundaryMesh().mesh(),</span><br><span class="line"> IOobject::MUST_READ_IF_MODIFIED,</span><br><span class="line"> IOobject::NO_WRITE,</span><br><span class="line"> <span class="keyword">false</span></span><br><span class="line"> ),</span><br><span class="line"> <span class="keyword">true</span></span><br><span class="line"> )</span><br><span class="line">{}</span><br></pre></td></tr></table></figure></p>
<p>$U^+$ 和 $\nu_t$ 分别由函数 <code>calcUPlus</code> 和 <code>calcNut</code> 来计算。</p>
<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line">tmp<scalarField> nutUTabulatedWallFunctionFvPatchScalarField::calcNut() <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">label</span> patchi = patch().<span class="literal">index</span>();</span><br><span class="line"> <span class="keyword">const</span> turbulenceModel& turbModel =</span><br><span class="line"> <span class="keyword">db</span>().lookupObject<turbulenceModel>(<span class="string">"turbulenceModel"</span>);</span><br><span class="line"> <span class="keyword">const</span> scalarField& y = turbModel.<span class="literal">y</span>()[patchi];</span><br><span class="line"> <span class="keyword">const</span> fvPatchVectorField& Uw = turbModel.<span class="keyword">U</span>().boundaryField()[patchi];</span><br><span class="line"> <span class="keyword">const</span> scalarField magUp(mag(Uw.patchInternalField() - Uw));</span><br><span class="line"> <span class="keyword">const</span> scalarField magGradU(mag(Uw.snGrad()));</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnu = turbModel.nu();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& nu = tnu();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nuw = nu.boundaryField()[patchi];</span><br><span class="line"> <span class="literal">return</span></span><br><span class="line"> <span class="literal">max</span></span><br><span class="line"> (</span><br><span class="line"> <span class="literal">scalar</span>(0),</span><br><span class="line"> sqr(magUp/(calcUPlus(magUp*y/nuw) + ROOTVSMALL))</span><br><span class="line"> /(magGradU + ROOTVSMALL)</span><br><span class="line"> - nuw</span><br><span class="line"> );</span><br><span class="line"> <span class="comment">// magUp/UPlus = utau, sqr(utau) = tauw, tauw/magGradU = nuEff = nut + nu</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">tmp<scalarField> nutUTabulatedWallFunctionFvPatchScalarField::calcUPlus</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> scalarField& Rey</span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> tmp<scalarField> tuPlus(new scalarField(patch().size(), 0.0));</span><br><span class="line"> scalarField& uPlus = tuPlus();</span><br><span class="line"> forAll(uPlus, faceI)</span><br><span class="line"> {</span><br><span class="line"> uPlus[faceI] = uPlusTable_.interpolateLog10(Rey[faceI]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> tuPlus;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>注意这里 <code>calcUPlus</code> 用的是 <code>interpolateLog10</code> 函数来插值,这个函数的定义为<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">template<<span class="keyword">class</span> <span class="keyword">Type</span>></span><br><span class="line"><span class="keyword">Type</span> Foam::uniformInterpolationTable<<span class="keyword">Type</span>>::interpolateLog10</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">scalar</span> x</span><br><span class="line">) <span class="keyword">const</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (log10_)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (x > 0)</span><br><span class="line"> {</span><br><span class="line"> x = ::<span class="literal">log10</span>(x);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (bound_ && (x <= 0))</span><br><span class="line"> {</span><br><span class="line"> x = x0_;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> FatalErrorIn</span><br><span class="line"> (</span><br><span class="line"> <span class="string">"uniformInterpolationTable<Type>::interpolateLog10(scalar x)"</span></span><br><span class="line"> ) << <span class="string">"Table "</span> << name() << <span class="keyword">nl</span></span><br><span class="line"> << <span class="string">"Supplied value must be greater than 0 when in log10 mode"</span></span><br><span class="line"> << <span class="keyword">nl</span> << <span class="string">"x="</span> << x << <span class="keyword">nl</span> << <span class="keyword">exit</span>(FatalError);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> interpolate(x); <span class="comment">// 这个是普通的线性插值函数</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>即计算 <code>x</code> 的对数(log10),在将计算结果用来进行线性插值。所以,用这个壁面函数的时候,要注意你所提供的数据表是普通线性坐标的还是对数坐标的。</p>
<p>基本上常见的处理壁面上的湍流粘度的方法就是以上几种了。OpenFOAM 中还提供了几个能处理粗糙壁面的壁面函数( <code>nutURoughWallFunction</code> , <code>nutkRoughWallFunction</code> ),以及处理大气层边界的(<code>nutkAtmRoughWallFunction</code>,需要跟 <code>atmBoundaryLayerInletVelocity</code> 这个入口边界配合使用 ),细节这里不再详述了,有需要时可以去看相关代码,代码结构是类似的,只是具体计算公式不一样。</p>
]]></content>
<summary type="html">
<![CDATA[<p>这篇来看看可能是最关键的 $\nu_t$ 的壁面函数。</p>]]>
</summary>
<category term="Code Explained" scheme="http://xiaopingqiu.github.io/tags/Code-Explained/"/>
<category term="wall functions" scheme="http://xiaopingqiu.github.io/tags/wall-functions/"/>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/categories/OpenFOAM/"/>
</entry>
<entry>
<title><![CDATA[OpenFOAM 中的壁面函数(三)]]></title>
<link href="http://xiaopingqiu.github.io/2016/04/25/wallFunctions3/"/>
<id>http://xiaopingqiu.github.io/2016/04/25/wallFunctions3/</id>
<published>2016-04-24T16:43:34.000Z</published>
<updated>2016-04-25T03:05:53.080Z</updated>
<content type="html"><![CDATA[<p>这篇来看看计算湍动能 $\varepsilon$ 和 $\omega$ 的壁面函数。</p>
<a id="more"></a>
<h5 id="3-_湍动能耗散_$\varepsilon$_的壁面函数">3. 湍动能耗散 $\varepsilon$ 的壁面函数</h5><p>本篇来看看 OpenFOAM 中的 <code>epsilonWallFunction</code>,共有两个: <code>epsilonWallFunction</code> 和 <code>epsilonLowReWallFunction</code>。</p>
<ul>
<li>(1). epsilonWallFunction</li>
</ul>
<p><code>epsilonWallFunction</code> 代码比前面的 <code>kqRWallFunction</code> 复杂多了,主要原因在于这里需要得到的是 <code>epsilon</code> 在临近网格的值,而且,需要考虑包含两个边界面的网格。这里先来梳理代码的脉络,然后再看具体的计算细节。<br>外部调用的主要是 <code>updateCoeffs()</code> 函数,所以,从这个函数看起。<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span> epsilonWallFunctionFvPatchScalarField::updateCoeffs()</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (updated())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">const</span> turbulenceModel& turbulence =</span><br><span class="line"> db().lookupObject<turbulenceModel>(turbulenceModel::typeName);</span><br><span class="line"></span><br><span class="line"> setMaster();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (patch().index() == master_)</span><br><span class="line"> {</span><br><span class="line"> createAveragingWeights();</span><br><span class="line"> calculateTurbulenceFields(turbulence, G(<span class="keyword">true</span>), epsilon(<span class="keyword">true</span>));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">const</span> scalarField& G0 = <span class="keyword">this</span>->G();</span><br><span class="line"> <span class="keyword">const</span> scalarField& epsilon0 = <span class="keyword">this</span>->epsilon();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">typedef</span> DimensionedField<scalar, volMesh> FieldType;</span><br><span class="line"></span><br><span class="line"> FieldType& G =</span><br><span class="line"> <span class="keyword">const_cast</span><FieldType&></span><br><span class="line"> (</span><br><span class="line"> db().lookupObject<FieldType>(turbulence.GName())</span><br><span class="line"> );</span><br><span class="line"> <span class="comment">//这里是获取内部场,所以,修改这里的引用 "epsilon",相当于修改 epsilon 的内部场值。</span></span><br><span class="line"> FieldType& epsilon = <span class="keyword">const_cast</span><FieldType&>(dimensionedInternalField());</span><br><span class="line"></span><br><span class="line"> forAll(*<span class="keyword">this</span>, faceI)</span><br><span class="line"> {</span><br><span class="line"> label cellI = patch().faceCells()[faceI];</span><br><span class="line"></span><br><span class="line"> G[cellI] = G0[cellI];</span><br><span class="line"> epsilon[cellI] = epsilon0[cellI];</span><br><span class="line"> }</span><br><span class="line"> fvPatchField<scalar>::updateCoeffs();</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p> 一步一步来看。首先是调用了 <code>setMaster()</code> 函数,来看看这个函数以及相关的一个函数 <code>epsilonPatch</code> 的代码:<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span> epsilonWallFunctionFvPatchScalarField::setMaster()</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (master_ != -<span class="number">1</span>) <span class="comment">// 如果当前处理的边界的 master_ != -1,说明它已被处理过,直接返回</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">const</span> volScalarField& epsilon =</span><br><span class="line"> <span class="keyword">static_cast</span><<span class="keyword">const</span> volScalarField&>(<span class="keyword">this</span>->dimensionedInternalField());</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> volScalarField::GeometricBoundaryField& bf = epsilon.boundaryField();</span><br><span class="line"></span><br><span class="line"> label master = -<span class="number">1</span>;</span><br><span class="line"> forAll(bf, patchI)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (isA<epsilonWallFunctionFvPatchScalarField>(bf[patchI]))</span><br><span class="line"> {</span><br><span class="line"> epsilonWallFunctionFvPatchScalarField& epf = epsilonPatch(patchI);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (master == -<span class="number">1</span>) <span class="comment">// 只有头一个被处理的边界满足这个条件</span></span><br><span class="line"> {</span><br><span class="line"> master = patchI;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> epf.master() = master; <span class="comment">// 这意味着所有边界的 master_ 数据成员都将赋值为头一个被处理的边界的编号,即第一个被处理的边界是master</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">epsilonWallFunctionFvPatchScalarField&</span><br><span class="line">epsilonWallFunctionFvPatchScalarField::epsilonPatch(<span class="keyword">const</span> label patchI)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">const</span> volScalarField& epsilon =</span><br><span class="line"> <span class="keyword">static_cast</span><<span class="keyword">const</span> volScalarField&>(<span class="keyword">this</span>->dimensionedInternalField());</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> volScalarField::GeometricBoundaryField& bf = epsilon.boundaryField();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> epsilonWallFunctionFvPatchScalarField& epf =</span><br><span class="line"> refCast<<span class="keyword">const</span> epsilonWallFunctionFvPatchScalarField>(bf[patchI]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">const_cast</span><epsilonWallFunctionFvPatchScalarField&>(epf);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p> 从上述代码可以看出, <code>epsilonPatch</code> 函数需要一个参数,这个参数的含义是某一个边界的序号,返回的是指向这个边界的一个 <code>epsilonWallFunctionFvPatchScalarField</code> 类型的引用。<br>在此基础上,再来看 <code>setMaster</code>。先判断当前边界的数据成员 <code>master_</code> 是否不等于-1,如果成立则不做任何操作,直接返回;否则,先获取到 <code>epsilon</code> 的所有边界,存在变量 <code>bf</code> 中,然后,遍历 <code>bf</code> ,如果边界的类型是 <code>epsilonWallFunctionFvPatchScalarField</code>,则判断临时变量 <code>master</code> 是否等于 <code>-1</code>,等于则将边界的序号 <code>patchI</code> 赋值给 <code>master</code>,并临时变量 <code>master</code> 的值赋给 <code>patchI</code> 对应边界的数据成员 <code>master_</code>。 举个例子,假设有一个算例,有两个边界上使用了 <code>epsilonWallFunctionFvPatchScalarField</code> 类型的边界条件,两个边界的编号分别是 <code>patchI = 0</code> 和 <code>patchI = 1</code>。则在上述循环过程中,当 <code>patchI = 0</code>时, <code>master == -1</code> 肯定成立。于是,<code>patchI = 0</code> 对应边界的数据成员 <code>master_</code> 被赋值为0;而当遍历到 <code>patchI = 1</code> 时, 此时<code>master = 0</code>,所以,结果是 <code>patchI = 1</code> 的边界的数据成员 <code>master_</code> 也被赋值为0。 </p>
<p> 继续向下看,如果 <code>patch.index() == master_</code> ,则调用两个函数。这个怎么理解呢?还以上面的那个简单例子来说明。注意,在外部调用边界条件的时候,也是会依次调用一个场的所有边界的边界条件的。在这里的简单例子中,有两个边界的类型是 <code>epsilonWallFunctionFvPatchScalarField</code> ,所以,我们假设调用 <code>patchI = 0</code> 对应的边界时,由于初始化时数据成员 <code>master_</code> 赋值为 <code>-1</code> ,所以,调用 <code>patchI = 0</code> 的边界时, <code>setMaster</code> 函数中的操作会进行。而根据上面的分析,调用 <code>patchI = 0</code> 的边界时, <code>setMaster</code> 函数同时也将 <code>patchI = 1</code> 边界的数据成员 <code>master_</code> 赋值为 <code>0</code>了,所以,在外部调用 <code>patchI = 1</code> 的边界时, <code>setMaster</code> 函数将不作任何操作,直接返回。同样的,在外部调用 <code>patchI = 0</code> 的边界时,<code>patch.index() == master_</code> 条件是成立的,所以 <code>createAveragingWeights()</code> 和 <code>calculateTurbulenceFields(turbulence, G(true), epsilon(true));</code> 两个语句将会执行;而在外部调用 <code>patchI = 1</code> 边界时,由于 <code>patch.index() == master_</code> 不成立,这两个语句将不执行。</p>
<p> 再继续往前看, <code>const scalarField& G0 = this->G(); const scalarField& epsilon0 = this->epsilon();</code> ,这里是将成员函数 <code>G</code> 和 <code>epsilon</code> 的返回值分别赋给变量 <code>G0</code> 和 <code>epsilon0</code>。开看一下成员函数的定义<br><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">scalarField& epsilonWallFunctionFvPatchScalarField::<span class="type">G</span>(bool <span class="keyword">init</span>)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (patch().index() == master_) <span class="comment">// 只有头一个被处理的边界满足这个条件</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">init</span>) <span class="comment">// init 缺省值是 false </span></span><br><span class="line"> {</span><br><span class="line"> <span class="type">G_</span> = <span class="number">0.0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="type">G_</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> epsilonPatch(master_).<span class="type">G</span>(); <span class="comment">// 对于不是 master 的边界,返回master边界的数据成员 G_</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">scalarField& epsilonWallFunctionFvPatchScalarField::epsilon(bool <span class="keyword">init</span>)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (patch().index() == master_)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">init</span>)</span><br><span class="line"> {</span><br><span class="line"> epsilon_ = <span class="number">0.0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> epsilon_;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> epsilonPatch(master_).epsilon(<span class="keyword">init</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>类似的,对于 <code>patchI = 0</code>, <code>patch().index() == master_</code> ,所以返回值为 <code>patchI = 0</code> 边界的数据成员 <code>G_</code> 或 <code>epsilon_</code> (<code>init</code> 的缺省值是 <code>false</code>);而对于 <code>patchI = 1</code>边界,返回的是 <code>patchI = master_</code> 对应边界的数据成员 <code>G_</code> 或 <code>epsilon_</code>,而根据上面的分析, <code>patchI= 1</code> 的边界的数据成员 <code>master_ = 0</code>,因此, <code>patchI = 1</code> 的边界的成员函数返回的是 <code>patchI = 0</code>边界的相应的数据成员。</p>
<p>再往下的内容就很简单了,只是将得到的 <code>G0</code> 和 <code>epsilon0</code> 的值分别赋给当前边界的临近边界网格而已。</p>
<p>到此,代码的框架就基本清晰了,小结一下就是,如果对于某个算例,有多个边界上需要用到 <code>epsilonWallFunctionFvPatchScalarField</code> 类型的边界条件,则,编号更小的那个边界将会被设置成 <code>master</code>。所有的相关计算都在调用 <code>master</code> 边界的时候进行,非 <code>master</code> 的边界,则只需要从 <code>master</code> 那里读取结果即可! </p>
<p>接下来看看外部调用 <code>master</code> 边界的时候,具体做了哪些计算,主要就是看 <code>createAveragingWeights()</code> 和 <code>calculateTurbulenceFields(turbulence, G(true), epsilon(true));</code> 这两条语句了。<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span> epsilonWallFunctionFvPatchScalarField::createAveragingWeights()</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">const</span> volScalarField& epsilon =</span><br><span class="line"> <span class="keyword">static_cast</span><<span class="keyword">const</span> volScalarField&>(<span class="keyword">this</span>->dimensionedInternalField());</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> volScalarField::GeometricBoundaryField& bf = epsilon.boundaryField();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> fvMesh& mesh = epsilon.mesh();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (initialised_ && !mesh.changing())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function">volScalarField <span class="title">weights</span></span><br><span class="line"> <span class="params">(</span><br><span class="line"> IOobject</span><br><span class="line"> (</span><br><span class="line"> "weights",</span><br><span class="line"> mesh.time()</span>.<span class="title">timeName</span><span class="params">()</span>,</span><br><span class="line"> mesh,</span><br><span class="line"> IOobject::NO_READ,</span><br><span class="line"> IOobject::NO_WRITE,</span><br><span class="line"> <span class="keyword">false</span> <span class="comment">// do not register</span></span><br><span class="line"> ),</span><br><span class="line"> mesh,</span><br><span class="line"> <span class="title">dimensionedScalar</span><span class="params">("zero", dimless, 0.0)</span></span><br><span class="line"> )</span>;</span><br><span class="line"></span><br><span class="line"> DynamicList<label> epsilonPatches(bf.size());</span><br><span class="line"> <span class="comment">//遍历所有边界,如果边界类型是 epsilonWallFunctionFvPatchScalarField 则将该边界放到 epsilonPatches 这个动态 list 中。</span></span><br><span class="line"> forAll(bf, patchI)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (isA<epsilonWallFunctionFvPatchScalarField>(bf[patchI]))</span><br><span class="line"> {</span><br><span class="line"> epsilonPatches.append(patchI);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> labelUList& faceCells = bf[patchI].patch().faceCells();</span><br><span class="line"> forAll(faceCells, i)</span><br><span class="line"> {</span><br><span class="line"> label cellI = faceCells[i];</span><br><span class="line"> <span class="comment">// weight 衡量的是网格cellI有多少个边界面使用了 epsilonWallFunctionFvPatchScalarField 类型的边界条件</span></span><br><span class="line"> weights[cellI]++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> cornerWeights_.setSize(bf.size());</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 遍历所有 epsilonWallFunctionFvPatchScalarField 类型的边界</span></span><br><span class="line"> forAll(epsilonPatches, i)</span><br><span class="line"> {</span><br><span class="line"> label patchI = epsilonPatches[i];</span><br><span class="line"> <span class="keyword">const</span> fvPatchScalarField& wf = weights.boundaryField()[patchI];</span><br><span class="line"> <span class="comment">//cornerWeights_存储的所有边界面的weight的倒数,边界面的weight等于其所属网格的weight。所以,如果有一个网格包含两个使用epsilonWallFunction的边界面,那么根据上面的计算,这个网格的weight将是 2,而这两个边界面的 cornerWeights_ 则都是 1/2。 </span></span><br><span class="line"> cornerWeights_[patchI] = <span class="number">1.0</span>/wf.patchInternalField();</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 将数据成员 G_ 和 epsilon_ 初始化为0</span></span><br><span class="line"> G_.setSize(dimensionedInternalField().size(), <span class="number">0.0</span>);</span><br><span class="line"> epsilon_.setSize(dimensionedInternalField().size(), <span class="number">0.0</span>);</span><br><span class="line"></span><br><span class="line"> initialised_ = <span class="keyword">true</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> epsilonWallFunctionFvPatchScalarField::calculateTurbulenceFields</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> turbulenceModel& turbulence,</span><br><span class="line"> scalarField& G0,</span><br><span class="line"> scalarField& epsilon0</span><br><span class="line">)</span><br><span class="line">{</span><br><span class="line"> <span class="comment">// accumulate all of the G and epsilon contributions</span></span><br><span class="line"> <span class="comment">//cornerWeights_ 是一个二维 list,这里是遍历这个list 的第一层</span></span><br><span class="line"> forAll(cornerWeights_, patchI)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (!cornerWeights_[patchI].empty()) <span class="comment">// 如果是empty,意味着这个对应的边界不是epsilonWallFunction类型,所以就不需要考虑</span></span><br><span class="line"> {</span><br><span class="line"> epsilonWallFunctionFvPatchScalarField& epf = epsilonPatch(patchI);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> List<scalar>& w = cornerWeights_[patchI];</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 非 empty 则调用 calculate 函数更新 G0 和 epsilon 的值</span></span><br><span class="line"> epf.calculate(turbulence, w, epf.patch(), G0, epsilon0);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// apply zero-gradient condition for epsilon</span></span><br><span class="line"> forAll(cornerWeights_, patchI)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (!cornerWeights_[patchI].empty())</span><br><span class="line"> {</span><br><span class="line"> epsilonWallFunctionFvPatchScalarField& epf = epsilonPatch(patchI);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 对 epsilon 使用 零梯度边界条件,即将上面计算得到的临近壁面网格的epsilon的值存储在壁面。</span></span><br><span class="line"> epf == scalarField(epsilon0, epf.patch().faceCells());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> epsilonWallFunctionFvPatchScalarField::calculate</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> turbulenceModel& turbulence,</span><br><span class="line"> <span class="keyword">const</span> List<scalar>& cornerWeights,</span><br><span class="line"> <span class="keyword">const</span> fvPatch& patch,</span><br><span class="line"> scalarField& G,</span><br><span class="line"> scalarField& epsilon</span><br><span class="line">)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">const</span> label patchI = patch.index();</span><br><span class="line"> <span class="keyword">const</span> scalarField& y = turbulence.y()[patchI];</span><br><span class="line"> <span class="keyword">const</span> scalar Cmu25 = pow025(Cmu_);</span><br><span class="line"> <span class="keyword">const</span> scalar Cmu75 = <span class="built_in">pow</span>(Cmu_, <span class="number">0.75</span>);</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tk = turbulence.k();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& k = tk();</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnu = turbulence.nu();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nuw = tnu().boundaryField()[patchI];</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnut = turbulence.nut();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& nut = tnut();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nutw = nut.boundaryField()[patchI];</span><br><span class="line"> <span class="keyword">const</span> fvPatchVectorField& Uw = turbulence.U().boundaryField()[patchI];</span><br><span class="line"> <span class="function"><span class="keyword">const</span> scalarField <span class="title">magGradUw</span><span class="params">(mag(Uw.snGrad()</span>))</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Set epsilon and G</span></span><br><span class="line"> 遍历参数 patch 对应的边界的每一个面</span><br><span class="line"> forAll(nutw, faceI)</span><br><span class="line"> {</span><br><span class="line"> label cellI = patch.faceCells()[faceI];</span><br><span class="line"> scalar w = cornerWeights[faceI];</span><br><span class="line"> </span><br><span class="line"> epsilon[cellI] += w*Cmu75*<span class="built_in">pow</span>(k[cellI], <span class="number">1.5</span>)/(kappa_*y[faceI]);</span><br><span class="line"> G[cellI] +=</span><br><span class="line"> w</span><br><span class="line"> *(nutw[faceI] + nuw[faceI])</span><br><span class="line"> *magGradUw[faceI]</span><br><span class="line"> *Cmu25*<span class="built_in">sqrt</span>(k[cellI])</span><br><span class="line"> /(kappa_*y[faceI]);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p><code>calculate</code> 函数中进行的是实际的计算过程,主要是更新了临近壁面网格的 <code>epsilon</code> 和 <code>G</code> 的值,计算公式如下:<br>$$<br>\varepsilon_c = \frac{1}{N} \sum_{f=i}^{N}\left( \frac{c_\mu^{3/4} k_C^{3/2}}{\kappa y_i}\right) \\<br>\text{相当于} \quad \quad \quad<br>\varepsilon ^+ = \frac{1}{\kappa y^+} \quad \quad \quad \quad \quad \quad \quad \quad \quad \quad \quad<br>$$</p>
<p>$$<br>G_c = \frac{1}{N} \sum_{f=i}^{N}\left( \frac{(\nu + \nu_t)\cdot |\tfrac{U_i-U_c}{d}|\cdot c_\mu^{1/4} k_C^{1/2}}{\kappa y_i}\right)<br>$$<br>这里的 <code>Uw.snGrad()</code> 是 <code>fvPatchFields<Type></code> 类的成员函数:<br><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">template<class <span class="constant">Type></span></span><br><span class="line"><span class="constant">Foam:</span><span class="symbol">:tmp<Foam</span><span class="symbol">:</span><span class="symbol">:Field<Type></span> > <span class="constant">Foam:</span><span class="symbol">:fvPatchField<Type></span><span class="symbol">:</span><span class="symbol">:snGrad</span>() const</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> patch<span class="constant">_</span>.deltaCoeffs()*(*this - patchInternalField());</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>公式中下标 <code>c</code> 表示临近边界的网格, <code>i</code> 表示网格 <code>c</code> 包含的某个边界面元。<code>y</code> 和 <code>d</code> 都表示边界面元所属网格中心到该面元的垂直距离。 </p>
<p>还有一个重要的函数, <code>manipulateMatrix</code><br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">void epsilonWallFunctionFvPatchScalarField::manipulateMatrix</span><br><span class="line">(</span><br><span class="line"> fvMatrix<<span class="keyword">scalar</span>>& <span class="literal">matrix</span></span><br><span class="line">)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (manipulatedMatrix())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">matrix</span>.setValues(patch().faceCells(), patchInternalField());</span><br><span class="line"></span><br><span class="line"> fvPatchField<<span class="keyword">scalar</span>>::manipulateMatrix(<span class="keyword">matrix</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这个函数的功能是修改 matrix 中的值,将当前 patch 每一个面所属网格的值更新到 matrix 中,参考<a href="http://www.cfd-online.com/Forums/openfoam-solving/132703-boundarymanipulate.html" target="_blank" rel="external">这个帖子</a>。</p>
<p>如果不是使用的低雷诺数湍流模型,则 $\varepsilon$ 应该使用这个边界条件。理论上,边界第一层网格应该设置在对数区。什么是低雷诺数湍流模型呢?<a href="http://www.cfd-online.com/Forums/openfoam/125473-low-reynolds-turbulence-models.html" target="_blank" rel="external">这篇帖子</a>的三楼有精彩的解释。</p>
<ul>
<li>(2). epsilonLowReWallFunction</li>
</ul>
<p><code>epsilonLowReWallFunction</code> 继承自 <code>epsilonWallFunction</code> ,在此基础上,增加了一个成员函数 <code>yPlusLam</code>,并重新定义了 <code>calculate</code> 函数<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">scalar</span> epsilonLowReWallFunctionFvPatchScalarField::yPlusLam</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">scalar</span> <span class="keyword">kappa</span>,</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">scalar</span> <span class="literal">E</span></span><br><span class="line">)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">scalar</span> ypl = 11.0;</span><br><span class="line"> <span class="keyword">for</span> (int i=0; i<10; i++)</span><br><span class="line"> {</span><br><span class="line"> ypl = <span class="literal">log</span>(<span class="literal">max</span>(<span class="keyword">E</span>*ypl, 1))/<span class="keyword">kappa</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ypl;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这个跟 <code>kLowReWallFunction</code> 里是一样的,不再赘述。<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line">void epsilonLowReWallFunctionFvPatchScalarField::calculate</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> turbulenceModel& turbulence,</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">List</span><<span class="keyword">scalar</span>>& cornerWeights,</span><br><span class="line"> <span class="keyword">const</span> fvPatch& patch,</span><br><span class="line"> scalarField& <span class="keyword">G</span>,</span><br><span class="line"> scalarField& epsilon</span><br><span class="line">)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">label</span> patchI = patch.<span class="literal">index</span>();</span><br><span class="line"> <span class="keyword">const</span> scalarField& y = turbulence.<span class="literal">y</span>()[patchI];</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">scalar</span> Cmu25 = pow025(Cmu_);</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">scalar</span> Cmu75 = pow(Cmu_, 0.75);</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tk = turbulence.k();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& k = tk();</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnu = turbulence.nu();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nuw = tnu().boundaryField()[patchI];</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnut = turbulence.nut();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& nut = tnut();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nutw = nut.boundaryField()[patchI];</span><br><span class="line"> <span class="keyword">const</span> fvPatchVectorField& Uw = turbulence.<span class="keyword">U</span>().boundaryField()[patchI];</span><br><span class="line"> <span class="keyword">const</span> scalarField magGradUw(mag(Uw.snGrad()));</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Set epsilon and G</span></span><br><span class="line"> forAll(nutw, faceI)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">label</span> cellI = patch.faceCells()[faceI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">scalar</span> yPlus = Cmu25*<span class="literal">sqrt</span>(k[cellI])*y[faceI]/nuw[faceI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">scalar</span> w = cornerWeights[faceI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (yPlus > yPlusLam_)</span><br><span class="line"> {</span><br><span class="line"> epsilon[cellI] = w*Cmu75*pow(k[cellI], 1.5)/(kappa_*y[faceI]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> epsilon[cellI] = w*2.0*k[cellI]*nuw[faceI]/sqr(y[faceI]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">G</span>[cellI] =</span><br><span class="line"> <span class="literal">w</span></span><br><span class="line"><span class="comment"> *(nutw[faceI] + nuw[faceI])</span></span><br><span class="line"><span class="comment"> *magGradUw[faceI]</span></span><br><span class="line"><span class="comment"> *Cmu25*sqrt(k[cellI])</span></span><br><span class="line"> /(kappa_*y[faceI]);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这里需要根据 <code>yPlus</code> 和 <code>yPlusLam_</code> 的相对大小来选择不同的计算方式。只是,上面这段来自 OpenFOAM-2.3.1 的代码是有问题的!在OpenFOAM-3.0.1 中已经修复成如下<br><figure class="highlight prolog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"> <span class="atom">forAll</span>(<span class="atom">nutw</span>, <span class="atom">facei</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="atom">label</span> <span class="atom">celli</span> = <span class="atom">patch</span>.<span class="atom">faceCells</span>()[<span class="atom">facei</span>];</span><br><span class="line"></span><br><span class="line"> <span class="atom">scalar</span> <span class="atom">yPlus</span> = <span class="name">Cmu25</span>*<span class="atom">sqrt</span>(<span class="atom">k</span>[<span class="atom">celli</span>])*<span class="atom">y</span>[<span class="atom">facei</span>]/<span class="atom">nuw</span>[<span class="atom">facei</span>];</span><br><span class="line"></span><br><span class="line"> <span class="atom">scalar</span> <span class="atom">w</span> = <span class="atom">cornerWeights</span>[<span class="atom">facei</span>];</span><br><span class="line"></span><br><span class="line"> <span class="atom">if</span> (<span class="atom">yPlus</span> > <span class="atom">yPlusLam_</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="atom">epsilon0</span>[<span class="atom">celli</span>] += <span class="atom">w</span>*<span class="name">Cmu75</span>*<span class="atom">pow</span>(<span class="atom">k</span>[<span class="atom">celli</span>], <span class="number">1.5</span>)/(<span class="atom">kappa_</span>*<span class="atom">y</span>[<span class="atom">facei</span>]);</span><br><span class="line"></span><br><span class="line"> <span class="name">G0</span>[<span class="atom">celli</span>] +=</span><br><span class="line"> <span class="atom">w</span></span><br><span class="line"> *(<span class="atom">nutw</span>[<span class="atom">facei</span>] + <span class="atom">nuw</span>[<span class="atom">facei</span>])</span><br><span class="line"> *<span class="atom">magGradUw</span>[<span class="atom">facei</span>]</span><br><span class="line"> *<span class="name">Cmu25</span>*<span class="atom">sqrt</span>(<span class="atom">k</span>[<span class="atom">celli</span>])</span><br><span class="line"> /(<span class="atom">kappa_</span>*<span class="atom">y</span>[<span class="atom">facei</span>]);</span><br><span class="line"> }</span><br><span class="line"> <span class="atom">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="atom">epsilon0</span>[<span class="atom">celli</span>] += <span class="atom">w</span>*<span class="number">2.0</span>*<span class="atom">k</span>[<span class="atom">celli</span>]*<span class="atom">nuw</span>[<span class="atom">facei</span>]/<span class="atom">sqr</span>(<span class="atom">y</span>[<span class="atom">facei</span>]);</span><br><span class="line"> <span class="name">G0</span>[<span class="atom">celli</span>] += <span class="name">G</span>[<span class="atom">celli</span>];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p><code>yPlus > yPlusLam_</code> 时,与 <code>epsilonWallFunction</code> 是一样的;<br><code>yPlus < yPlusLam_</code> 时<br>$$<br>\varepsilon_c = \frac{1}{N} \sum_{f=i}^{N}\left( \frac{2\cdot k_C \nu_i}{y^2_i}\right)<br>$$<br>这个公式等价于<br>$$<br>\varepsilon ^+ = 2\frac{k^+}{(y^+)^2}<br>$$</p>
<p><code>G</code> 则取在湍流模型中定义的值,不作修改。 不过,这里 <code>G0[celli] += G[celli]</code> 意味着假设有一个网格有两个边界面,则这个网格的中计算得到的 <code>G0</code> ,将是在湍流模型中定义的该网格中的 G 值的 2 倍,即认为每一个边界面对都该网格内的湍动能生成有贡献。</p>
<p>这个边界是给低雷诺数的 $k-\varepsilon$ 模型以及 $v^2\text{-}f$ 模型使用的。用 OpenFOAM-3.0 以下版本的注意了,这些版本的 <code>epsilonLowReWallFunction</code> 有问题,<strong>一定不要忘了修正一下上面提到的那个bug </strong>!</p>
<h5 id="4-_$\omega$_的壁面函数">4. $\omega$ 的壁面函数</h5><p>OpenFOAM 中只提供了一个 <code>omegaWallFunction</code>,这个壁面函数,属于一种自动壁面函数,能自动地根据 $y^+$ 的值来在粘性层和对数层切换,过渡层则采用粘性层和对数层混合的结果。<br><code>omegaWallFunction</code> 与 <code>epsilonWallFunction</code> 类似,也是需要计算 $\omega$ 和 $P_k$ 在临近边界网格里的值,因此也需要考虑一个网格包含两个以上边界面的情况。具体处理方法跟 <code>epsilonWallFunction</code> 是一样的 ,所以这里就不重复了,只看具体的计算 $\omega$ 和 $P_k$ 的公式<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">void omegaWallFunctionFvPatchScalarField::calculate</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> turbulenceModel& turbulence,</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">List</span><<span class="keyword">scalar</span>>& cornerWeights,</span><br><span class="line"> <span class="keyword">const</span> fvPatch& patch,</span><br><span class="line"> scalarField& <span class="keyword">G</span>,</span><br><span class="line"> scalarField& omega</span><br><span class="line">)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">label</span> patchI = patch.<span class="literal">index</span>();</span><br><span class="line"> <span class="keyword">const</span> scalarField& y = turbulence.<span class="literal">y</span>()[patchI];</span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">scalar</span> Cmu25 = pow025(Cmu_);</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tk = turbulence.k();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& k = tk();</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnu = turbulence.nu();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nuw = tnu().boundaryField()[patchI];</span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnut = turbulence.nut();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& nut = tnut();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nutw = nut.boundaryField()[patchI];</span><br><span class="line"> <span class="keyword">const</span> fvPatchVectorField& Uw = turbulence.<span class="keyword">U</span>().boundaryField()[patchI];</span><br><span class="line"> <span class="keyword">const</span> scalarField magGradUw(mag(Uw.snGrad()));</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Set omega and G</span></span><br><span class="line"> forAll(nutw, faceI)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">label</span> cellI = patch.faceCells()[faceI];</span><br><span class="line"> <span class="keyword">scalar</span> w = cornerWeights[faceI];</span><br><span class="line"> <span class="keyword">scalar</span> omegaVis = 6.0*nuw[faceI]/(beta1_*sqr(y[faceI]));</span><br><span class="line"> <span class="keyword">scalar</span> omegaLog = <span class="literal">sqrt</span>(k[cellI])/(Cmu25*kappa_*y[faceI]);</span><br><span class="line"> omega[cellI] += w*<span class="literal">sqrt</span>(sqr(omegaVis) + sqr(omegaLog));</span><br><span class="line"> <span class="keyword">G</span>[cellI] +=</span><br><span class="line"> <span class="literal">w</span></span><br><span class="line"><span class="comment"> *(nutw[faceI] + nuw[faceI])</span></span><br><span class="line"><span class="comment"> *magGradUw[faceI]</span></span><br><span class="line"><span class="comment"> *Cmu25*sqrt(k[cellI])</span></span><br><span class="line"> /(kappa_*y[faceI]);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这里, <code>omegaVis</code> 和 <code>omegaLog</code> 分别指的是在假定第一层网格位于粘性底层和对数层时得到的 <code>omega</code> 的解析解<br>$$<br>\omega_{Vis} = \frac{6.0\nu}{\beta_1y^2} \<br>\omega_{Log} = \frac{k_C^{1/2}}{C_\mu^{1/4}\kappa y}<br>$$<br>然后,将 $\omega_{Vis}$ 和 $\omega_{Log}$ 用一个函数混合起来,就得到了<br>$$<br>\omega = \sqrt{\omega_{Vis}^2 + \omega_{Log}^2}<br>$$<br>只是,这里的湍动能生成项,却似乎并没有使用混合的方法,而是用的基于对数律的公式:<br>$$<br>G = \frac{(\nu + \nu_t)\cdot |\frac{U_c-U_w}{d}|\cdot C_\mu^{1/4}k_C^{1/2}}{\kappa y}<br>$$</p>
<p>$omega$ 方程是能直接积分到壁面,所以,如果使用基于 $\omega$ 的湍流模型,$\omega$ 变量直接使用这个边界条件就可以了。</p>
]]></content>
<summary type="html">
<![CDATA[<p>这篇来看看计算湍动能 $\varepsilon$ 和 $\omega$ 的壁面函数。</p>]]>
</summary>
<category term="Code Explained" scheme="http://xiaopingqiu.github.io/tags/Code-Explained/"/>
<category term="wall functions" scheme="http://xiaopingqiu.github.io/tags/wall-functions/"/>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/categories/OpenFOAM/"/>
</entry>
<entry>
<title><![CDATA[OpenFOAM 中的壁面函数(二)]]></title>
<link href="http://xiaopingqiu.github.io/2016/04/25/wallFunctions2/"/>
<id>http://xiaopingqiu.github.io/2016/04/25/wallFunctions2/</id>
<published>2016-04-24T16:43:29.000Z</published>
<updated>2016-04-25T02:49:07.183Z</updated>
<content type="html"><![CDATA[<p>这篇来看看计算湍动能 $k$ 的壁面函数。</p>
<a id="more"></a>
<h5 id="2-_湍流动能_$k$_的壁面函数">2. 湍流动能 $k$ 的壁面函数</h5><p>OpenFOAM 中提供了两种 $k$ 的壁面函数, <code>kqRWallFunction</code> 和 <code>kLowReWallFunction</code> 。</p>
<ul>
<li><p><code>kqRWallFunction</code><br>其实就是 <code>zeroGradient</code> ,无需多言。除非使用 $v^2\text{-}f$ 模型,一般情况下 $k$ 应该使用这个边界条件。</p>
</li>
<li><p><code>kLowReWallFunction</code><br>这个壁面函数应该是可以用于低雷诺数模型的。该壁面函数继承自 <code>fixedValue</code> :</p>
<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> kLowReWallFunctionFvPatchScalarField</span><br><span class="line">:</span><br><span class="line"> public fixedValueFvPatchField<<span class="keyword">scalar</span>></span><br><span class="line">{</span><br><span class="line">protected:</span><br><span class="line"> <span class="comment">//- Cmu coefficient</span></span><br><span class="line"> <span class="keyword">scalar</span> Cmu_;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//- Von Karman constant</span></span><br><span class="line"> <span class="keyword">scalar</span> kappa_;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//- E coefficient</span></span><br><span class="line"> <span class="keyword">scalar</span> E_;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//- Ceps2 coefficient</span></span><br><span class="line"> <span class="keyword">scalar</span> Ceps2_;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//- Y+ at the edge of the laminar sublayer</span></span><br><span class="line"> <span class="keyword">scalar</span> yPlusLam_;</span><br><span class="line"> ......</span><br><span class="line"> </span><br><span class="line">kLowReWallFunctionFvPatchScalarField::kLowReWallFunctionFvPatchScalarField</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> fvPatch& p,</span><br><span class="line"> <span class="keyword">const</span> DimensionedField<<span class="keyword">scalar</span>, volMesh>& <span class="keyword">iF</span>,</span><br><span class="line"> <span class="keyword">const</span> dictionary& dict</span><br><span class="line">)</span><br><span class="line">:</span><br><span class="line"> fixedValueFvPatchField<<span class="keyword">scalar</span>>(p, <span class="keyword">iF</span>, dict),</span><br><span class="line"> Cmu_(dict.lookupOrDefault<<span class="keyword">scalar</span>>(<span class="string">"Cmu"</span>, 0.09)),</span><br><span class="line"> kappa_(dict.lookupOrDefault<<span class="keyword">scalar</span>>(<span class="string">"kappa"</span>, 0.41)),</span><br><span class="line"> E_(dict.lookupOrDefault<<span class="keyword">scalar</span>>(<span class="string">"E"</span>, 9.8)),</span><br><span class="line"> Ceps2_(dict.lookupOrDefault<<span class="keyword">scalar</span>>(<span class="string">"Ceps2"</span>, 1.9)),</span><br><span class="line"> yPlusLam_(yPlusLam(kappa_, E_))</span><br><span class="line"> {</span><br><span class="line"> checkType();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>核心的函数是以下两个:<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line">scalar kLowReWallFunctionFvPatchScalarField::yPlusLam</span><br><span class="line">(</span><br><span class="line"> <span class="keyword">const</span> scalar kappa,</span><br><span class="line"> <span class="keyword">const</span> scalar E</span><br><span class="line">)</span><br><span class="line">{</span><br><span class="line"> scalar ypl = <span class="number">11.0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i=<span class="number">0</span>; i<<span class="number">10</span>; i++)</span><br><span class="line"> {</span><br><span class="line"> ypl = <span class="built_in">log</span>(max(E*ypl, <span class="number">1</span>))/kappa;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> ypl;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">void</span> kLowReWallFunctionFvPatchScalarField::updateCoeffs()</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (updated())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> label patchI = patch().index();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> turbulenceModel& turbulence =</span><br><span class="line"> db().lookupObject<turbulenceModel>(<span class="string">"turbulenceModel"</span>);</span><br><span class="line"> <span class="keyword">const</span> scalarField& y = turbulence.y()[patchI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tk = turbulence.k();</span><br><span class="line"> <span class="keyword">const</span> volScalarField& k = tk();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> tmp<volScalarField> tnu = turbulence.nu();</span><br><span class="line"> <span class="keyword">const</span> scalarField& nuw = tnu().boundaryField()[patchI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> scalar Cmu25 = pow025(Cmu_);</span><br><span class="line"></span><br><span class="line"> scalarField& kw = *<span class="keyword">this</span>; <span class="comment">// 更新 kw 相当于更新壁面上的 k 值。</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// Set k wall values</span></span><br><span class="line"> forAll(kw, faceI)</span><br><span class="line"> {</span><br><span class="line"> label faceCellI = patch().faceCells()[faceI];</span><br><span class="line"></span><br><span class="line"> scalar uTau = Cmu25*<span class="built_in">sqrt</span>(k[faceCellI]);</span><br><span class="line"></span><br><span class="line"> scalar yPlus = uTau*y[faceI]/nuw[faceI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (yPlus > yPlusLam_)</span><br><span class="line"> {</span><br><span class="line"> scalar Ck = -<span class="number">0.416</span>;</span><br><span class="line"> scalar Bk = <span class="number">8.366</span>;</span><br><span class="line"> kw[faceI] = Ck/kappa_*<span class="built_in">log</span>(yPlus) + Bk;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> scalar C = <span class="number">11.0</span>;</span><br><span class="line"> scalar Cf = (<span class="number">1.0</span>/sqr(yPlus + C) + <span class="number">2.0</span>*yPlus/pow3(C) - <span class="number">1.0</span>/sqr(C));</span><br><span class="line"> kw[faceI] = <span class="number">2400.0</span>/sqr(Ceps2_)*Cf;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> kw[faceI] *= sqr(uTau);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> fixedValueFvPatchField<scalar>::updateCoeffs();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// TODO: perform averaging for cells sharing more than one boundary face</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>先在函数里计算 <code>ypl</code> 的值, <code>updateCoeffs</code> 函数里根据 <code>yPlus</code> 与这个 <code>ypl</code> 的值来相对大小而采取不同的方法来计算壁面上的 $k_w$。 <code>ypl</code> 的计算是一个迭代过程<br>$$<br>ypl = \frac{\log(\max(E*ypl,1.0))}{\kappa}<br>$$<br>初始值为 <code>ypl = 11.0</code>,迭代10次,最终结果应该是 <code>ypl = 11.5301073043272</code>。<br>$y^+$ 定义为:<br>$$<br>u_\tau = C_\mu^{1/4 }\sqrt{k_c} \<br>y^+ = \frac{u_\tau \cdot y}{\nu_w}<br>$$<br>壁面上的k计算方法如下:如果 $y^+ > ypl$,则<br>$$<br>k^+ _w = \frac{C_k}{\kappa}\ln(y^+) + B_k<br>$$<br>否则<br>$$<br>k^+ _w = \frac{2400}{C_{eps2}^2}\cdot \left[ \frac{1}{(y^+ + C)^2} + \frac{2y^+}{C^3} - \frac{1}{C^2}\right ]<br>$$<br>最终,壁面上的值为 $k_w=k^+ _w u_\tau ^2 =k^+ _w C_\mu^{1/2}k_c$ 。<br>以上公式中,下标 $c$ 表示壁面单元所述网格的值,下标 $w$ 表示当前壁面上的值。<br>这个壁面函数参考文献 “Kalitzin, G., Medic, G., Iaccarino, G., Durbin, P., 2005. Near-wall behavior of RANS turbulence models and implications for wall functions. J. Comput. Phys. 204, 265–291. doi:10.1016/j.jcp.2004.10.018”,是为 $v^2\text{-}f$ 模型设计的。 </p>
<h5 id="$v^2$_和_$f$_的壁面函数">$v^2$ 和 $f$ 的壁面函数</h5><p>上面提到了 $v^2\text{-}f$ 模型,所以这里顺便来看看$v^2$ 和 $f$ 的壁面函数。这里参考的也是上面提到的那篇参考文献。</p>
<ul>
<li>$v^2$ 的壁函数<figure class="highlight perl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">forAll(v2, faceI)</span><br><span class="line"> {</span><br><span class="line"> label faceCellI = patch().faceCells()[faceI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">scalar</span> uTau = Cmu25*<span class="keyword">sqrt</span>(k[faceCellI]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">scalar</span> yPlus = uTau*<span class="keyword">y</span>[faceI]/nuw[faceI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (yPlus > yPlusLam<span class="number">_</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">scalar</span> Cv2 = <span class="number">0</span>.<span class="number">193</span>;</span><br><span class="line"> <span class="keyword">scalar</span> Bv2 = -<span class="number">0</span>.<span class="number">94</span>;</span><br><span class="line"> v2[faceI] = Cv2/kappa<span class="number">_</span>*<span class="keyword">log</span>(yPlus) + Bv2;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">scalar</span> Cv2 = <span class="number">0</span>.<span class="number">193</span>;</span><br><span class="line"> v2[faceI] = Cv2*pow4(yPlus);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> v2[faceI] *= <span class="keyword">s</span><span class="string">qr(uTau)</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> fixedValueFvPatchField<<span class="keyword">scalar</span>>::updateCoeffs();</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p><code>yPlus > yPlusLam_</code> 时,<br>$$<br>v^2 = u_\tau^2 \cdot \left[ \frac{C_{v2}}{\kappa}\ln(y^+) + B_{v2} \right]<br>$$<br>与文献中的无量纲形式 $(\overline{v^2})^{^+} = \frac{C_{v2}}{\kappa}\ln(y^+) + B_{v2} $ 一致。</p>
<p><code>yPlus < yPlusLam\_</code> 时,<br>$$<br>v^2 = u_\tau^2 \cdot C_{v2}(y^+)^2<br>$$<br>与无量纲形式 $(\overline{v^2})^{^+} = C_{v2}(y^+)^2$ 一致。</p>
<ul>
<li>$f$ 的壁函数<figure class="highlight perl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">forAll(f, faceI)</span><br><span class="line"> {</span><br><span class="line"> label faceCellI = patch().faceCells()[faceI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">scalar</span> uTau = Cmu25*<span class="keyword">sqrt</span>(k[faceCellI]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">scalar</span> yPlus = uTau*<span class="keyword">y</span>[faceI]/nuw[faceI];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (yPlus > yPlusLam<span class="number">_</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">scalar</span> N = <span class="number">6.0</span>;</span><br><span class="line"> <span class="keyword">scalar</span> v2c = v2[faceCellI];</span><br><span class="line"> <span class="keyword">scalar</span> epsc = epsilon[faceCellI];</span><br><span class="line"> <span class="keyword">scalar</span> kc = k[faceCellI];</span><br><span class="line"></span><br><span class="line"> f[faceI] = N*v2c*epsc/(<span class="keyword">s</span><span class="string">qr(kc)</span> + ROOTVSMALL);</span><br><span class="line"> f[faceI] /= <span class="keyword">s</span><span class="string">qr(uTau)</span> + ROOTVSMALL;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> f[faceI] = <span class="number">0</span>.<span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p><code>yPlus > yPlusLam_</code> 时,<br>$$<br>f = \frac{N \cdot v^2\cdot \varepsilon}{k^2 u_\tau^2}<br>$$<br>这似乎与文献中的无量纲形式<br>$$<br>f^+ = N \frac{(\overline{v^2})^{^+}}{(k^+)^2}\varepsilon^+<br>$$<br>不一致!是 bug 还是我推导出错了?存疑…</p>
<p><code>yPlus < yPlusLam_</code> 时,文献给出的公式是<br>$$<br>f^+ = \frac{-4(6-N)(\overline{v^2})^{^+}}{\varepsilon^+ (y^+)^4}<br>$$<br>当 <code>N=6</code> 时,可以得到 $f^+ = 0$ 。</p>
<p>按理说,$v^2$ 和 $f$ 应该跟 $\varepsilon$ 和 $\omega$ 那样(见后文),计算第一层网格内的值,并且考虑一个网格有多个边界面的情形。OpenFOAM 目前计算的是每一个边界面元上的值,不知道这两种方式对结果有多大影响。</p>
]]></content>
<summary type="html">
<![CDATA[<p>这篇来看看计算湍动能 $k$ 的壁面函数。</p>]]>
</summary>
<category term="Code Explained" scheme="http://xiaopingqiu.github.io/tags/Code-Explained/"/>
<category term="wall functions" scheme="http://xiaopingqiu.github.io/tags/wall-functions/"/>
<category term="OpenFOAM" scheme="http://xiaopingqiu.github.io/categories/OpenFOAM/"/>
</entry>
</feed>