这里我介绍一种比较简单的方法,首先我们从ANSYS Fluent UDF Manual上随便找一段正确的UDF,下面这段UDF取自ANSYS 18的ANSYS Fluent UDF Manual,位于2.3.23.3. Example 1 - Pressure Profile
/ ***********************************************************************
UDF for specifying steady-state parabolic pressure profile boundary
profile for a turbine vane
************************************************************************/
#include "udf.h"
DEFINE_PROFILE(pressure_profile,t,i)
{
real x[ND_ND]; / * this will hold the position vector */
real y;
face_t f;
begin_f_loop(f,t)
{
F_CENTROID(x,f,t);
y = x[1];
F_PROFILE(f,t,i) = 1.1e5 - y*y/(.0745*.0745)*0.1e5;
}
end_f_loop(f,t)
}
我们将上面的UDF源代码存为prepare.c
我们启动Fluent
然后我们直接编译我们刚才保存的prepare.c
我们打开Visual Studio(我是Visual Studio 2013英文版)
DLL的代码很简单,就是输出Hello Fluent,这里有一点需要注意一下Solution PlatForms一定要根据Fluent的位数来选择,默认是编译为Win32,而我们现在的一般使用的是64位的Fluent,所以我们需要改变为x64才行(见截图)
#include / *包含输入输出流头文件*/
using namespace std;
/ *一定要这样写,以c语言的形式导出,在Fluent当中才能识别*/
extern "C" __declspec(dllexport) void CppDynamicLinkLibrary()
{
cout << "Hello Fluent" << endl; / *输出“Hello Fluent”*/
}
然后准备真实需要编译且加载了加载第三方动态链接库的UDF源文件,代码如下:
#include "udf.h"
/ *链接我们刚才动态链接库的函数*/
extern void CppDynamicLinkLibrary();
/ *******************************************
*我们在每次迭代完成以后,
*用动态链接库中的函数输出一次“Hello Fluent”
********************************************/
DEFINE_ADJUST(my_adjust,d)
{
CppDynamicLinkLibrary(); / *调用动态链接库中的函数*/
}
将源代码也保存为prepare.c
然后前面动态链接库项目文件夹下
重新打开Fluent
导入网格,设置好各种求解参数
加载刚才编译的UDF(注意:此处只需要加载(Load),而不需要编译(Build)了!见截图)
求解运行算例
附:
makefile文件的注释说明
###########################################################
##
## Copyright 2003-2011 ANSYS, Inc.
## All Rights Reserved
##
###########################################################
#
# purpose:
# This file is the makefile for NT UDF builds.
#
# usage:
# Change file name 'makefile_nt.udf' to 'makefile'.
# Place the makefile file in the target dir.
# Place the helper file 'user_nt.udf' in same directory.
# Edit user_nt.udf file.
# Execute an 'nmake' (no arguments needed).
#
# notes:
# The user should not need to change this file.
# The following macros are expected to be in the user_nt.udf file:
# SOURCES, VERSION, PARALLEL_NODE and USER_OBJECTS.
# The macro FLUENT_LIB is automatically defined here based on VERSION
# and PARALLEL_NODE.
# Only this makefile and the helper file 'user_nt.udf' needs to be
# the target dir, all other files are automatically generated,
# and removed in an 'nmake clean'.
# The source file is expected in ..\..\src directory.
# Make sure the VC compiler is set up for command line mode, use
# the file Vcvars32.bat from Visual Studio to assist this.
# This makefile uses the public domain program 'sed', make sure
# sed is in your executable path.
# The '^' char in the SRC literal is a quote for the '\' char,
# otherwise interpretted as a line continuation char.
# Use the 'nmake clean' command to restart builds.
###########################################################
#包含user_nt.udf文件
!INCLUDE user_nt.udf
# These need to be updated for each release.
LIB_RELEASE=1800
RELEASE=18.0.0
# If a local path can be found, use it
!IF (("$(FLUENT_INC_LOCAL_RESERVED)" != "") && ("$(FLUENT_INC)" == ""))
FLUENT_INC = $(FLUENT_INC_LOCAL_RESERVED)
!ENDIF
# it is assumed $(FLUENT_INC)is already set.
!IF !DEFINED(FLUENT_INC)
! ERROR You need to define the environmental variable FLUENT_INC.
!ENDIF
!IF !DEFINED(FLUENT_ARCH)
!IF ("$(PROCESSOR_ARCHITECTURE)" == "ALPHA")
FLUENT_ARCH = ntalpha
!ENDIF
!IF ("$(PROCESSOR_ARCHITECTURE)" == "x86")
FLUENT_ARCH = ntx86
!ENDIF
!IF ("$(PROCESSOR_ARCHITECTURE)" == "AMD64")
FLUENT_ARCH = win64
!ENDIF
!IF ("$(PROCESSOR_ARCHITEW6432)" == "AMD64")
! MESSAGE You seem to be working on a 64-bit machine, but in a 32-bit build environment.
! MESSAGE If you really want to build the UDF for the "ntx86" FLUENT_ARCH, then please
! MESSAGE set the "FLUENT_ARCH" environment variable to "ntx86" before calling this.
! ERROR Aborting.
!ENDIF
!ENDIF
# set FLUENT_LIB based on VERSION macro
!IF (("$(VERSION)" == "2d") || ("$(VERSION)" == "3d") || \
("$(VERSION)" == "2ddp") || ("$(VERSION)" == "3ddp"))
FLUENT_LIB = fl$(LIB_RELEASE).lib
LIBS = /Libpath:"$(FLUENT_INC)"\fluent$(RELEASE)\$(FLUENT_ARCH)\$(VERSION)
!ENDIF
!IF (("$(VERSION)" == "2d_host") || ("$(VERSION)" == "3d_host") || \
("$(VERSION)" == "2ddp_host") || ("$(VERSION)" == "3ddp_host"))
COMM = net
FLUENT_LIB = mport.lib fl$(LIB_RELEASE).lib
LIBS = /Libpath:"$(FLUENT_INC)"\fluent$(RELEASE)\$(FLUENT_ARCH)\$(VERSION) /Libpath:"$(FLUENT_INC)"\fluent$(RELEASE)\multiport\$(FLUENT_ARCH)\$(COMM)\shared
!ENDIF
!IF (("$(VERSION)" == "2d_node") || ("$(VERSION)" == "3d_node") || \
("$(VERSION)" == "2ddp_node") || ("$(VERSION)" == "3ddp_node"))
!IF (("$(PARALLEL_NODE)" != "none") && ("$(PARALLEL_NODE)" != "net"))
PARALLEL_NODE = mpi
!ENDIF
COMM = mpi
FLUENT_LIB = mport.lib fl_$(PARALLEL_NODE)$(LIB_RELEASE).lib
LIBS = /Libpath:"$(FLUENT_INC)"\fluent$(RELEASE)\$(FLUENT_ARCH)\$(VERSION) /Libpath:"$(FLUENT_INC)"\fluent$(RELEASE)\multiport\$(FLUENT_ARCH)\$(COMM)\shared
!ENDIF
###########################################################
#定义变量SRC,其中^表示回车符成为字符串的一部分,其实就是表示字符串..\..\src\
SRC = ..\..\src^\
#使用vc的编译器
CC = cl
#CFLAGS用来指定头文件的路径
# compile flags
# /c for compile only, /Za for ansi c and __STDC__ is set
CFLAGS = /c /Za /DUDF_EXPORTING /DUDF_NT /DWIN64
#目标文件为libudf.dll动态链接库
TARGET = libudf.dll
UDFDATA = udf_names.c
# generate object names from source names
#".cpp=.obj"的意思是做一个替换
#把变量比如$CSOURCES,$SOURCES2,$SRC_OBJECT,$UDFDATA
#所有的[.cpp]的字符串转换为[.obj]字符串
SOURCES2 = $(CSOURCES:..\..\src\=) #这里实际上就是test.c
SRC_OBJECT = $(SOURCES2:.cpp=.obj) #这里实际上如果是cpp文件就是test.obj,否则默认不发生变化
SRC_OBJECT = $(SRC_OBJECT:.c=.obj)#这里如果是c文件就是test.obj
UDF_OBJECT = $(UDFDATA:.c=.obj) #这里实际上是udf_name.obj
OBJECTS = $(UDF_OBJECT) $(SRC_OBJECT) $(USER_OBJECTS) #
#此处为包含的头文件
INCLUDES= -I. \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\$(FLUENT_ARCH)\$(VERSION) \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\main \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\addon-wrapper \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\io \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\species \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\pbns \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\numerics \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\sphysics \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\storage \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\mphase \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\bc \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\models \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\material \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\amg \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\util \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\mesh \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\udf \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\ht \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\dx \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\turbulence \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\parallel \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\etc \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\ue \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\dpm \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\src\dbns \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\cortex\src \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\client\src \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\tgrid\src \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\multiport\src \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\multiport\mpi_wrapper\src
GPU_LIB=
!IF ("$(GPU_SUPPORT)" == "on") #如果开启了GPU加速,那么久将GPU的头文件也包含到INCLUDE里面,默认为off的
INCLUDES = $(INCLUDES) \
-I"$(FLUENT_INC)"\fluent$(RELEASE)\multiport\gpu_wrapper\include
GPU_LIB = OpenCL.lib
LIBS = $(LIBS) /Libpath:"$(FLUENT_INC)"\fluent$(RELEASE)\multiport\gpu_wrapper\$(FLUENT_ARCH)\stub
!ENDIF
default: $(TARGET) #假想目标,每次更新$(TARGET)即libudf.dll
$(UDF_OBJECT): $(UDFDATA) #从udf_name.c编译生成目标文件udf_name.obj
$(CC) $(CFLAGS) $(INCLUDES) $**
#采用cl编译器 替换(编译但不链接 禁用语言扩展 定义预处理器) 包含头文件 编译所有的文件
$(SRC_OBJECT): $(CSOURCES) #从test.c编译生成目标文件test.obj
@echo # Generating ud_io1.h
resolve.exe -udf $(CSOURCES) -head_file ud_io1.h
$(CC) $(CFLAGS) $(INCLUDES) $**
#采用cl编译器 替换(编译但不链接 禁用语言扩展 定义预处理器) 包含头文件 编译所有的文件
$(TARGET): makefile user_nt.udf $(UDF_OBJECT) $(SRC_OBJECT) #生成目标文件libudf.dll
@echo # Linking $@ because of $?
link $(LIBS) /dll /out:$(TARGET) \ #/dll表示生成dll文件
$(OBJECTS) $(FLUENT_LIB) $(GPU_LIB) #需要链接文件
$(UDFDATA): makefile $(SRC_OBJECT)
#自动生成udf_name.c文件
@echo # Generating $@ because of $?
@echo > $@
@echo >> $@
@echo #include "udf.h" >> $@
@echo #include "prop.h" >> $@
@echo #include "dpm.h" >> $@
@sed -n "s/^ *\(DEFINE_[_A-Z]*(.*)\)/extern \1;/p" $(CSOURCES) >> $@
@echo __declspec(dllexport) UDF_Data udf_data[] = { >> $@
@sed -n "s/^ *DEFINE_\([_A-Z]*\)( *\([_a-zA-Z0-9]*\).*)/\{\"\2\", (void (*)(void))\2, UDF_TYPE_\1\},/p" $(CSOURCES) >> $@
@echo }; >> $@
@echo __declspec(dllexport) int n_udf_data = sizeof(udf_data)/sizeof(UDF_Data); >> $@
@echo #include "version.h" >> $@
@echo __declspec(dllexport) void UDF_Inquire_Release(int *major, int *minor, int *revision) >> $@
@echo { >> $@
@echo *major = RampantReleaseMajor; >> $@
@echo *minor = RampantReleaseMinor; >> $@
@echo *revision = RampantReleaseRevision; >> $@
@echo } >> $@
#清理输出文件
clean:
@del *.dll *.obj *.ilk *.exp *.lib *.pdb *.c
tellfluentarch:
@echo FLUENT_ARCH: $(FLUENT_ARCH)
@echo PROCESSOR_ARCHITECTURE: $(PROCESSOR_ARCHITECTURE)
@echo PROCESSOR_ARCHITEW6432: $(PROCESSOR_ARCHITEW6432)
$(OBJECTS): $(HSOURCES)