1 Star 0 Fork 63

谢凡 / openFoamUserManual

forked from poplee / openFoamUserManual 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
49.functions.md 23.29 KB
一键复制 编辑 原始数据 按行查看 历史
poplee 提交于 2020-08-27 22:19 . images updated

Part VI 后处理

​ 在OpenFOAM中,有两种主要的后处理方法。首先,有一些工具在模拟完成后执行。这些工具处理模拟结果的写入数据。sampleparaView是这类的两个工具。

​ 除此之外,还有实时后处理。实时后处理是在生成模拟结果数据时执行某种操作。因此,实时后处理允许更精细的时间问题。函数对象,例如用于计算力或阻力系数,是一个实时后处理的示例。这种方法的最大缺点是,用户开始模拟之前,必须知道预期的后处理的步骤。有关实时后处理详细信息请看http://www.openfoam.com/features/runtime-postprocessing.php。

49 functions

​ 一般来说,函数对象是以与函数类似的方式使用的对象。函数对象的这一主要优点是它们可以有一个永久的状态。此状态可用于存储数据(在“调用”函数对象之间)。一个非常有说服力的例子是OpenFOAM的函数对象 fieldAverage,它用于计算场的时均值。此函数对象需要在每次计算时间步长时更新自身,并且当前的时均场需要在fieldAverage的“调用”之间保留。

​ 函数对象通常用于一个特定的目的,例如计算场量的时均值。因此,在OpenFOAM中可用的函数对象数量很多,而且在持续增加。下面列出一些,让人了解OpenFOAM函数对象涵盖任务之广泛:

fieldAverage 计算场量的时均值

fieldValue系列 计算场量(或其他操作)的空间平均值

forces 计算物体(表面)上的力

forceCoeffs 计算力的系数,例如阻力、升力和扭矩

sampledSet 保存某个区域的场量的值,例如沿一条直线

probes 在某些点保存场量值

streamLine 计算流线

scalarTransport 求解被动标量输运方程

codedFunctionObject 在一个不是从零头开始的框架中实现自己的函数对象

上面的列表只是可用功能的一小部分。所有的可用函数对象资料,查看OpenFOAM的源码[141]。

49.1保持最新

​ 使用函数对象进行实时后处理是OpenFOAM的一个特性,它在应用程序和日常使用非常多,这与mesh类的内部工作方式不同。因此,函数对象更受开发者关注的是添加新的函数对象,扩展已有的函数对象,或重新组织和重命名现有函数对象。

​ 前两点(添加和扩展)显然是对用户有利,而后一点(重组)在减少代码重复或便于维护方面,最可能对开发人员有利。函数对象的重组可能和重命名同步进行[142]。在这种情况下,你可能需要修改函数对象定义,当将你的算例迁移到新的[143]版本时。

​ 除了使用最新版本的OpenFOAM的所有其他好处外,尤其是在函数对象,如果OpenFOAM的版本已经包含了一个实现你所需功能的函数对象,您就可以不必自己开发一个函数对象。

49.2 定义

​ 函数对象在文件controlDict中定义。在那里创建一个包含所有必要的信息的函数字典。列表320显示了这样一个定义的基本结构。

​ 每个函数都有一个名称。在列表320中,这个名称在NAME占位符处被声明。这个名称也是OpenFOAM在算例目录中创建的文件夹的名称。在那里,存储所有由函数对象产生的数据。

​ 每个函数对象也有一个类型。需要在TYPE占位符的位置指定此类型。类型必须来自可用函数的列表。要了解哪些函数可用,则可以使用banana-trick[144]。列表321显示了由banana-trick引起的错误消息。

​ 占位符LIBRARY标记需要输入库名称的位置。函数对象不是一个单独可执行的程序。它只是一个供其他程序使用的库。在在我们的例子中,函数对象由解算器调用。因此,函数对象不会编译成可执行的。编译器在编译函数对象时创建库。此库包含机器可读形式的函数。

	关键字**enabled**是可选的。使用此关键字函数,对象可以从执行中排除。
