前言:
柔性双轴和三轴的代码一年半以前就已经写好框架了,但有一些Bug,一直没有时间去整理。最近计算力有点空闲,刚好今天有点酒意,将柔性双轴的代码先整理了一下,基本上土的力学特性是可以反应了,剩下的就靠各位去继续完善了。
首先我们得搞清楚为什么要做柔性双轴或者三轴。真三轴其实是更加符合土单元概念的力学试验,但是在现实中真三轴的难度可以说是假三轴的百倍以上。这就导致了目前很多土力学实验都是假三轴。而我们做参数标定,是需要做和现实一致的单元实验,调整微观参数使其宏观特性一致的,所以数值模拟中做假三轴比真三轴更好。
数值模拟是在还原现实的基础上去研究更多力学特性,所以第一步还原现实我们需要首先做到位。
一、成样和预压
这里还是和之前的一样,成样代码如下:
newdomain extent -5 5set random 10001def parwidth=1.5height=width*2poro=0.18end@parwall generate box [-width*0.5] [width*0.5] [-height*0.5] [height*0.5] expand 1.5cmat default model linear method deformability emod 100e6 kratio 1.5ball distribute radius 0.006 0.009 porosity @poro ...range x [-width*0.5 0.001] [width*0.5-0.001] ...y [-height*0.5 0.001] [height*0.5-0.001]ball attribute density 7800 damp 0.7cycle 1000 calm 10solveball delete range x [-width] [-width*0.5]ball delete range x [width*0.5] [width]ball delete range y [-height] [-height*0.5]ball delete range y [height*0.5] [height]save ball_sample
预压代码如下,注意在压之前给参数,这是我认为比较好的砂土模拟步骤。
restore ball_sample[fric_shiyang=0.5][rrfric_shiyang=0.2][emod_shiyang=100e6]ball group shiyangcmat add 1 model rrlinear method deformability emod @emod_shiyang kratio 1.5 property fric @fric_shiyang rr_fric @rrfric_shiyang ...range group shiyangcmat apply[txx=-2e4][tyy=-2e4][sevro_factor=0.5][do_xSevro=true][do_ySevro=true][sevro_freq=100][timestepNow=global.step-1]def sevro_wallscompute_stressif timestepNow<global.step thenget_g(sevro_factor)timestepNow =sevro_freqendifif do_xSevro=true thenXvel=gx*(wxss-txx)wall.vel.x(wpRight)=-Xvel; suduwall.vel.x(wpLeft)=Xvelendifif do_ySevro=true thenYvel=gy*(wyss-tyy)wall.vel.y(wpUp)=-Yvelwall.vel.y(wpDown)=Yvelendifenddef wp_iniwpDown=wall.find(1)wpRight=wall.find(2)wpUp=wall.find(3)wpLeft=wall.find(4)end@wp_inidef computer_chiCunwlx=wall.pos.x(wpRight)-wall.pos.x(wpLeft)wly=wall.pos.y(wpUp)-wall.pos.y(wpDown)enddef compute_stresscomputer_chiCunwxss=-(wall.force.contact.x(wpRight)-wall.force.contact.x(wpLeft))*0.5/wlywyss=-(wall.force.contact.y(wpUp)-wall.force.contact.y(wpDown))*0.5/wlxend@compute_stressdef get_g(fac)computer_chiCungx=0gy=0zongKNX=100e6*10zongKNY=100e6*10loop foreach ct wall.contactmap(wpLeft)zongKNX =contact.prop(ct,"kn")endlooploop foreach ct wall.contactmap(wpRight)zongKNX =contact.prop(ct,"kn")endlooploop foreach ct wall.contactmap(wpUp)zongKNY =contact.prop(ct,"kn")endlooploop foreach ct wall.contactmap(wpDown)zongKNY =contact.prop(ct,"kn")endloopgx=fac*wly/(zongKNX*global.timestep)gy=fac*wlx/(zongKNY*global.timestep)end@compute_stressset fish callback -1.0 @sevro_wallshistory id 1 @wxsshistory id 2 @wysscycle 1solve aratio 1e-5save yuya
二、柔性膜
这就是本文的重点了,下图为柔性膜颗粒计算的基本逻辑,静水压力为stressW,这里将颗粒间看作是连续的膜,膜的长度就是接触的长度L,于是静水压力作用在整个膜上的力为fw。我们再将这个力分解到膜的两端,也就是接触两端的颗粒,分别为0.5*fw。

