相场模拟——枝晶生长(COMSOL实现雪花形成案例)

发布时间 2023-07-16 16:48:21作者: blogzzt

一、介绍

1.1 物理含义

雪花是人们最常见的枝晶。枝晶生长是一种生长的不稳定现象,常起因于过冷的液体,或晶体的生长速度受限于溶质原子向固体表面的扩散速度。造成以上条件的原因,可以是液相中负的温度梯度,也可以是负的浓度梯度。在这种模式下,晶体倾向于在其棱角处优先生长,从而形成突触状结构。

这篇博文会介绍用相场模拟的方法,模拟雪花生长的过程。

1.2 相场模拟介绍

在相场法中,使用连续变量描述微观结构特征。这些变量有两种形式:代表物理性质的守恒变量,如原子浓度或材料密度;描述材料微观结构(包括晶粒和不同相)的非守恒序参数(order parameters)。这些连续变量的演化用自由能的函数表达,可以定义为一个PDE偏微分方程系统。该相场模型还可以与其他物理相耦合,例如力学或热传导。这些模型方程可以用多种方法求解,包括有限差分法、谱方法和有限元法。

相场PDE是各种变量的演化方程,是自由能泛函F的函数。

对于守恒变量(conserved variables),其满足Cahn-Hilliard方程:

其中ci是保守变量,Mi是相应的迁移率。

对于非保守量,其满足 Allen-Cahn方程:

ηj是序参量,Lj是序参数的迁移率。

 自由能函数包括局部自由能,梯度自由能,以及系统的其它额外自由能(比如电势能,弹性势能等等)。可以用如下公式计算:

f_loc: local free energy density; f_gr: gradient energy density; Ed: additional sources of energy in the system, such as deformation or electrostatic energy.

 

二、枝晶生长模型

模型包含两个变量: 相场θ(r, t),温度场T(r, t)

θ = 0 表示液态;θ = 1 表示固态;

PDE:

其它方程:

 

三、COMSOL建模

1.      建立一个2D,两个变量的General Form PDE模型(自变量为theta, T),瞬态求解。

 

 2.      Global Definition-> Parameters

K 1.8 1.8
TAU 0.0003 3E-4
EPS 0.01 0.01
DELTA 0.02 0.02
ANGLE0 1.57 1.57
ANISO 6 6
ALPHA 0.9 0.9
GAMMA 10.0 10
TEQ 1.0 1

 

 

 

4.      Model -> Definition -> Variables

epsilon EPS*(1+DELTA*cos(ANISO*(angle-ANGLE0)))
epsilonp -EPS*ANISO*DELTA*sin(ANISO*(angle-ANGLE0))
epsilon2 epsilon*epsilon
m ALPHA/pi*atan(GAMMA*(TEQ-T)) rad
angle if(abs(thetax)>eps,atan2(thetay,thetax)+pi*(atan2(thetay,thetax)<0),pi/2*((thetay>0)+3*(thetay<0))) rad

 

5.      Geometry

建立一个关于原点对称的9×9矩形

 

6.      PDE设置

 

 

初始值

 

7. Mesh

建立Mapped型网格,Maximum element size为0.1(可适当加密,0.06~0.08左右效果比较好)

 

 8.      Study求解时间为range(0,0.1,0.3)

 

导出的部分matlab代码:

function out = model
%
% crystalGrowth.m
%
% Model exported on Jul 16 2023, 16:41 by COMSOL 6.0.0.318.

import com.comsol.model.*
import com.comsol.model.util.*

model = ModelUtil.create('Model');

model.component.create('comp1', true);

model.component('comp1').geom.create('geom1', 2);

model.component('comp1').mesh.create('mesh1');

model.component('comp1').physics.create('g', 'GeneralFormPDE', {'theta' 'T'});

model.study.create('std1');
model.study('std1').create('time', 'Transient');
model.study('std1').feature('time').setSolveFor('/physics/g', true);

model.param.set('K', '1.8');
model.param.set('TAU', '0.0003');
model.param.set('EPS', '0.01');
model.param.set('DELTA', '0.02');
model.param.set('ANGLE0', '1.57');
model.param.set('ANISO', '6');
model.param.set('ALPHA', '0.9');
model.param.set('GAMMA', '10.0');
model.param.set('TEQ', '1.0');

model.func.create('step1', 'Step');
model.func('step1').set('location', 0.09);
model.func('step1').set('from', 1);
model.func('step1').set('to', 0);
model.func('step1').set('smooth', 0.05);

model.variable.create('var1');
model.variable.remove('var1');
model.component('comp1').variable.create('var1');

model.component('comp1').geom('geom1').run;