functions
{
    NAME
    {
         type             TYPE ;
         functionObjectLibs (" LIBRARY ");
         enabled         true;
        /*
   		  Definition
    	*/
    }
}

列表320:文件controlDict中函数对象的定义

--> FOAM FATAL ERROR :
Unknown function type banana
Valid functions are :
13
(
cellSource
faceSource
fieldAverage
fieldCoordinateSystemTransform
fieldMinMax
nearWallFields
patchProbes
probes
readFields
sets
streamLine
surfaceInterpolateFields
surfaces
)

列表321 :banana-trick的输出;应用于关键字type

49.3 控制

​ 所有函数对象或多或少都与基类functionObject直接相关,后者在文件**$FOAM_SRC/OpenFOAM/db/functionObjects/functionObject/functionObject.H**中定义,这个类定义

所有函数对象的最小公共行为。因此,学习这个类,正如它应用于所有函数对象一样,我们也许会有回报。

49.3.1 时间控制

函数对象的阶段

​ 一些OpenFOAM函数对象可能有一些需要更新的内部状态,而另一些对象有一些内部状态需要更新时,可能不需要内部状态。简单的函数对象,后一类情况,例如,函数对象fieldValue族中的函数对象surfaceRegion,只需将指定patches程序中的数据写入磁盘情况,将选定的数据写入磁盘可能会失败。这只是在写入时才执行。

​ 另一方面,函数对象可能需要从结果数据中计算数据,因此需要一个内部状态,例如,fieldAverage函数对象需要为连续更新时均值,即使它不太频繁地将它们写入磁盘。

​ 因此,函数对象的操作阶段分为执行(用于更新其内部状态)和写入(用于写入数据,并计算要写入的数据,这不是内部状态)

执行和写控制

​ 何时写入的函数对象的属性是writeControlwriteInterval,在OpenFOAM旧版本中,这些属性是outputControloutpunterval。它们控制从函数对象写入磁盘数据的时间和频率。

​ 存在一对相似的控件(executeControlexecuteInterval)来控制函数对象的执行,即内部状态更新。

​ 请注意,当能够使用writeInterval adjustableRunTime设置时;对于函数对象的写入间隔,一般来说,我们需要确保对模拟进行相同的设置。如果模拟使用设置writeInterval runTime,则函数对象的设置被否决。

启用

​ 启用标志控制是否启用函数对象。这需要一个布尔值和控制是否执行函数对象。这对测试或调试模拟算例可能很有用。此标志允许您在不从controlDict 中删除的情况下,定义和停止使用函数对象。从算例文件编辑的角度来看,这个标志的一个粗暴的替代方法是注释函数对象定义。但是,将标志从“开”改为“关”,或者相反,所需更少字符,相比更改为注释和取消注释[145]。

timeStarttimeEnd控制何时开始和何时停止使用函数对象。这些控件是可选的,在大多数情况下被省略。当省略时,默认行为是执行函数对象,从模拟开始直到模拟完成。事实上,默认值是一个负数,对于timeStarttimeEnd来说是个大得离谱的数字[146]。因此,在timeStart的默认值之前,不会启动任何可能的模拟,或者任何大于timeEnd的默认值。这样,一个简单的与当前时间进行比较就足够了,就不需要条件语句了。

49.3.2 区域控制

region关键字控制函数对象应用于哪个网格区域。只有一个网格区域时都可以省略,这种情况下说明网格区域是多余的。然而,在OpenFOAM中也有具有多个网格区域的,如共轭传热模拟。在这种情况下,当求解传热时有一个网格(区域)为流体区域,一个网格(区域)为的固体部分。在这种情况下,我们可以使用一个函数对象来记录流体和固体区域的平均温度。因此,我们指定两个函数对象来计算体积平均温度,但是,我们需要指定要为其执行函数对象的区域。

