首页/文章/ 详情

Fluent UDF云图表情教程

14天前浏览869




注:

本文所需的所有文件包含python代码、UDF代码、cas和dat文件、gif图文件都附在文末的链接中



1. 云图表情包说明

本云图表情包有一定的局限性,即只适用于黑白线条的表情包,在云图中红色表示黑色,蓝色表示白色。这是因为云图颜色从蓝色到红色变化,而表情包颜色可能RGB全覆盖。-我不知道怎么能在云图中显示RGB颜色。


当然,我尝试过RGB直接相加,确实能得到有颜色的云图,但结果却像热成像照片。


 
 




 


2. 云图表情包生成思路

这个云图的生成其实有几种方法,使用profile文件也可实现部分的效果。但最终确定比较简单的实现方式还是python结合UDF。


思路与步骤:我们都知道动图是由很多图片叠加实现的,云图表情包也是这个原理。


2.1获得表情包的关键帧

首先我们需要获得表情包的关键帧,这一操作可以通过WPS的图片编辑器实现。


通过WPS图片编辑器将表情包的gif文件生成很多图片。


2.2python识别像素点

这一操作由python来完成。通过python将表情包的图片文件识别成像素点,并将每个图片的像素点写入一个txt数据。


比如一个表情包gif图片可以生成20张png图片,那么通过python就可以生成20个profile文件。每个proflie代表一张图片的像素点信息



2.3UDF动态导入像素点数据


 

我们已经获取了图片的像素点信息了,现在需要将这些信息导入Fluent。如何导入呢?可以通过profile和UDF两种方式。但是UDF方式更加简单且流程化。



为了实现动画效果,我们必须在每迭代步都导入一个profile,然后强制让温度或者其他变量根据像素点信息改变数值。每个迭代步画一张图,20张图就20个迭代步,连接起来就会实现动画效果了。



2.4Fluent动画制作

就是很常规的Fluent生成动画操作,在生成动画之前,要注意必须要勾选能量方程,然后在control里面不选择能量方程。


这样做的目的是不让Fluent自带的求解器影响到生成的图片。




3. 表情包案例步骤

上面是整个思路和步骤,下面我们来通过一个例子详细详解。


3.1 获得表情包的关键帧


首先搜索表情包,然后保存下来

 

用WPS打开表情包gif图,点击保存所有帧

 


可以在表情包图片所在的文件夹下看到所有帧的文件夹,里面是每帧的图片。这就是我们要生成云图动画的源图片


 


3.2 python识别像素点

基本逻辑:python读取图片像素,如果像素颜色小于某个值,则记录此处的坐标,否则,不记录。

下面为完整的python代码:
























































from PIL import Imageimport matplotlib.pyplot as plt
def get_coordinate(path):    # 打开图片    image = Image.open(path)    width, height = image.size    length_x=4  #Fluent中模型尺寸,x方向,根据云图表情包尺寸调整    length_y=3  #Fluent中模型尺寸,y方向,根据云图表情包尺寸调整    x_list=[]   #x坐标    y_list=[]   #y坐标    out = image.convert("RGB")    num=0    for i in range(width):        for j in range(height):            num+=1            if (out.getpixel((i, j)) < (50, 50, 50)): #RGB数小于次数值,值越大可捕捉更多的像素                x=i/width*length_x                y=(height-j)/height*length_y                if (num%2==0):  #跳过多少数据                    x_list.append(x)                    y_list.append(y)    return x_list,y_list

def write_file(x_list,y_list,path,UDF=0,draw=1):    # 打开文件用于写入,如果文件不存在则创建    if(UDF==1):     #如果使用UDF,则UDF=1,生成UDF使用的txt数据,否则生成profile文件        with open(path, 'w') as file:            for i,x in enumerate(x_list):                file.write("{:.5f} {:.5f}\n".format(x,y_list[i]))    if(draw==1):#是否显示图片,1表示显示        plt.scatter(x_list, y_list, marker='o')        plt.grid(True)        plt.xlabel('1st')        plt.ylabel('2nd')        plt.title('Scatter Plot')        plt.show()
if __name__ == '__main__':
   """----------------------------系统动图------------------------"""    MAX_DATA_POINTS=[]    for i in range(1,141):#141表示帧数,根据实际情况更改        path=r"G:\ANSYS Test\wechat\BIG\Chapter94\gif\12\12\\"+"12_wps图片_{:d}.jpg".format(i)#帧图片地址,根据实际情况更改地址        x_list,y_list=get_coordinate(path)        print("The number of data item:{:d}".format(len(x_list)))        MAX_DATA_POINTS.append(len(x_list))        path1 = r"G:\ANSYS Test\wechat\BIG\Chapter94\gif\12\12\\" + "{:d}.txt".format(i)#UDF文件地址,根据实际情况更改地址,保存和帧图片地址相同即可        if i % 50==0:   #每隔多少次画一次图            draw =1        else:            draw=0        write_file(x_list,y_list,path1,UDF=1,draw=draw)
   print(MAX_DATA_POINTS)

可以分为四个主要步骤:图片处理、坐标提取、数据导出、可视化。整体流程如下:


a. 图片处理和打开

代码从指定的图片路径中逐帧加载图像。使用 PIL.Image.open 函数打开图片,转换为 RGB 格式。


b. 坐标提取

通过遍历图片的每一个像素,提取颜色值较暗的像素(RGB值低于设定的阈值 (50, 50, 50))。


c. 数据导出

对每一帧图像处理后,提取到的坐标数据可以根据需要选择保存为UDF格式:如果 UDF=1,将坐标以文本格式保存,用于Fluent的自定义用户定义函数 (UDF)。


d. 可视化