model.component('comp1').variable('var1').set('epsilon', 'EPS*(1+DELTA*cos(ANISO*(angle-ANGLE0)))');
model.component('comp1').variable('var1').set('epsilonp', '-EPS*ANISO*DELTA*sin(ANISO*(angle-ANGLE0))');
model.component('comp1').variable('var1').set('epsilon2', 'epsilon*epsilon');
model.component('comp1').variable('var1').set('m', 'ALPHA/pi*atan(GAMMA*(TEQ-T))');
model.component('comp1').variable('var1').set('angle', 'if(abs(thetax)>eps,atan2(thetay,thetax)+pi*(atan2(thetay,thetax)<0),pi/2*((thetay>0)+3*(thetay<0)))');

model.component('comp1').geom('geom1').create('r1', 'Rectangle');
model.component('comp1').geom('geom1').feature('r1').set('size', [9 9]);
model.component('comp1').geom('geom1').runPre('fin');
model.component('comp1').geom('geom1').run;

model.component('comp1').physics('g').feature('gfeq1').setIndex('Ga', {'-thetax*epsilon2+epsilon*epsilonp*thetay' '-thetay'}, 0);
model.component('comp1').physics('g').feature('gfeq1').setIndex('Ga', {'-thetax*epsilon2+epsilon*epsilonp*thetay' '-thetay*epsilon2-epsilon*epsilonp*thetax'}, 0);
model.component('comp1').physics('g').feature('gfeq1').setIndex('f', 'd(epsilon2,x)*thetax+d(epsilon2,y)*thetay+theta*(1-theta)*(theta-0.5+m)', 0);
model.component('comp1').physics('g').feature('gfeq1').setIndex('f', 0, 1);
model.component('comp1').physics('g').feature('gfeq1').setIndex('da', 'TAU', 0);
model.component('comp1').physics('g').feature('gfeq1').setIndex('da', '-K', 1);
model.component('comp1').physics('g').feature('init1').set('theta', 'step1(x^2+y^2)');

model.component('comp1').mesh('mesh1').create('size1', 'Size');
model.component('comp1').mesh('mesh1').feature.remove('size1');
model.component('comp1').mesh('mesh1').create('map1', 'Map');
model.component('comp1').mesh('mesh1').feature('size').set('hmax', 0.1);
model.component('comp1').mesh('mesh1').feature('size').set('hmin', '6.75e-4');
model.component('comp1').mesh('mesh1').feature('size').set('hgrad', 1.2);
model.component('comp1').mesh('mesh1').feature('size').set('hcurve', 0.25);
model.component('comp1').mesh('mesh1').run;

model.sol.create('sol1');
model.sol('sol1').study('std1');

model.study('std1').feature('time').set('notlistsolnum', 1);
model.study('std1').feature('time').set('notsolnum', 'auto');
model.study('std1').feature('time').set('listsolnum', 1);
model.study('std1').feature('time').set('solnum', 'auto');

model.sol('sol1').create('st1', 'StudyStep');
model.sol('sol1').feature('st1').set('study', 'std1');
model.sol('sol1').feature('st1').set('studystep', 'time');
model.sol('sol1').create('v1', 'Variables');
model.sol('sol1').feature('v1').set('control', 'time');
model.sol('sol1').create('t1', 'Time');
model.sol('sol1').feature('t1').set('tlist', 'range(0,0.1,1)');
model.sol('sol1').feature('t1').set('plot', 'off');
model.sol('sol1').feature('t1').set('plotgroup', 'Default');
model.sol('sol1').feature('t1').set('plotfreq', 'tout');
model.sol('sol1').feature('t1').set('probesel', 'all');
model.sol('sol1').feature('t1').set('probes', {});
model.sol('sol1').feature('t1').set('probefreq', 'tsteps');
model.sol('sol1').feature('t1').set('atolglobalvaluemethod', 'factor');
model.sol('sol1').feature('t1').set('endtimeinterpolation', true);
model.sol('sol1').feature('t1').set('control', 'time');
model.sol('sol1').feature('t1').create('fc1', 'FullyCoupled');
model.sol('sol1').feature('t1').feature('fc1').set('linsolver', 'dDef');
model.sol('sol1').feature('t1').feature.remove('fcDef');
model.sol('sol1').attach('std1');

model.result.create('pg1', 'PlotGroup2D');
model.result('pg1').set('data', 'dset1');
model.result('pg1').create('surf1', 'Surface');
model.result('pg1').feature('surf1').set('expr', 'theta');

model.sol('sol1').runAll;

  

 

 

四、结果

 

 

 

 

 

参考:

https://mooseframework.inl.gov/modules/phase_field/Phase_Field_Equations.html

https://mooseframework.inl.gov/modules/phase_field/Derivation_explanations.html

https://blog.sina.com.cn/s/blog_4a0a8b5d01011spl.html