Fluent UDF中调用变量的梯度及其注意点
Fluent UDF中有時候需要調用變量的梯度,例如溫度梯度,壓力梯度,VOF梯度等等,一般是在C_T,C_P,C_VOF后面加上“_G”來獲取,例如C_T_G,C_VOF_G。看似簡單,實際上里面有比較多的“坑”,現以如下實例來提請各位看官注意。
???????? 首先,我們利用VC++ UDF Studio插件(https://vcudfstudio.github.io)啟動Fluent,然后再點擊Fluent中的“啟動Visual Studio”菜單,這樣我們就可以在Visual Studio中輸入源碼并編譯UDF了。
在Visual Studio項目中的udf_source.cpp文件中輸入如下源碼。
#include "udf.h" #include "SuperUdfExtension.h" //VC++ UDF Studio自帶的擴展庫頭文件,具體參考該軟件中的編程手冊 #pragma comment(lib, "SuperUdfExtension.lib") //VC++ UDF Studio自帶的擴展庫的lib文件 int GetZoneIdByName(CString zoneName); //函數聲明DEFINE_ADJUST(show_gradient, domain) {face_t f;real T_gradient[ND_ND];int theInletID = GetZoneIdByName("inlet"); //根據邊界名字獲取其ID,如果返回-1表示找不到if (-1 == theInletID){Message("Cannot find the boundary name 'inlet'. Please modify!\n");return;}Thread * wall_thread = Lookup_Thread(domain, theInletID); //根據inlet的ID獲得其ThreadThread *fluid_thread = THREAD_T0(wall_thread); //獲得和邊界face鄰接的cell的threadbegin_f_loop(f, wall_thread) //對inlet的面進行循環{cell_t c0 = F_C0(f, wall_thread); //獲得和inlet面鄰接的cellNV_V(T_gradient, =, C_T_G(c0, fluid_thread)); //將溫度梯度賦值給T_gradientMessage("c=%d, Temperature X gradient is %g\n", c0, T_gradient[0]); //打印x方向的梯度}end_f_loop(f, wall_thread) }int GetZoneIdByName(CString zoneName) //適用于所有Fluent版本 {int returnID = -1;Domain*domain = Get_Domain(1);CString strCurrentFluentVersion;strCurrentFluentVersion.Format("%d.%d", RampantReleaseMajor, RampantReleaseMinor);//格式化當前Fluent版本為字符串形式double fCurrentFluentVersion = atof(strCurrentFluentVersion.GetBuffer()); //當前Fluent版本轉為double類型if (fCurrentFluentVersion <= 19.2) // 對于Fluent6.3-19.2,只能調用VC++ UDF Studio擴展庫{SuperUdf_Initialize(AfxGetInstanceHandle()); //調用VC++ UDF Studio擴展庫中任何函數之前必須調用此初始化函數,具體參考該軟件中的編程手冊 #if !RP_NODEreturnID = SuperUdf_GetZoneIdByName(zoneName.GetBuffer()); //調用VC++ UDF Studio擴展庫中的SuperUdf_GetZoneIdByName函數,具體參考該軟件中的編程手冊 #endifhost_to_node_int_1(returnID);}else // 對于Fluent version >=19.3,有直接UDF函數可以實現{Thread*tf;thread_loop_f(tf, domain) //對所有面的thread進行循環查找{if (0 == zoneName.CompareNoCase(THREAD_NAME(tf))) //對比名字是否相同{returnID = THREAD_ID(tf);break;}}if (-1 == returnID) //如果面的thread中無法找到匹配名字{Thread*tc;thread_loop_c(tc, domain) //對所有網格的thread進行循環查找{if (0 == zoneName.CompareNoCase(THREAD_NAME(tc))) //對比名字是否相同{returnID = THREAD_ID(tc);break;}}}}return returnID; }?以上程序是想要在每次迭代之前顯示x方向的溫度梯度的值。其中,GetZoneIdByName函數是根據邊界的名字來獲得其ID,可以參考博文《Fluent UDF中根據zone的名字獲取ID》(https://www.cnblogs.com/SuperUDF/articles/15886289.html)。
注意:請確保有名字為inlet的入口邊界,否則加載UDF的時候就會報告“Cannot find the boundary name 'inlet'. Please modify!”,說明找不到名字為inlet的邊界。
?
源碼輸入完畢以后,點擊“編譯UDF”按鈕就可以編譯UDF了,編譯成功后點擊“UDF庫加載到Fluent”按鈕就可以加載UDF庫了。
?
?加載成功以后,我們就需要手動將DEFINE_ADJUST宏hook到Fluent。這樣才能每次迭代之前執行我們的Adjust宏。
?
?
?初始化然后開始迭代計算,然而計算第一步就直接報錯,說明我們已經順利“入坑”。
?
然而,面對這個毫無頭緒的錯誤提示,可能連坑在哪里都不知道,那怎么辦呢?可以啟用VC++ UDF Studio插件的調試功能。即在宏內第一行鼠標右鍵然后菜單選擇“Insert Breakpoint”,此時該行前面就會出現一個圓球,表示斷點已經插入。 一旦程序運行到該行,就會中斷。點擊三角形的按鈕進入調試模式,然后重新初始化開始迭代計算。
?
?開始迭代計算后,程序馬上就中斷在圓球的斷點處,并顯示一個黃色箭頭,這就說明fluent執行到該行被中斷暫停了(但尚未執行該行),然后我們就可以手動一步一步跟蹤后面每一行是否能正確運行。
?單擊Debug菜單中的“Step Over”項,或者快捷鍵F10,就能手動執行一行程序,如果沒有出現錯誤提示,那說明改行能正確運行,同時我們還可以在變量值顯示區查看執行該行的變量值有什么變化,檢查變量值是不是如我們所設想的那樣,從而可以發現潛在錯誤。
?當我們一步一步執行到C_T_G這一行時,前面那個錯誤就跳出來了,那就說明錯誤就發生在這一行,需要我們仔細考慮如何修改。
?首先,我們知道這個是溫度梯度,可是我們連能量方程都沒有開,哪來的溫度呢?所以第一坑就是要對什么方程求解什么傳輸變量要有理解,例如取溫度梯度必須開能量方程,VOF梯度也必須開多相流模型。這樣,我們先把第一個坑給填平了,打開能量控制方程。
?重復前面的調試過程,然而錯誤提示依舊出現,而且還是這一行出問題。我們通過查閱UDF手冊發現里面有這么一句話,“默認情況下求解器會不斷移除梯度數據”。如果需要保留梯度數據,需要使用“solver/set/expert”的TUI命令回答“yes”來保留。原來,第二個坑在這里。
OK,那我們繼續填平第二個“坑”,在控制臺里面輸入“solver/set/expert”的TUI命令,并對于“Keep temporary solver memory from being freed?”回答yes。
?然后重復前面的調試過程,然而錯誤提示依舊出現,還是定位在C_T_G這一行。這個可夠讓人郁悶的,怎么回事?經過筆者的研究,原來這最大的“坑”是因為迭代第一步迭代之前梯度還沒有建立,而adjust恰恰是每一步迭代前調用的,所以第一步迭代之前是取不到梯度的,需要迭代第二步迭代前才有值。這樣,剛開始迭代第一步就跳出錯誤。為了避免這個問題,我們需要寫一個判斷語句。
if(NULL!=T_STORAGE_R_NV(fluid_thread, SV_T_G)) // 如果溫度梯度已經建立,一般迭代第二步以后就有梯度值了NV_V(T_gradient, =, C_T_G(c0, fluid_thread));else // 如果溫度梯度尚未建立,一般是迭代第一步的開始NV_D(T_gradient,=,0,0,0);?其中,SV_T_G是溫度梯度的存儲序號。類似地,如果是VOF梯度,其序號為SV_VOF_G。整個語句結構的意思就是:對于梯度尚未建立的情況(一般是迭代第一步的開始),直接賦值零梯度。后面當梯度有存儲值以后,就可以調用梯度了。正確的完整程序如下:
#include "udf.h" #include "SuperUdfExtension.h" //VC++ UDF Studio自帶的擴展庫頭文件,具體參考該軟件中的編程手冊 #pragma comment(lib, "SuperUdfExtension.lib") //VC++ UDF Studio自帶的擴展庫的lib文件 int GetZoneIdByName(CString zoneName); //函數聲明DEFINE_ADJUST(show_gradient, domain) {face_t f;real T_gradient[ND_ND];int theInletID = GetZoneIdByName("inlet"); //根據邊界名字獲取其ID,如果返回-1表示找不到if (-1 == theInletID){Message("Cannot find the boundary name 'inlet'. Please modify!\n");return;}Thread * wall_thread = Lookup_Thread(domain, theInletID);Thread *fluid_thread = THREAD_T0(wall_thread);begin_f_loop(f, wall_thread){cell_t c0 = F_C0(f, wall_thread);if(NULL!=T_STORAGE_R_NV(fluid_thread, SV_T_G)) // 如果溫度梯度已經建立,一般迭代第二步以后就有梯度值了NV_V(T_gradient, =, C_T_G(c0, fluid_thread));else // 如果溫度梯度尚未建立,一般是迭代第一步的開始NV_D(T_gradient,=,0,0,0);Message("c=%d, Temperature X gradient is %g\n", c0, T_gradient[0]); }end_f_loop(f, wall_thread) }int GetZoneIdByName(CString zoneName) //適用于所有Fluent版本 {int returnID = -1;Domain*domain = Get_Domain(1);CString strCurrentFluentVersion;strCurrentFluentVersion.Format("%d.%d", RampantReleaseMajor, RampantReleaseMinor);//格式化當前Fluent版本為字符串形式double fCurrentFluentVersion = atof(strCurrentFluentVersion.GetBuffer()); //當前Fluent版本轉為double類型if (fCurrentFluentVersion <= 19.2) // 對于Fluent6.3-19.2,只能調用VC++ UDF Studio擴展庫{SuperUdf_Initialize(AfxGetInstanceHandle()); //調用VC++ UDF Studio擴展庫中任何函數之前必須調用此初始化函數,具體參考該軟件中的編程手冊 #if !RP_NODEreturnID = SuperUdf_GetZoneIdByName(zoneName.GetBuffer()); //調用VC++ UDF Studio擴展庫中的SuperUdf_GetZoneIdByName函數,具體參考該軟件中的編程手冊 #endifhost_to_node_int_1(returnID);}else // 對于Fluent version >=19.3,有直接UDF函數可以實現{Thread*tf;thread_loop_f(tf, domain) //對所有面的thread進行循環查找{if (0 == zoneName.CompareNoCase(THREAD_NAME(tf))) //對比名字是否相同{returnID = THREAD_ID(tf);break;}}if (-1 == returnID) //如果面的thread中無法找到匹配名字{Thread*tc;thread_loop_c(tc, domain) //對所有網格的thread進行循環查找{if (0 == zoneName.CompareNoCase(THREAD_NAME(tc))) //對比名字是否相同{returnID = THREAD_ID(tc);break;}}}}return returnID; }執行結果如下,可以看到第一次迭代前的梯度因為沒有存儲值,所以取零值,第二步開始就有具體的值了。
?
總結
以上是生活随笔為你收集整理的Fluent UDF中调用变量的梯度及其注意点的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: samsung学习笔记2
- 下一篇: linux主机安全加固,linux主机安