​ 负责选择要操作的网格区域的(抽象类[147])基类是regionFunctionObject。许多函数对象或多或少是直接从regionFunctionObject派生的。其中包括fieldValues系列的函数对象以及fieldMinMaxfieldAverage

49.4 探针

​ 函数探针在空间中的指定点保存特定场量的值。列表322显示了一个探针函数对象定义的示例。

​ 此函数对象的类型为probes。函数对象的名称是probes1。此函数生成的数据存储在probes1目录中。此目录包含一个子目录。此子目录名称对应于模拟开始的时间。这样可以防止文件在某个时间点继续模拟时被覆盖。

​ 图112显示了模拟结束后的目录树。在那里,probes1文件夹包含一个名为0的子目录。这是模拟开始的时间。0文件夹包含文件p和U。

​ 关键字outputControloutputInterval是可选的。正如他们的名字所示,他们控制着数据写入硬盘的方式。

​ 字段包含感兴趣场的名称。probeLocations 包含一系列点。计算这些点位置指定场的数据,并将其写入文件。文件名就是场名。列表322将生成两个文件。文件p包含所有位置的压力值,文件U将包含所有位置的速度值。

probes函数包含在文件中libsampling.so文件。 这些信息可以从教程获得。有关如何在教程中搜索特定信息的更多信息,请参见第66.3节。

functions
{
	probes1
	{
		type 			probes ;
		functionObjectLibs (" libsampling .so ");
		enabled 		true ;
		outputControl 	timeStep ;
		outputInterval 	1;
		fields
		(
			p
			U
		);
		probeLocations
		(
			( 0.0254 0.0253 0 )
			( 0.0508 0.0253 0 )
		);
	}
}

​ 列表322:controlDict文件中probes的定义

图像112 ​ 图112: 模拟结束后目录树的一部分

49.4.1 陷阱

区域外的探测位置

如果探针位置在域之外,OpenFOAM将发出警告消息并继续模拟。

--> FOAM Warning :
	From function findElements :: findElements ( const fvMesh &)
	in file probes / probes .C at line 102
	Did not find location (0.075 0 0.48) in any cell. Skipping location.

​ 列表323:探针位于区域外

未知和不存在的场

如果探测字典包含不存在要探测的字段,则不会警告或发布错误消息。OpenFOAM只是继续计算。如果字典中没有要探测的有效字段,则不会执行探测功能。因此,不会创建存储数据的文件夹。

在动网格中使用探针

​ 当我们使用探针时,OpenFOAM会在网格中搜索包含指定探针位置的单元。更具体地说,它确定包含探针位置的单元的单元索引。因此,OpenFOAM可以很容易得到探测场的单元值。实际上,OpenFOAM中的一个场是一个值列表,而单元索引用于导航列表。

​ 然而,当我们使用移动网格时,与空间中某一点相关的单元索引,在时间上可能会发生变化,例如旋转网格区域内探测一个点时。因此,每次网格更新时,需要确保被探测的单元索引也被更新。

​ 在OpenFOAM中,探针有一个布尔标志(fixedLocations)来控制单元索引的更新,默认情况下,此标志设置为true,表示不需要更新。在下面列表324中,我们看到头文件probes.C中此标志的说明。

// - Fixed locations , default = yes
// 	 Note : set to false for moving mesh calations where locations
// 		  should move with the mesh
bool fixedLocations_ ;

​ 列表324:在probes.HfixedLocations布尔标志的描述

​ 使用移动网格时,将fixedLocations标志添加到probesDict中,如清单325所示下面。

fields
(
	...
)
probeLocations
(
	...
)
// add this for cases using moving meshes
fixedLocations false ;

​ 列表325:使用带有动网格的探针时,向probesDict添加fixedLocations标志

49.5 场平均

fieldAverage计算时均场。列表326显示一个函数已设置例子。