我们首先生成上下的加载板,这里用vertice生成异形墙体就行,这里采用指定坐标的方法。

之后生成膜颗粒,这里循环生成即可,上下加载板中都会有膜颗粒,以模拟膜绑在加载板上的样子。


这两步走完后是这个样子:
![]()

之后给膜颗粒加接触,这里指定模量为7e6,也是一般橡胶的模量,强度设为1e300,这样膜是不会坏的。


下面就是最重要的施加膜颗粒上的作用力了。
disp就是接触的长度L,fmag就是0.5*fw。
dirt为两个膜颗粒的方向,注意这里我们需要旋转90度,逆时针还是顺时针取决于是左边的膜还是右边的膜,以及计算时候bp2在bp的上方还是下方。
左边和右边我们在生成的时候已经分好组了。上方下方我们可以根据颗粒的id来确定。
举个例子:如果是左边膜,然后bp2在bp的上方,根据bp和bp2计算得到的力方向应当是dirt顺时针旋转90度。
至于旋转矩阵就是高中知识了,(x,y)逆时针旋转90度为(-y,x)。
[weiya=math.abs(txx)]def upadat_bianjie_forceloop foreach bp ball.groupmap("left_bianjie")if ball.contactnum(bp)>=2 thenf=vector(0,0)loop foreach ct ball.contactmap(bp)if contact.model(ct)="linearcbond" thenbp2=contact.end1(ct)if bp2=bp thenbp2=contact.end2(ct)endifdirt=ball.pos(bp2)-ball.pos(bp)disp=math.sqrt(comp.x(dirt)^2 comp.y(dirt)^2)fmag=weiya*disp/2.0factor=1if ball.id(bp2)>ball.id(bp) thenfactor=-1endifnorm=factor*vector(comp.y(dirt)*(-1),comp.x(dirt))/dispf= f norm*fmagendifendloopball.force.app(bp)=fendifendlooploop foreach bp ball.groupmap("right_bianjie")if ball.contactnum(bp)>=2 thenf=vector(0,0)loop foreach ct ball.contactmap(bp)if contact.model(ct)="linearcbond" thenbp2=contact.end1(ct)if bp2=bp thenbp2=contact.end2(ct)endifdirt=ball.pos(bp2)-ball.pos(bp)disp=math.sqrt(comp.x(dirt)^2 comp.y(dirt)^2)fmag=weiya*disp/2.0factor=-1if ball.id(bp2)>ball.id(bp) thenfactor=1endifnorm=factor*vector(comp.y(dirt)*(-1),comp.x(dirt))/dispf= f norm*fmagendifendloopball.force.app(bp)=fendifendloopend
另外上下的加载板也需要伺服,我们还需要将加载板上的颗粒固定住。
def initUpDownMoloop foreach bp ball.groupmap("left_bianjie")if ball.pos.y(bp)>wly*0.5-bianjie_rad thenball.group(bp,10)="upMo"endifif ball.pos.y(bp)<-wly*0.5 bianjie_rad thenball.group(bp,10)="downMo"endifendlooploop foreach bp ball.groupmap("right_bianjie")if ball.pos.y(bp)>wly*0.5-bianjie_rad thenball.group(bp,10)="upMo"endifif ball.pos.y(bp)<-wly*0.5 bianjie_rad thenball.group(bp,10)="downMo"endifendloopend@initUpDownMoball fix vel spin range group upMo slot 10ball fix vel spin range group downMo slot 10
这里的upMO和downMo就是加载板上的颗粒。
之后就是伺服的过程了,不去多讲。
完整柔性膜部分的代码如下:
restore yuya[tyy=-10e4][txx=-10e4]set fish callback -1.0 remove @sevro_walls[bianjie_rad=0.002][freq=200]wall deletewall create vertices [-wlx*0.5] [wly*0.5*1.5] [-wlx*0.5] [wly*0.5] ...[-wlx*0.5] [wly*0.5] [wlx*0.5] [wly*0.5] ...[wlx*0.5] [wly*0.5] [wlx*0.5] [wly*0.5*1.5] id 1wall create vertices [-wlx*0.5] [-wly*0.5*1.5] [-wlx*0.5] [-wly*0.5] ...[-wlx*0.5] [-wly*0.5] [wlx*0.5] [-wly*0.5] ...[wlx*0.5] [-wly*0.5] [wlx*0.5] [-wly*0.5*1.5] id 2def add_bianjiey_pos=-wly*0.5*1.2loop while y_pos<wly*0.5*1.2commandball create position [-wlx*0.5-bianjie_rad] [y_pos] radius [bianjie_rad] group left_bianjieball create position [wlx*0.5 bianjie_rad] [y_pos] radius [bianjie_rad] group right_bianjieendcommandy_pos =2*bianjie_radendloopend@add_bianjiecontact groupbehavior andcmat default type ball-ball model rrlinear method deformability emod @emod_shiyang kratio 1.5 property fric 5.0 rr_fric 5.0cmat add 2 model linearcbond method deform emod 7e6 kratio 1.5 ...property cb_tenf 1e300 cb_shearf 1e300 rgap [bianjie_rad*0.01] ...range group left_bianjiecmat add 3 model linearcbond method deform emod 7e6 kratio 1.5 ...property cb_tenf 1e300 cb_shearf 1e300 rgap [bianjie_rad*0.01] ...range group right_bianjiecmat apply range group left_bianjiecmat apply range group right_bianjieball attribute density 1.5e3 damp 0.7 range group left_bianjieball attribute density 1.5e3 damp 0.7 range group right_bianjiecleancontact method bond gap [bianjie_rad*0.1][weiya=math.abs(txx)]def upadat_bianjie_forceloop foreach bp ball.groupmap("left_bianjie")if ball.contactnum(bp)>=2 thenf=vector(0,0)loop foreach ct ball.contactmap(bp)if contact.model(ct)="linearcbond" thenbp2=contact.end1(ct)if bp2=bp thenbp2=contact.end2(ct)endifdirt=ball.pos(bp2)-ball.pos(bp)disp=math.sqrt(comp.x(dirt)^2 comp.y(dirt)^2)fmag=weiya*disp/2.0factor=1if ball.id(bp2)>ball.id(bp) thenfactor=-1endifnorm=factor*vector(comp.y(dirt)*(-1),comp.x(dirt))/dispf= f norm*fmagendifendloopball.force.app(bp)=fendifendlooploop foreach bp ball.groupmap("right_bianjie")if ball.contactnum(bp)>=2 thenf=vector(0,0)loop foreach ct ball.contactmap(bp)if contact.model(ct)="linearcbond" thenbp2=contact.end1(ct)if bp2=bp thenbp2=contact.end2(ct)endifdirt=ball.pos(bp2)-ball.pos(bp)disp=math.sqrt(comp.x(dirt)^2 comp.y(dirt)^2)fmag=weiya*disp/2.0factor=-1if ball.id(bp2)>ball.id(bp) thenfactor=1endifnorm=factor*vector(comp.y(dirt)*(-1),comp.x(dirt))/dispf= f norm*fmagendifendloopball.force.app(bp)=fendifendloopenddef initUpDownMoloop foreach bp ball.groupmap("left_bianjie")if ball.pos.y(bp)>wly*0.5-bianjie_rad thenball.group(bp,10)="upMo"endifif ball.pos.y(bp)<-wly*0.5 bianjie_rad thenball.group(bp,10)="downMo"endifendlooploop foreach bp ball.groupmap("right_bianjie")if ball.pos.y(bp)>wly*0.5-bianjie_rad thenball.group(bp,10)="upMo"endifif ball.pos.y(bp)<-wly*0.5 bianjie_rad thenball.group(bp,10)="downMo"endifendloopend@initUpDownMoball fix vel spin range group upMo slot 10ball fix vel spin range group downMo slot 10[now_timestep=global.step-1]def servo_bianjiestress_jianceif global.step > now_timestep thenupadat_bianjie_forcenow_timestep=global.step freqendifend[wpDown=wall.find(2)][wpUp=wall.find(1)]def sevro_wallscompute_stressif timestepNow<global.step thenget_g(sevro_factor)timestepNow =sevro_freqendifif do_ySevro=true thenYvel=gy*(wyss-tyy)wall.vel.y(wpUp)=-Yvelwall.vel.y(wpDown)=Yvelloop foreach bp ball.groupmap("upMo",10)ball.vel.y(bp)=-Yvelendlooploop foreach bp ball.groupmap("downMo",10)ball.vel.y(bp)=Yvelendloopendifenddef computer_chiCunwly=wall.pos.y(wpUp)-wall.pos.y(wpDown)enddef compute_stresscomputer_chiCunwyss=-(wall.force.contact.y(wpUp)-wall.force.contact.y(wpDown))*0.5/wlxenddef get_g(fac)gy=0zongKNY=100e6*2*10loop foreach ct wall.contactmap(wpUp)zongKNY =contact.prop(ct,"kn")endlooploop foreach ct wall.contactmap(wpDown)zongKNY =contact.prop(ct,"kn")endloopgy=fac*wlx/(zongKNY*global.timestep)endset fish callback -1.0 @servo_bianjieset fish callback -1.0 @sevro_wallsmeasure create position 0 0 radius [wlx*0.3] id 1[mp=measure.find(1)]def stress_jiancestressXX=measure.stress.xx(mp)endhistory deletehistory id 1 @stressXXhistory id 2 @wysscycle 1solvesave rouxingmo
伺服结束后如图:
.png?imageView2/0)
可以看到是符合我们需求的,我们看一下颗粒受力图:
.png?imageView2/0)
当然我们还布置了测量圆测了一下横向应力:
横向应力距离目标应力有误差,来源于颗粒效应以及测量圆的误差。