每隔50帧,代码会根据参数 draw=1,调用 matplotlib.pyplot 绘制并显示一张散点图,展示提取出的坐标数据,便于可视化验证。


e. 主程序控制流程

主函数处理 141 帧图片,每一帧都会调用 get_coordinate 函数提取坐标,并调用 write_file 保存数据。

图片帧地址和输出文件的路径根据每一帧图片编号动态生成,最终每帧的UDF数据以 .txt 文件保存。


经过上面的操作之后,会生成大量的像素坐标txt文件,一张图片生成一个,这些文件即是UDF需要读取的文件。


需要调整的代码行数为:8、9、17、20、43、44、48、49


 


3.3 UDF动态导入像素点数据


下面就需要UDF读取这些txt文件


基本逻辑:每个迭代步读取一次txt文件,然后对整个计算域网格进行遍历循环,判断txt文件坐标是否满足当前的网格坐标位置,如果满足则改变温度;下个迭代步再次读取下一个txt文件。


下面为完整的UDF代码:
































































#include "udf.h"#include <stdio.h>
DEFINE_EXECUTE_AT_END(on_demand_calc){  cell_t c;  Domain *d;  Thread *t;  d = Get_Domain(1);  real xc[ND_ND];  int j = 0;  int i = 0;  //每个文件保存的像素点个数,根据情况更改  int MAX_DATA_POINTS[140] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3002, 4466, 6010, 7999, 8949, 10528, 11381, 11364, 11769, 11775, 11792, 11767, 11775, 11767, 11767, 11767, 11767, 11767, 11767, 11767, 11767, 11767, 11767, 11767, 11767, 11767, 11767, 11767, 11767, 11767, 12440, 14092, 15473, 17368, 18150, 20611, 21697, 23227, 23785, 24214, 24214, 24203, 24206, 24214, 24216, 24216, 24216, 24216, 24216, 24216, 24216, 24216, 24216, 24216, 24216, 24431, 26627, 28899, 30957, 31855, 33930, 35290, 36923, 38362, 40050, 40983, 42576, 43869, 45743, 46371, 46594, 46771, 46754, 46771, 46754, 46754, 46754, 46754, 46754, 46754, 46754, 46754, 46754, 46754, 46754, 46754, 46754, 46754, 46754, 46754, 46754, 48170, 49763, 51614, 52923, 54112, 55552, 57157, 58301, 58559, 58550, 58559, 58559, 58559, 58559, 58559, 58559, 58559, 58559, 58559, 58559, 58559, 58559, 58559, 58559, 58559, 58559, 58559, 58559, 58559, 58559 };  real *data_x = NULL;  real *data_y = NULL;  //// 动态分配内存  data_x = (real*)malloc(sizeof(real) * MAX_DATA_POINTS[N_ITER-1]);  data_y = (real*)malloc(sizeof(real) * MAX_DATA_POINTS[N_ITER-1]);  char filename[] = "G:/ANSYS Test/wechat/BIG/Chapter94/gif/12/12/";//数据点txt文件  char index[20];  sprintf(index, "%d", N_ITER);//int类型转换为字符串类型  strcat(filename, index);//字符串拼接  strcat(filename, ".txt");//字符串拼接
 FILE *fp = NULL;  fp = fopen(filename, "r");  if (fp == NULL)  {    Message("Error: Cannot open file %s\n", filename);//如果读取文件失败,则输出信息    return;  }  else  {    Message("Successfully opened file %s %d \n", filename, N_ITER);//读取成功,输出文件名  }  while ((fscanf(fp, "%lf %lf", &data_x[i], &data_y[i]) != EOF && i < MAX_DATA_POINTS[N_ITER-1]))//读取数据  {    //Message("Value %d: %lf  %lf\n", i + 1, data_x[i], data_y[i]);    i++;  }  fclose(fp);
 thread_loop_c(t, d)  {    begin_c_loop(c, t)    {      C_T(c, t) = 100;      C_CENTROID(xc, c, t);      for (j = 0; j < MAX_DATA_POINTS[N_ITER-1]; j++)//循环遍历一组数据      {        if (((xc[0] - data_x[j])*(xc[0] - data_x[j]) + (xc[1] - data_y[j])*(xc[1] - data_y[j])) < 0.0001)//判断是否满足位置,此值越小,则图形越细,可调整        {          C_T(c, t) = 1000;//满足像素点位置,令温度为1000K        }      }    }    end_c_loop(c, t)  }  //// 释放内存  free(data_x);  free(data_y);}


UDF的代码逻辑很简单,要更改的代码:

a. 14行的数组,数组个数为txt文件个数,数组值为python代码的MAX_DATA_POINTS的值。

 


b. 20行的txt文件地址,你保存的txt文件地址即可,要注意不要有中文路径



3.4 Fluent中的操作

a

 打开Fluent,读取cas和dat

打开Fluent,读取cas和dat,cas和dat最基本二维矩形计算域就可以,这里给大家提供一个。

 

b

编译UDF

 



 


c

不计算能量方程

 


d

标准初始化

 


e

生成温度云图动画

 


f

迭代步数改成帧数

 


i

计算过程

 


g

最后生成动画


 





通过百度网盘分享的文件:Chapter94

链接:https://pan.baidu.com/s/1--r4CGH94ef-9SIyGbFceQ?pwd=k2us

提取码:k2us

来源:Fluent学习笔记

附件

免费链接.txt
FluentUDFpythonUM控制ANSYS
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2024-11-01
最近编辑:14天前
Fluent学习笔记
博士 签名征集中
获赞 124粉丝 325文章 133课程 3
点赞
收藏
未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习 福利任务 兑换礼品
下载APP
联系我们
帮助与反馈