functions
{
	fieldAverage1
	{
		type 			fieldAverage ;
		functionObjectLibs ( " libfieldFunctionObjects .so" );
		enabled 		true ;
		outputControl 	outputTime ;
		fields
		(
			Ua
			{
				mean 		on;
				prime2Mean 	off ;
				base 		time ;
			}
		);
	}
}

​ 列表326:文件controlDictfieldAverage函数对象的定义

fieldAverage函数对象可以提供一个平均窗口尺寸和名称来计算滑动平均。在这种情况下,生成的平均值场除了以场命名和加后缀Mean,还将窗口名作为文件名后缀。使用此功能,可以计算一个场的多个平均值。列表327显示了场U.water的两个平均值。

​ 如果没有指定窗口,fieldAverage从函数对象的开始时间计算平均值。这个结果场包含要平均的场的名称和后缀Mean。如果指定了一个窗口尺寸和窗口名称,则结果场的名称将窗口名称作为扩展名。

U. water U. waterMean U. waterMean_w1  

​ 列表 327: U. water的多个平均值

49.6 面源faceSource

49.6.1 平面上的平均

​ 面源从曲面(面)中提取数据。列表328显示了在一个切割平面上,场量的平均值如何设置。

	functions
	{
		fieldAverage1
		{
			type 			fieldAverage ;
			functionObjectLibs ("libfieldFunctionObjects.so" );
			enabled 		true ;
			outputControl 	outputTime ;	
		// Output to log & file (true) or to file only
		log 			true ;
		
		// Output field values as well
		valueOutput 	false ;
		
		// Type of source : patch/faceZone/sampledSurface
		source 			sampledSurface ;
		
		sampledSurfaceDict
		{
			// Sampling on triSurface
			type 		cuttingPlane ;
			planeType 	pointAndNormal ;
			pointAndNormalDict
			{
				basePoint ( 0 0 0.3 );
				normalVector ( 0 0 1 );
			}
			interpolate true ;
		}
		// Operation : areaAverage/sum/weightedAverage ...
		operation 		areaAverage ;
		fields
		(
			alpha
		);			
	  }
	}

​ 列表328:在controlDict文件中定义一个faceSource对象

49.6.2计算边界上的体积流率

​ 列表329显示了一个函数对象的定义,该对象用于计算边界面上的体积流率。其中的关键点是定义权重场和使用求和运算。这个权重场是自动应用于后处理场的,不需要指定一个操作,如weightedSum。如果未定义权重场,则不使用权重场。

functions
{
	faceIn
	{
		type 			faceSource ;
		functionObjectLibs ("libfieldFunctionObjects.so");
		enabled			true ;
		outputControl 	timeStep ;
		log 			true ;
		valueOutput 	false ;
		source 			patch ;
		sourceName 		spargerInlet ;
		surfaceFormat 	raw;
		operation 		sum;
		weightField 	alpha1;
		

		fields
		(
			phi1
		);
	}

}

​ 列表239:在文件controlDict中定义一个faceSource对象

49.6.3 陷阱:valueOutput

​ 选项valueOutput将采样曲面上的场量值写入磁盘。当outputControl设置为timeStep时,会使用巨大的磁盘空间。在这种情况下,每个时间步都会写入场量值。除非确实需要,否则应禁用选项valueOutput

​ 图113显示了两个时间步写入磁盘后处理文件夹的内容。对于每个采样场,采样片上的场量值将写入磁盘的surface文件夹中的文件中。

图像113

​ 图113:postPrecessing 文件夹中内容

49.7 单元源

cellSource函数对象作用于网格的所有单元或cellZone的单元。

​ 列表330显示了cellSource函数对象的定义。在本例中,在左边的单元里,包含了区域的一部分。函数对象计算空气体积组分的体积平均值。这个关键字valueOutput设置为false,并被注释标记为邪恶,原因如第49.6.3条所述。