三、加载
最后一步没啥新鲜的:
restore rouxingmowall attribute displacement multiply 0ball attribute displacement multiply 0set fish callback -1.0 remove @sevro_walls[streainRatio=1e-2]def get_ding_posftdown=wall.facet.find(5)ftup=wall.facet.find(2)y_ding_pos=math.abs(wall.facet.pos.y(ftup))end@get_ding_poswall attribute yvelocity [y_ding_pos*streainRatio] range id 2wall attribute yvelocity [-y_ding_pos*streainRatio] range id 1ball attribute yvelocity [-y_ding_pos*streainRatio] range group upMo slot 10ball attribute yvelocity [y_ding_pos*streainRatio] range group downMo slot 10[Iy0=y_ding_pos*2]def computer_stress_strainq=wyss-txxweyy=(-1)*(Iy0-(wall.facet.pos.y(ftup)-wall.facet.pos.y(ftdown)))/Iy0wyss=-(wall.force.contact.y(wpUp)-wall.force.contact.y(wpDown))*0.5/wlxendset fish callback -1.1 @computer_stress_strainhistory deletehistory id 1 @wysshistory id 2 @weyyhistory id 3 @q[stop_me=0]def stop_meif weyy<-20e-2 thenstop_me=1endifend[baocunpinlv=2e-3][time_record=weyy 1][count=0]def savefileif time_record-weyy >= baocunpinlv thenfilename=string.build("jieguo_%1",count)commandsave @filenameendcommandtime_record=weyycount =1endifendset fish callback -1.0 @savefilesolve fishhalt @stop_mesave result
四、结果分析
我这里做了三个不同孔隙率在100kpa围压下的柔性双轴,分别为0.1、0.18、0.26.
首先看一下应力应变:
0.1孔隙率

0.18孔隙率

0.26孔隙率

可以看出来还是比较符合常规的砂土力学特性的,即:
1、密砂软化、松砂硬化
2、不同孔隙率的残余强度一致
我们再看一下10%应变对应的位移图:
0.1孔隙率

0.18孔隙率

0.26孔隙率

具体机理不去解释了,基本在很多土力学论文中都可以了解到。
20%应变对应的位移图
0.1

0.18

0.26

为了展现更多细节,通过动图显示会好一点
0.1孔隙率

0.18孔隙率
.gif?imageView2/1/w/748/h/525)
0.26孔隙率
.gif?imageView2/1/w/688/h/563)
岩石的和这个道理一样,就不单独写了。
不得不说一句,我真牛批