日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Fluent UDF中调用变量的梯度及其注意点

發(fā)布時(shí)間:2023/12/29 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Fluent UDF中调用变量的梯度及其注意点 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Fluent UDF中有時(shí)候需要調(diào)用變量的梯度,例如溫度梯度,壓力梯度,VOF梯度等等,一般是在C_T,C_P,C_VOF后面加上“_G”來(lái)獲取,例如C_T_G,C_VOF_G。看似簡(jiǎn)單,實(shí)際上里面有比較多的“坑”,現(xiàn)以如下實(shí)例來(lái)提請(qǐng)各位看官注意。

???????? 首先,我們利用VC++ UDF Studio插件(https://vcudfstudio.github.io)啟動(dòng)Fluent,然后再點(diǎn)擊Fluent中的“啟動(dòng)Visual Studio”菜單,這樣我們就可以在Visual Studio中輸入源碼并編譯UDF了。

在Visual Studio項(xiàng)目中的udf_source.cpp文件中輸入如下源碼。

#include "udf.h" #include "SuperUdfExtension.h" //VC++ UDF Studio自帶的擴(kuò)展庫(kù)頭文件,具體參考該軟件中的編程手冊(cè) #pragma comment(lib, "SuperUdfExtension.lib") //VC++ UDF Studio自帶的擴(kuò)展庫(kù)的lib文件 int GetZoneIdByName(CString zoneName); //函數(shù)聲明DEFINE_ADJUST(show_gradient, domain) {face_t f;real T_gradient[ND_ND];int theInletID = GetZoneIdByName("inlet"); //根據(jù)邊界名字獲取其ID,如果返回-1表示找不到if (-1 == theInletID){Message("Cannot find the boundary name 'inlet'. Please modify!\n");return;}Thread * wall_thread = Lookup_Thread(domain, theInletID); //根據(jù)inlet的ID獲得其ThreadThread *fluid_thread = THREAD_T0(wall_thread); //獲得和邊界face鄰接的cell的threadbegin_f_loop(f, wall_thread) //對(duì)inlet的面進(jìn)行循環(huán){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);//格式化當(dāng)前Fluent版本為字符串形式double fCurrentFluentVersion = atof(strCurrentFluentVersion.GetBuffer()); //當(dāng)前Fluent版本轉(zhuǎn)為double類型if (fCurrentFluentVersion <= 19.2) // 對(duì)于Fluent6.3-19.2,只能調(diào)用VC++ UDF Studio擴(kuò)展庫(kù){SuperUdf_Initialize(AfxGetInstanceHandle()); //調(diào)用VC++ UDF Studio擴(kuò)展庫(kù)中任何函數(shù)之前必須調(diào)用此初始化函數(shù),具體參考該軟件中的編程手冊(cè) #if !RP_NODEreturnID = SuperUdf_GetZoneIdByName(zoneName.GetBuffer()); //調(diào)用VC++ UDF Studio擴(kuò)展庫(kù)中的SuperUdf_GetZoneIdByName函數(shù),具體參考該軟件中的編程手冊(cè) #endifhost_to_node_int_1(returnID);}else // 對(duì)于Fluent version >=19.3,有直接UDF函數(shù)可以實(shí)現(xiàn){Thread*tf;thread_loop_f(tf, domain) //對(duì)所有面的thread進(jìn)行循環(huán)查找{if (0 == zoneName.CompareNoCase(THREAD_NAME(tf))) //對(duì)比名字是否相同{returnID = THREAD_ID(tf);break;}}if (-1 == returnID) //如果面的thread中無(wú)法找到匹配名字{Thread*tc;thread_loop_c(tc, domain) //對(duì)所有網(wǎng)格的thread進(jìn)行循環(huán)查找{if (0 == zoneName.CompareNoCase(THREAD_NAME(tc))) //對(duì)比名字是否相同{returnID = THREAD_ID(tc);break;}}}}return returnID; }

?以上程序是想要在每次迭代之前顯示x方向的溫度梯度的值。其中,GetZoneIdByName函數(shù)是根據(jù)邊界的名字來(lái)獲得其ID,可以參考博文《Fluent UDF中根據(jù)zone的名字獲取ID》(https://www.cnblogs.com/SuperUDF/articles/15886289.html)。
注意:請(qǐng)確保有名字為inlet的入口邊界,否則加載UDF的時(shí)候就會(huì)報(bào)告“Cannot find the boundary name 'inlet'. Please modify!”,說明找不到名字為inlet的邊界。

?

源碼輸入完畢以后,點(diǎn)擊“編譯UDF”按鈕就可以編譯UDF了,編譯成功后點(diǎn)擊“UDF庫(kù)加載到Fluent”按鈕就可以加載UDF庫(kù)了。

?

?加載成功以后,我們就需要手動(dòng)將DEFINE_ADJUST宏hook到Fluent。這樣才能每次迭代之前執(zhí)行我們的Adjust宏。

?

?

?初始化然后開始迭代計(jì)算,然而計(jì)算第一步就直接報(bào)錯(cuò),說明我們已經(jīng)順利“入坑”。

?

然而,面對(duì)這個(gè)毫無(wú)頭緒的錯(cuò)誤提示,可能連坑在哪里都不知道,那怎么辦呢?可以啟用VC++ UDF Studio插件的調(diào)試功能。即在宏內(nèi)第一行鼠標(biāo)右鍵然后菜單選擇“Insert Breakpoint”,此時(shí)該行前面就會(huì)出現(xiàn)一個(gè)圓球,表示斷點(diǎn)已經(jīng)插入。 一旦程序運(yùn)行到該行,就會(huì)中斷。點(diǎn)擊三角形的按鈕進(jìn)入調(diào)試模式,然后重新初始化開始迭代計(jì)算。

?

?開始迭代計(jì)算后,程序馬上就中斷在圓球的斷點(diǎn)處,并顯示一個(gè)黃色箭頭,這就說明fluent執(zhí)行到該行被中斷暫停了(但尚未執(zhí)行該行),然后我們就可以手動(dòng)一步一步跟蹤后面每一行是否能正確運(yùn)行。

?單擊Debug菜單中的“Step Over”項(xiàng),或者快捷鍵F10,就能手動(dòng)執(zhí)行一行程序,如果沒有出現(xiàn)錯(cuò)誤提示,那說明改行能正確運(yùn)行,同時(shí)我們還可以在變量值顯示區(qū)查看執(zhí)行該行的變量值有什么變化,檢查變量值是不是如我們所設(shè)想的那樣,從而可以發(fā)現(xiàn)潛在錯(cuò)誤。

?當(dāng)我們一步一步執(zhí)行到C_T_G這一行時(shí),前面那個(gè)錯(cuò)誤就跳出來(lái)了,那就說明錯(cuò)誤就發(fā)生在這一行,需要我們仔細(xì)考慮如何修改。

?首先,我們知道這個(gè)是溫度梯度,可是我們連能量方程都沒有開,哪來(lái)的溫度呢?所以第一坑就是要對(duì)什么方程求解什么傳輸變量要有理解,例如取溫度梯度必須開能量方程,VOF梯度也必須開多相流模型。這樣,我們先把第一個(gè)坑給填平了,打開能量控制方程。

?重復(fù)前面的調(diào)試過程,然而錯(cuò)誤提示依舊出現(xiàn),而且還是這一行出問題。我們通過查閱UDF手冊(cè)發(fā)現(xiàn)里面有這么一句話,“默認(rèn)情況下求解器會(huì)不斷移除梯度數(shù)據(jù)”。如果需要保留梯度數(shù)據(jù),需要使用“solver/set/expert”的TUI命令回答“yes”來(lái)保留。原來(lái),第二個(gè)坑在這里。

OK,那我們繼續(xù)填平第二個(gè)“坑”,在控制臺(tái)里面輸入“solver/set/expert”的TUI命令,并對(duì)于“Keep temporary solver memory from being freed?”回答yes。

?然后重復(fù)前面的調(diào)試過程,然而錯(cuò)誤提示依舊出現(xiàn),還是定位在C_T_G這一行。這個(gè)可夠讓人郁悶的,怎么回事?經(jīng)過筆者的研究,原來(lái)這最大的“坑”是因?yàn)榈谝徊降疤荻冗€沒有建立,而adjust恰恰是每一步迭代前調(diào)用的,所以第一步迭代之前是取不到梯度的,需要迭代第二步迭代前才有值。這樣,剛開始迭代第一步就跳出錯(cuò)誤。為了避免這個(gè)問題,我們需要寫一個(gè)判斷語(yǔ)句。

if(NULL!=T_STORAGE_R_NV(fluid_thread, SV_T_G)) // 如果溫度梯度已經(jīng)建立,一般迭代第二步以后就有梯度值了NV_V(T_gradient, =, C_T_G(c0, fluid_thread));else // 如果溫度梯度尚未建立,一般是迭代第一步的開始NV_D(T_gradient,=,0,0,0);

?其中,SV_T_G是溫度梯度的存儲(chǔ)序號(hào)。類似地,如果是VOF梯度,其序號(hào)為SV_VOF_G。整個(gè)語(yǔ)句結(jié)構(gòu)的意思就是:對(duì)于梯度尚未建立的情況(一般是迭代第一步的開始),直接賦值零梯度。后面當(dāng)梯度有存儲(chǔ)值以后,就可以調(diào)用梯度了。正確的完整程序如下:

#include "udf.h" #include "SuperUdfExtension.h" //VC++ UDF Studio自帶的擴(kuò)展庫(kù)頭文件,具體參考該軟件中的編程手冊(cè) #pragma comment(lib, "SuperUdfExtension.lib") //VC++ UDF Studio自帶的擴(kuò)展庫(kù)的lib文件 int GetZoneIdByName(CString zoneName); //函數(shù)聲明DEFINE_ADJUST(show_gradient, domain) {face_t f;real T_gradient[ND_ND];int theInletID = GetZoneIdByName("inlet"); //根據(jù)邊界名字獲取其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)) // 如果溫度梯度已經(jīng)建立,一般迭代第二步以后就有梯度值了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);//格式化當(dāng)前Fluent版本為字符串形式double fCurrentFluentVersion = atof(strCurrentFluentVersion.GetBuffer()); //當(dāng)前Fluent版本轉(zhuǎn)為double類型if (fCurrentFluentVersion <= 19.2) // 對(duì)于Fluent6.3-19.2,只能調(diào)用VC++ UDF Studio擴(kuò)展庫(kù){SuperUdf_Initialize(AfxGetInstanceHandle()); //調(diào)用VC++ UDF Studio擴(kuò)展庫(kù)中任何函數(shù)之前必須調(diào)用此初始化函數(shù),具體參考該軟件中的編程手冊(cè) #if !RP_NODEreturnID = SuperUdf_GetZoneIdByName(zoneName.GetBuffer()); //調(diào)用VC++ UDF Studio擴(kuò)展庫(kù)中的SuperUdf_GetZoneIdByName函數(shù),具體參考該軟件中的編程手冊(cè) #endifhost_to_node_int_1(returnID);}else // 對(duì)于Fluent version >=19.3,有直接UDF函數(shù)可以實(shí)現(xiàn){Thread*tf;thread_loop_f(tf, domain) //對(duì)所有面的thread進(jìn)行循環(huán)查找{if (0 == zoneName.CompareNoCase(THREAD_NAME(tf))) //對(duì)比名字是否相同{returnID = THREAD_ID(tf);break;}}if (-1 == returnID) //如果面的thread中無(wú)法找到匹配名字{Thread*tc;thread_loop_c(tc, domain) //對(duì)所有網(wǎng)格的thread進(jìn)行循環(huán)查找{if (0 == zoneName.CompareNoCase(THREAD_NAME(tc))) //對(duì)比名字是否相同{returnID = THREAD_ID(tc);break;}}}}return returnID; }

執(zhí)行結(jié)果如下,可以看到第一次迭代前的梯度因?yàn)闆]有存儲(chǔ)值,所以取零值,第二步開始就有具體的值了。

?

總結(jié)

以上是生活随笔為你收集整理的Fluent UDF中调用变量的梯度及其注意点的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。