functions
{
	airContent_left
	{
		type 			cellSource ;
		functionObjectLibs ("libfieldFunctionObjects.so");
		enabled 		true ;
		outputControl 	timeStep ;
		log 			true ;
		valueOutput 	false ; // evil
		source 			cellZone ;
		sourceName 		left ;
		operation 		volAverage ;
		 fields
		 (
			alpha.air
		 );
	 }
}

​ 列表330:cellSource函数对象使用例子

49.8 读入场

​ 如果我们想后处理一个算例,我们使用创建自定义场的自定义求解器计算,并且后处理涉及这些自定义场,在运行后处理函数对象时,OpenFOAM很可能会抱怨这些场没有在数据库中。就在那时,读入场就可以上台了。

​ 头文件中的说明如下:

​ 从时间目录中读取场,并将其添加到万个数据库中,为进一步的后处理。

​ 这个函数对象服务于读取指定场,并将这些场添加到数据库中。因此,添加后处理函数对象的这个函数对象,允许我们使用OpenFOAM的标准函数对象后处理任何自定义场。

49.9 写对象

​ 如果我们想对默认情况下不写入的场进行后期处理,那么我们可以告诉OpenFOAM写入指定的场到磁盘中。此对象的文件头函数说明:

​ 允许指定注册到数据库的对象的不同写入频率。

49.10 执行C++代码作为函数对象

​ OpenFOAM让执行C++代码作为一个函数对象[148]成为可能。默认情况下此功能禁用。要激活它,必须更改一个标志。单个用户在**~/.OpenFOAM/$WM_PROJECT_VERSION/controlDict中设置,系统范围内的在$WM_PROJECT_DIR/etc/controlDict**中。在其中一个文件,列表331所示的标志必须设置为1。第一个文件可能不存在,即没有用户指定设置。作者没有探讨优先权问题(用户设置优先于系统范围设置)。

​ 列表332显示这个特性的一个示例。读取场量U1U2p,并且一些计算值将打印到终端。

// Allow case - supplied C++ code (# codeStream , codedFixedValue )
allowSystemOperations 1;  

​ 列表331:运行 算例提供的 C++代码

extraInfo
{
	type 			coded ;
	functionObjectLibs ("libutilityFunctionObjects.so");
	redirectType 	average ;
	code
	#{
		const volVectorField& U1 = mesh().lookupObject<volVectorField>("U1");
		const volVectorField& U2 = mesh().lookupObject<volVectorField>("U2");
		Info<<" max U1 = "<<max(mag(U1)).value()<< ", U2 = "<<max(mag(U2)).value()<< endl ;
		const volScalarField& p = mesh().lookupObject<volScalarField>("p");
		Info<<"p min/max =  "<<min(p).value()<< ", " << max(p).value()<<endl ;
	#};
}

​ 列表332:用C++定义一个函数对象

​ 当求解器被调用时,所谓的编码函数对象会被即时编译。列表333显示了求解器输出的一部分。在进入时间循环和第一次计算之间,从controlDict读取代码并粘贴到一个编码functionObject的模板中。

Starting time loop

Using dynamicCode for functionObject extraInfo at line 69 in "/home/user/OpenFOAM /user-2.1.x/
	run/twoPhaseEulerFoam/bubbleColumn/system/controlDict::functions::extraInfo"
Creating new library in " dynamicCode/average/platforms/linux64GccDPOpt/lib/
	libaverage_731fed868edc5a1d75988808649ac874cf00e044.so"
Invoking "wmake -s libso/home/user/OpenFOAM/user-2.1.x/run/twoPhaseEulerFoam/bubbleColumn/
	dynamicCode/average "
wmakeLnInclude : linking include files to ./lnInclude
Making dependency list for source file functionObjectTemplate.C
Making dependency list for source file FilterFunctionObjectTemplate.C
’/home/user/OpenFOAM/user-2.1.x/run/twoPhaseEulerFoam/bubbleColumn/dynamicCode/average/../
	platforms/linux64GccDPOpt/lib/libaverage_731fed868edc5a1d75988808649ac874cf00e044.so’ is
	up to date .
