【PFC6.0】三维Cluster碎石三轴模拟
1 引言
离散元作为一款基于颗粒力学的软件,得益于胶结模型的开发应用,使其在模拟胶结材料上展现出了令人惊讶的效果。对于散体材料,使用ball模拟可以很好的模拟颗粒在变形过程中的滑动、跃迁。但是美中不足的是,ball作为刚性体,不能体现出颗粒的破碎效果。
目前主流的是有两种方法,一种是监测ball的应力状态,当其超过强度阈值时,用若干小颗粒来代替大颗粒完成破碎效果。这种方法比较好的是计算效率高,且计算简单,毕竟都是线性模型。缺点也很明显,大颗粒碎成多少块小颗粒、每个小颗粒多大,这个事情讲不清楚的话肯定达不到一个比较好的模拟效果。
另一种就是用cluster来模拟了,所谓cluster,中文名为柔性簇。其作用方式是若干细小颗粒聚合成指定形状,且胶结在一起。这种方法模拟效果较好,且能够比较好的反映碎石破碎后的状态。
本文基于之前研究的成果 柔性簇Cluster模拟基本框架介绍 ,开发一个适用于三维碎石的cluster框架,并在三轴中进行实现。
2 框架介绍
本文和之前讲述的二维一样,首先进行模板生成,只是现在不是做cluster模板,而是做clump模板。完成一个比较好的clump模板后,在成样时候先完成clump的成样,再进行cluster颗粒的替换。
3 clump模板生成
clump中ball替换pebble的概念早已经有了,其实缺少的就是一个比较好的clump模板。clump中pebble不能重叠量过大,不然在替换成ball后ball也是有大的重叠量,而这种计算是不准确的。
所以这里我们必须想出一个生成pebble重叠量不大的clump模板。
最后采用的模拟思路是:1)将形状导入为墙体,并且在墙体中生成指定孔隙率的颗粒进行平衡;2)读取当前所有的ball作为clump模板;3)模板导出为本地的p3clp文件格式,后续用到成样工况中。
代码如下:
model newmodel domain extent -2 2def RdPar rdmin=0.08 rdmax=0.12 poro=0.3end@RdParcmat default type ball-facet model linear property kn 1e8 cmat default type ball-ball model linear property kn 1e7 ks 1e7 fric 0.2 program call "Geo_Tools.dat"program call "OutClumpTemplate.dat"def CreateTemplate loop n(1,4) stlName="Rock"+string(n) fileName="shape\\"+stlName+".stl" command geometry import @fileName endcommand get_min_max(stlName) x_len=x_max-x_min move_geo(stlName,vector(-(x_max+x_min)*0.5,-(y_max+y_min)*0.5,-(z_max+z_min)*0.5)) scale_geo(stlName,1.0/x_len) command wall import from-geometry @stlName ball distribute radius @rdmin @rdmax porosity @poro range geometry-space @stlName inside ball attribute density 2e3 damp 0.7 model cycle 2000 calm 50 model cycle 10000 endcommand OutTemplate(stlName) command model save @stlName ball delete wall delete clump template delete endcommand endloopend@CreateTemplate
其中先假设我们的形状文件存在于本地的shape文件夹中,且以Rock来命名,这里可以自行修改。
文中用到的Geo_tools文件内容如下:
主要的目标是实现导入的图形缩放到x向长度为1,会在导入后先move到原点,再进行scale.
def get_min_max(id)global x_min=1e100global x_max=-1e100global y_min=1e100global y_max=-1e100global z_min=1e100global z_max=-1e100local gs = geom.set.find(id)loop foreach local gn geom.node.list(gs)local pos = geom.node.pos(gn)if x_min > comp.x(pos)x_min = comp.x(pos)endifif y_min > comp.y(pos)y_min = comp.y(pos)endifif z_min > comp.z(pos)z_min = comp.z(pos)endifif x_max < comp.x(pos)x_max = comp.x(pos)endifif y_max < comp.y(pos)y_max = comp.y(pos)endifif z_max < comp.z(pos)z_max = comp.z(pos)endifendloopenddef scale_geo(geo_name,scale_factor)geo_zidan=geo.set.find(geo_name)loop foreach nd geo.node.list(geo_zidan)=geo.node.pos.x(nd)*scale_factor=geo.node.pos.y(nd)*scale_factor=geo.node.pos.z(nd)*scale_factorendloopenddef move_geo(geo_name,dist)geo_zidan=geo.set.find(geo_name)loop foreach nd geo.node.list(geo_zidan)=geo.node.pos(nd)+distendloopend
文中用到的第二个文件OutClumpTemplate代码如下:
这里的目的是读取当前所有的颗粒,在当前目录的Template文件夹中生成clump模板的p3clp后缀的文件。
def OutTemplate(templateName) ball_num=ball.num command clump template create geometry @templateName bubblepack ratio 0.6 distance 50 ... surfcalculate endcommand cp_template= clump.template.find(templateName) loop foreach pb clump.template.pebblelist(cp_template) clump.template.deletepebble(cp_template,pb) endloop loop foreach bp ball.list clump.template.addpebble(cp_template,ball.radius(bp),ball.pos(bp)) endloop clump_file_name="Template\\"+templateName+".p3clp" command clump template export @templateName filename @clump_file_name endcommandend
到这一步,我们的四个模板就生成了。效果如下:
Rock1:
Rock2:
Rock3:
Rock4:
以上就是达到我们使用的clump模板要求,即pebble不可有大的重叠量。
p3clp文件存储路径如下
然后下面进行三轴的时候,把这个文件夹移动到三轴项目目录中
4 碎石三轴----成样
生成指定粒径、空隙率、尺寸的式样,这部分略过了。
model newdef parwidth=2height=width*2rdmin=0.15rdmax=0.2poro=0.16end@pardomain extent [-width*2.0] [width*2.0] [-width*2.0] [width*2.0] ...[height*2.0]model random 10001wall generate box [-width*0.5] [width*0.5] [-width*0.5] [width*0.5] ...[height*0.5] expand 1.5ball distribute porosity @poro radius [rdmin] [rdmax] box ...[width*0.5] [-width*0.5] [width*0.5] [-height*0.5] [height*0.5]ball attribute density 2e3 damp 0.7contact cmat default model linear method deform emod 100e6 kratio 1.5model cycle 2000 calm 50ball property "fric" 0.5model solvemodel save "sample"
5 碎石三轴----clump替换
先进行第一种替换:ball替换为clump,这里其实也是用clump作为桥梁来确定cluster中颗粒的位置。
这部分代码和之前三点弯曲基本类似。
有一点是开头首先进行clump template import,导入本地的模板文件。
还有就是模板选择,这里有四个模板,目前完成的概念是四个模板随机均匀分布,如果有规则的话,可以修改0.25 0.5 0.75这三个界限值。
注意避免墙体和clump自锁,所以墙体先放大,再压缩。
model restore "sample"def importTemplateloop n(1,4)stlName="Rock"+string(n)fileName="Template\\"+stlName+".p3clp"commandclump template import @fileName name @stlNameendcommandendloopend@importTemplatedef GetTemplateNamerd=math.random.uniformif rd<0.25 thenGetTemplateName="Rock1"else if rd<0.5 thenGetTemplateName="Rock2"else if rd<0.75 thenGetTemplateName="Rock3"elseGetTemplateName="Rock4"endifend[clump_count=1]def tihuanloop foreach bp ball.listx_pos = ball.pos(bp,1)y_pos = ball.pos(bp,2)z_pos = ball.pos(bp,3)bvol = (4/3.0)*math.pi*ball.radius(bp)^3template_name=GetTemplateNameball.delete(bp)angle= math.random.uniform*180axis_x=math.random.uniform-0.5axis_y=math.random.uniform-0.5axis_z=math.random.uniform-0.5axis=vector(axis_x,axis_y,axis_z)commandclump replicate id @clump_count name @template_name ...pos-x @x_pos pos-y @y_pos pos-z @z_pos ...volume @bvol angle @angle axis @axisclump group @template_name range id @clump_countendcommandclump_count+=1endloopend@tihuanclump attribute density 2e3 damp 0.7cmat default type pebble-facet model linear method deform emod 1000e6 kratio 1.5clump attribute density 2.3e3 damp 0.7[yasuo_time=5]wall deletewall generate box [-width] [width] [-width] [width] ...[-height] [height]wall attribute velocity-z [(height*0.5)/yasuo_time] range id 1wall attribute velocity-z [-(height*0.5)/yasuo_time] range id 2wall attribute velocity-x [(width*0.5)/yasuo_time] range id 3wall attribute velocity-x [-(width*0.5)/yasuo_time] range id 4wall attribute velocity-y [(width*0.5)/yasuo_time] range id 5wall attribute velocity-y [-width*0.5/yasuo_time] range id 6solve time [yasuo_time*0.3] calm 10solve time [yasuo_time*0.7]wall attribute velocity 0 0 0model solvemodel save "tihuan_clump"
6 碎石三轴----cluster替换
这里是我们主要的工作量了,模拟的概念是:
1)找到每一个clump,找到这个clump中每一个pebble的位置和半径,在这个位置上生成同粒径的ball
2)把这些颗粒打个组叫“jiaojie”,然后即时性的给这个组的颗粒附上pb模型,并且加上接触。由于只针对这个组,且指定了match 2,所以“jiaojie”这个组和其余的组之间的接触走default生成linear接触。每次进行内应力的清零防止颗粒崩散。安全起见也fix一下。
3)这些颗粒之间的接触数值可在外面写函数获取,比如我这里的GetEmodByClusterName,这里传进来的参数是cluster的group,也就是模板的名称,这里认为同一个模板用的接触属性一样,可以自己去确定属性规则。
model restore "tihuan_clump"contact cmat default type ball-ball model linear method deform emod 1e9 kratio 1.5 property fric 0.2 lin_mode 1contact cmat default type ball-facet model linear method deform emod 10e9 kratio 1.5 property fric 0.2 lin_mode 1def GetEmodByClusterName(clusterName)test_string=clusterNameif clusterName=="Rock1" thenGetEmodByClusterName=1e9else if clusterName=="Rock2" thenGetEmodByClusterName=2e9else if clusterName=="Rock3" thenGetEmodByClusterName=3e9elseGetEmodByClusterName=4e9endifenddef GetPbCohByClusterName(clusterName)if clusterName=="Rock1" thenGetPbCohByClusterName=1e7else if clusterName=="Rock2" thenGetPbCohByClusterName=2e7else if clusterName=="Rock3" thenGetPbCohByClusterName=3e7elseGetPbCohByClusterName=4e7endifenddef applyBond(groupName,clusterName,bondGap)emod=GetEmodByClusterName(clusterName)pb_coh=GetPbCohByClusterName(clusterName)commandmodel cycle 1model calmball attribute force-contact multiply 0.0clump attribute force-contact multiply 0.0contact property lin_force 0.0 0.0 0.0 range group @groupNamecontact model linearpbond range group @groupName match 2contact method deform emod [emod] kratio 1.5 pb_deform emod [emod] kratio 1.5 range group @groupName match 2contact property pb_coh @pb_coh pb_ten [pb_coh/1.5] pb_fa 50 fric 0.1 lin_mode 1 range group @groupName match 2model cleancontact method bond gap @bondGap range group @groupName match 2endcommandenddef TihuanCploop foreach cp clump.listtemplateName=clump.template.name(clump.template(cp))min_rd=1e100loop foreach pb clump.pebblelist(cp)rd=clump.pebble.radius(pb)min_rd=math.min(min_rd,rd)pos=clump.pebble.pos(pb)bp=ball.create(rd,pos)ball.group(bp)="jiaojie"endloopcommandball attribute density 2e3 damp 0.7 range group "jiaojie"endcommandapplyBond("jiaojie",templateName,min_rd)clump.delete(cp)commandball fix vel spin range group "jiaojie"ball group @templateName range group "jiaojie"endcommandendloopend@TihuanCpmodel save "tihuan_cluster"
生成完后,显示接触模型名称进行查看:
可以明显看到只有碎石内部是有胶结的。
显示pb_ten:
可以看到不同的属性也是给进去的。
7 碎石三轴----加围压
没什么可讲的,简单的伺服概念
model restore "tihuan_cluster"ball free vel spin=-2e6]=-2e6]=-2e6]=0.5]=true]=true]=100]=global.step-1]def sevro_wallscompute_stressif timestepNow<global.step thenget_g(sevro_factor)=sevro_freqendifif do_xSevro=true thenXvel=gx*(wxss-txx)Yvel=gy*(wyss-tyy)vel_arg=(Xvel+Yvel)*0.5=-vel_arg=vel_arg=vel_arg=-vel_argendifif do_zSevro=true thenZvel=gz*(wzss-tzz)=-Zvel=Zvelendifenddef wp_iniwpDown=wall.find(1)wpUp=wall.find(2)wpLeft=wall.find(3)wpRight=wall.find(4)wpFront=wall.find(5)wpBack=wall.find(6)end@wp_inidef computer_chiCunwlx=wall.pos.x(wpRight)-wall.pos.x(wpLeft)wlz=wall.pos.z(wpUp)-wall.pos.z(wpDown)wly=-wall.pos.y(wpFront)+wall.pos.y(wpBack)enddef compute_stresscomputer_chiCunwxss=-(wall.force.contact.x(wpRight)-wall.force.contact.x(wpLeft))*0.5/(wly*wlz)wzss=-(wall.force.contact.z(wpUp)-wall.force.contact.z(wpDown))*0.5/(wlx*wly)wyss=(wall.force.contact.y(wpFront)-wall.force.contact.y(wpBack))*0.5/(wlx*wlz)enddef get_g(fac)gx=0gy=0gz=0gX=1e10gY=1e10gZ=1e10loop foreach ct wall.contactmap(wpLeft)=contact.prop(ct,"kn")endlooploop foreach ct wall.contactmap(wpRight)=contact.prop(ct,"kn")endlooploop foreach ct wall.contactmap(wpUp)=contact.prop(ct,"kn")endlooploop foreach ct wall.contactmap(wpDown)=contact.prop(ct,"kn")endlooploop foreach ct wall.contactmap(wpFront)=contact.prop(ct,"kn")endlooploop foreach ct wall.contactmap(wpBack)=contact.prop(ct,"kn")endloopgx=fac*wly*wlz/(gX*global.timestep)gy=fac*wlx*wlz/(gY*global.timestep)gz=fac*wlx*wly/(gZ*global.timestep)end@get_g(@sevro_factor)@compute_stressfish callback add @sevro_walls -1.0history deletehistory id 1 @wxsshistory id 2 @wysshistory id 3 @wzssmechanical timestep fix 1e-2model cycle 1000model solvemodel save "weiya"
8 碎石三轴----加载
model restore "weiya"ball attribute displacement multiply 0[IZ0=wall.pos.z(wpUp)-wall.pos.z(wpDown)][strainrate=0.1][do_zSevro=false]wall attribute vel-z [-IZ0*strainrate*0.5] range id 2wall attribute vel-z [IZ0*strainrate*0.5] range id 1def jiancewhilesteppingwezz=((wall.pos.z(wpUp)-wall.pos.z(wpDown))-IZ0)/IZ0endhistory deletehistory id 1 @wzsshistory id 2 @wezz[final_time=0.1/strainrate][baocunpinlv=final_time/20.0][time_record_sav=-100][count=0]def savefiletime=mech.time.totalif time-time_record_sav >= baocunpinlv thenfilename=string.build("jieguo_%1",count)commandmodel save @filenameendcommandtime_record_sav=timecount +=1endifendfish callback add @savefile -1.0program call "fracture.p3fis"@track_initmodel solve time [final_time]model save "result"
首先看一下应力应变曲线:
比较经典的脆性破坏曲线。
所有颗粒在压缩过程中的破碎情况。
Rock1到Rock4的参数是逐渐变强的,所以碎石的破碎情况也是不均匀的。利于plot中的range筛选工具,可以选择只看某一个分组的变化情况。
Rock1
Rock2
Rock3
Rock4
可以看出Rock1由于参数最弱,所以坏的最多。
我这里裂纹文件没有改好,导致裂纹位置没有实现更新,就不分享出来了,大家可以自行用example中的裂纹文件。
从颗粒位置和裂纹位置的重合度来看,Rock1也是破碎最多的。
大家还可以去监测四个分组的破碎率,即胶结破坏数/总胶结数。计算不复杂,当作各位的作业了。
比较难的点在于级配统计了,这个也是一个比较广泛的需求。压缩破坏前后的级配曲线是我们的研究重点。
我这里也给出了计算级配的方法:
逻辑不复杂,用fragment的体积计算等体积下的球形颗粒半径作为粒径。然后统计当前所有fragment粒径范围,再进行分割统计。
model restore "jieguo_2"=20]def GetFragmentDia(fg)vol=fragment.vol(fg)GetFragmentDia= (vol*3.0/4.0/math.pi)^(1/3.0)enddef GetMinMaxDiamallVol=0min_d=1e100max_d=-1e100loop foreach fg fragment.mapfg_vol=GetFragmentDia(fg)=fragment.vol(fg)min_d=math.min(min_d,fg_vol)max_d=math.max(max_d,fg_vol)endloopend@GetMinMaxDiam=(max_d-min_d)/float(split_num)]def CreateTabletb=table.create("jipei")loop n(1,split_num)cur_d=min_d+n*split_d=cur_d=0endloopend@CreateTabledef tongjiloop foreach fg fragment.mapfg_vol=GetFragmentDia(fg)idx=math.ceiling((fg_vol-min_d)/split_d)if idx==0 thenidx=1endifloop n(idx,split_num)y_value=table.y(tb,n)=(fragment.vol(fg)/allVol)=y_valueendloopendloopend@tongji
我们初始粒径是0.15-0.2均匀分布的,我们看一下各个时刻的变化:
jieguo2:
jieguo5:
jieguo10
jieguo15
jieguo19:
jieguo5差不多就在峰后附近,这时候细粒径增多,而峰后,中粒径的颗粒也开始增加,可以结合破坏模型进行分析。
本文除了裂纹文件已包含所有的代码文件。读者可自行组装。也可转发本文到朋友圈集赞50,截图发到公众号后台,可以得到本文对应得文件项目包。为了避免半年后依然有同学艾特我,集赞活动截止到5月3日。
工程师必备
- 项目客服
- 培训客服
- 平台客服
TOP




