Courant Number mean : 1.68517e-05 max: 0.00363
Max Ur Courant Number = 0.00363
Time = 0.001

MULES: Solving for alpha1

​ 列表333:C++编码函数对象的即时编译

​ OpenFOAM在算例目录中创建一个名为dynamicCode的目录。在那里,与编码函数对象有关的所有文件、源文件和二进制文件都可以找到。图114显示了OpenFOAM编译编码的functionObject后的目录树。

图像114 ​ 图114:编码函数对象编译后的目录

49.11 壁面热流密度

wallHeatFlux函数对象可用于确定壁面热流密度。默认情况下,wallHeatFlux计算所有patches中类型为wall的壁面热流密度。或者,patches列表可以传递给使用patches关键字的函数对象。

确定物理单位

在列表334的第7行中,我们看到壁面热流密度场用物理单位千克每立方秒初始化。在第17行中,我们看到壁热通量是由焓的热扩散率和焓内能场[149]的梯度的乘积计算得出的。

$$ \rm[wallHeatFlux] =[alpah] \cdot [he.snGrad()] \tag{161} $$

$$ \rm [wallHeatFlux] =\frac{kg}{m s} \cdot \frac{J}{kg} \frac{1}{m} =\frac{1}{m s} \cdot \frac{W s}{m} = \frac{W}{m^2} \tag{162} $$

上面的方程说明,如何通过这个函数对象,推导壁面热流密度的物理单位。实际上,结果是每平方米瓦特。注意,α场是热场焓的扩散系数[150]。

tmp<volScalarField> twallHeatFlux
(
	volScalarField::New
	(
		type () ,
		mesh_ ,
		dimensionedScalar(dimMass/pow3( dimTime), 0)
	)
);

/* some code removed for brevity */

forAll(wallHeatFluxBf, patchi )
{
	if(!wallHeatFluxBf[patchi].coupled())
	{
		wallHeatFluxBf[patchi] = alphaBf[patchi]*heBf[patchi].snGrad();
	}
}

列表334:wallHeatFlux.C中壁面热流密度的计算

wallHeatFlux函数对象,不仅将壁面热流作为一个场来计算,而且还可以打印每个patch的积分和极值到终端,并将这些值写入数据文件。积分值当然是每个patch传递的能量,是以瓦特为单位。

49.12 模拟完成后执行函数

49.12.1 execFlowFunctionObjects

execFlowFunctionObjects是OpenFOAM的后处理工具。此工具允许用户执行功模拟完成后的函数对象。通常,函数对象是在模拟过程中执行的。然而,在某些情况下,将一个函数应用于已经完成的模拟的数据集是有用的,例如用于测试函数。

在单独的文件中定义函数对象

​ 列表335显示了一个只包含函数对象定义的文件。为了清楚起见,这个文件名为functionDict。在单独的文件中定义函数在某种程度上反映了分工。文件controlDict控制求解器,而文件functionDict定义函数对象。文件

functionDict可以通过**#include语句包含在文件controlDict**中。参见第11.3.5节例子。

FoamFile
{
	version 2.0;
	format ascii ;
	class dictionary ;
	location " system ";
	object functionDict ;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
functions
{
	probes1
	{
		type 		probes ;
		functionObjectLibs ("libsampling.so");
		dictionary 	probesDict ;
	}
}

​ 列表335:在单独的字典中定义函数。文件functionDict

运行execFlowFunctionObejcts

​ 必须告诉execFlowFunctionObjects,这些函数是在单独的文件中定义的。默认情况下,工具

读取文件controlDict。通过使用参数-dict,用户可以指定一个包含函数字典的替代文件。

execFlowFunctionObjects -noFlow -dict functionDict  

​ 列表336:调用execFlowFunctionObjects

1
https://gitee.com/stillfantasying/openFoamUserManual.git
git@gitee.com:stillfantasying/openFoamUserManual.git
stillfantasying
openFoamUserManual
openFoamUserManual
master

搜索帮助