基于PFC3D與Flac3D耦合的SHPB壓桿模擬
0 引言
最近在熟悉PFC6.0的內容,對于6.0來說,其最大的突破就是實現了軟件內與FLAC3D的耦合。這其實解決了PFC很大的一個問題,就是顆粒數太多時計算力的限制,我們可以用網格單元作為邊界來弱化邊界效應,當然也可以和本文一樣,使用網格單元模擬金屬等連續性材料。
本文試著去模擬一個結構方向同學經常遇到的一個工況,霍普金森壓桿(SHPB)實驗,對于測量混凝土材料在高應變率下的力學特性有很大的參考價值。因為我這里也沒有看過這方面的實驗,僅從有限的資料大概理解其邊界設置,利用有限差分和離散元耦合來實現SHPB壓桿模擬,希望能給各位有一定的參考價值。
1 成樣、預壓、加膠結
首先是我們的離散元部分,這里進行常規的方式來生成一個圓柱形式樣。這里不再贅述了。
成樣代碼:
model newfish define Parsample_width=0.05radmin=0.8e-3radmax=radmin*1.8poro=0.28sample_rad=sample_width*0.5poleLength=sample_width*40end@Parmodel domain extent [-sample_width] [sample_width]wall generate cylinder base [-sample_width*0.5*1.4] 0 0 axis 1 0 0 ...height [sample_width*1.4] radius [sample_rad] resolution 0.3 cap false falsewall generate plane position [sample_width*0.5] 0 0 dip 90 dip-dir 90wall generate plane position [-sample_width*0.5] 0 0 dip 90 dip-dir 90ball distribute group "shiyang" radius [radmin] [radmax] porosity @poro ...range cylinder end-1 [sample_width*0.5-radmax] 0 0 ...[-sample_width*0.5+radmax] 0 0 radius [sample_rad-radmax]cmat default type ball-facet model linear method deform emod 100e6 kratio 1.5cmat default type ball-ball model linear method deform emod 100e6 kratio 1.5ball attribute density 2.7e3 damp 0.2model cycle 2000 calm 50model solvemodel save "sample"
預壓代碼:
model restore "sample"ball property "fric" 0.5fish def wp_wallwp_up=wall.find(2)wp_down=wall.find(3)wp_rr=wall.find(1)loop foreach vt wall.vertexlist(wp_rr)vert_in_ce=vtendloopend@wp_wall=-1e6]=-1e6]=0.5]=true]=true]=100]=global.step-1]fish def servo_wallscomputer_wallStressif timestepNow<global.step thenget_gain(sevro_fac)=sevro_freqendifif do_xservo=true thenx_vel=gx*(wsxx-txx)=-x_vel=x_velendifif do_rservo=true thenr_vel_mag=(-1)*gr*(wsrr-trr)loop foreach vt wall.vertexlist(wp_rr)mag=math.sqrt(wall.vertex.pos.y(vt)^2+wall.vertex.pos.z(vt)^2)fang_normal_y=wall.vertex.pos.y(vt)/magfang_normal_z=wall.vertex.pos.z(vt)/magr_vel=vector(0,fang_normal_y,fang_normal_z)*r_vel_mag=r_velendloopendifendfish def computer_chicuny_pos=wall.vertex.pos.y(vert_in_ce)z_pos=wall.vertex.pos.z(vert_in_ce)wlr=math.sqrt(y_pos^2+z_pos^2)wlx=wall.pos.x(wp_up)-wall.pos.x(wp_down)endfish def computer_wallStresscomputer_chicunding_yuanmianji=math.pi*wlr^2wsxx=(wall.force.contact.x(wp_down)-wall.force.contact.x(wp_up))*0.5/ding_yuanmianjice_mianji=2*math.pi*wlr*wlxwsrr=0loop foreach ft wall.facetlist(wp_rr)ft_fangxiang=wall.facet.normal(ft)loop foreach ct wall.facet.contactmap(ft)force_in_facet=contact.force.global(ct)=(math.dot(force_in_facet,ft_fangxiang))/ce_mianjiendloopendloopenddef get_gain(fac)gx=0gr=0zonggangX=1e7zonggangR=1e7loop foreach ct wall.contactmap(wp_up)=contact.prop(ct,"kn")endlooploop foreach ct wall.contactmap(wp_down)=contact.prop(ct,"kn")endlooploop foreach ct wall.contactmap(wp_rr)=contact.prop(ct,"kn")endloopgX=fac*ding_yuanmianji/(zonggangX*global.timestep)gr=fac*ce_mianji/(zonggangR*global.timestep)endfish callback add @servo_walls -1.0history id 1 @wsXXhistory id 2 @wsrrmodel cycle 1model solvemodel save "yuya"
加膠結代碼
model restore "yuya"[pb_coh=100e6][ten_coh=2.7]contact cmat default type ball-facet model linear method deformability emod 10e8 kratio 1.5contact cmat default type ball-ball model linearpbond method deformability ...emod 12e8 kratio 1.5 pb_deformability emod 54e8 kratio 1.5 ...property "pb_coh" [pb_coh] "pb_ten" [pb_coh*ten_coh] "pb_fa" 50 "fric" 0contact cmat applymodel cycle 1model solvecontact method bond gap [radmin*0.5]model cycle 1model solvemodel save "jiajiaojie"
生成的式樣如圖
2、卸載
這里模擬混凝土從模具中取出,或者巖石從地下取出的過程,所以預壓的值是有講究的。
model restore "jiajiaojie"[txx=-1e3][trr=-1e3]model cycle 1model solvemodel save "xiezai"
3、生成壓桿
這部分需要生產入射桿和透射桿的單元,目前我知道的方式是通過四個1/4的cylinder拼起來,不知道會不會有更便捷的方法,可以后臺交流。
之后就是耦合部分的定義,PFC和FLAC提供了兩種耦合方式,wall-zone耦合與ball-zone耦合,就使用來看,本文應當用wall-zone耦合來實現zone與ball之間的力學聯系。
需要注意的一點是,由于我們的桿件是拼起來的,所以zone生成wall時,會出現重復點的情況,這里可以直接指定skip-errors跳過即可。
model restore "xiezai"model domain extent [-poleLength*1.5] [poleLength*1.5] ...[-sample_width] [sample_width]wall deletefish callback remove @servo_walls -1.0[materialMod=200e9]model largestrain on[bullet_Length=sample_width*8][midu=5]zone create cylinder point 0 ([-poleLength-wlx*0.5],0,0) ...point 1 ([-poleLength-wlx*0.5],[-sample_rad],0) ...point 2 ([-wlx*0.5],0,0) ...point 3 ([-poleLength-wlx*0.5],0,[sample_rad]) ...size @midu [math.floor(midu*poleLength/sample_rad)] @midu group "ImportPole"zone create cylinder point 0 ([-poleLength-wlx*0.5],0,0) ...point 1 ([-poleLength-wlx*0.5],0,[-sample_rad]) ...point 2 ([-wlx*0.5],0,0) ...point 3 ([-poleLength-wlx*0.5],[-sample_rad],0) ...size @midu [math.floor(midu*poleLength/sample_rad)] @midu group "ImportPole"zone create cylinder point 0 ([-poleLength-wlx*0.5],0,0) ...point 1 ([-poleLength-wlx*0.5],[sample_rad],0) ...point 2 ([-wlx*0.5],0,0) ...point 3 ([-poleLength-wlx*0.5],0,[-sample_rad]) ...size @midu [math.floor(midu*poleLength/sample_rad)] @midu group "ImportPole"zone create cylinder point 0 ([-poleLength-wlx*0.5],0,0) ...point 1 ([-poleLength-wlx*0.5],0,[sample_rad]) ...point 2 ([-wlx*0.5],0,0) ...point 3 ([-poleLength-wlx*0.5],[sample_rad],0) ...size @midu [math.floor(midu*poleLength/sample_rad)] @midu group "ImportPole"; toushezone create cylinder point 0 ([wlx*0.5],0,0) ...point 1 ([wlx*0.5],[-sample_rad],0) ...point 2 ([poleLength+wlx*0.5],0,0) ...point 3 ([wlx*0.5],0,[sample_rad]) ...size @midu [math.floor(midu*poleLength/sample_rad)] @midu group "ExportPole"zone create cylinder point 0 ([wlx*0.5],0,0) ...point 1 ([wlx*0.5],0,[-sample_rad]) ...point 2 ([poleLength+wlx*0.5],0,0) ...point 3 ([wlx*0.5],[-sample_rad],0) ...size @midu [math.floor(midu*poleLength/sample_rad)] @midu group "ExportPole"zone create cylinder point 0 ([wlx*0.5],0,0) ...point 1 ([wlx*0.5],[sample_rad],0) ...point 2 ([poleLength+wlx*0.5],0,0) ...point 3 ([wlx*0.5],0,[-sample_rad]) ...size @midu [math.floor(midu*poleLength/sample_rad)] @midu group "ExportPole"zone create cylinder point 0 ([wlx*0.5],0,0) ...point 1 ([wlx*0.5],0,[sample_rad]) ...point 2 ([poleLength+wlx*0.5],0,0) ...point 3 ([wlx*0.5],[sample_rad],0) ...size @midu [math.floor(midu*poleLength/sample_rad)] @midu group "ExportPole"zone cmodel assign elasticzone property young [materialMod] poisson 0.25wall-zone create skip-errors range position-x [-wlx*0.5-0.001] [-wlx*0.5+0.001]wall-zone create skip-errors range position-x [wlx*0.5-0.001] [wlx*0.5+0.001]model save "pole"
生產的壓桿如圖:
細節放大:
可以發現此時顆粒是有一定速度的,但是由于我們研究的是高應變率所以這里可以不用管。
4、加載
這里直接施加一個沖擊荷載,在入射桿的端部指定一個200MPa的應力,持續200us。之后接觸邊界條件,運算1500us。
model restore "pole"model mechanical time-total 0model configure dynamicball attribute displacement multiply 0zone face group "rushe" range position-x [-poleLength-wlx*0.5-0.001] ...[-poleLength-wlx*0.5+0.001]zone face apply stress-xx [(-1)*(200e6)] range group "rushe"zone initialize density 7.8e3model cycle 1measure create position 0 0 0 radius [wlr*0.5]def cedianzoneImportPole=zone.near(vector(-wlx*0.5-poleLength*0.5,[-wlr],0))zoneExportPole=zone.near(vector(wlx*0.5+poleLength*0.5,[-wlr],0))mp1=measure.find(1)zone.group(zoneImportPole,"cedianGroup")="cedian"zone.group(zoneExportPole,"cedianGroup")="cedian"stressShiyang0=measure.stress.xx(mp1)end@cediandef jiancetime=mech.time.totalstressImport=zone.stress.xx(zoneImportPole)stressExport=zone.stress.xx(zoneExportPole)stressShiyang=measure.stress.xx(mp1)-stressShiyang0endfish callback add @jiance -1.0history deletehistory id 1 @stressImporthistory id 2 @stressExporthistory id 3 @stressShiyanghistory id 4 @time[baocunpinlv=500e-6][time_record=-10][count=0]def savefileif time-time_record >= baocunpinlv thenfilename=string.build("jieguo%1",count)commandmodel save @filenameendcommandtime_record=timecount +=1endifendfish callback add @savefile -1.0program call "fracture.p3fis"@track_initmodel solve time 200e-6zone face apply-remove stress-xx range group "rushe"model solve time 1500e-6model save "jieguo"
5、結果分析
首先本文選用的微觀參數強度比較大,不會發生破壞,這也是為了和有限元的一些結果做對比。
先看一下應力波形圖
這里給出參考曲線:
(李成武等,中國礦業大學,2014)
本文的模擬結果為:
可以看出無論是波形還是數值,都是在一個比較正常的范圍內的。所以也是論證了我們程序的正確性。
壓桿上的應力傳遞到式樣時候的圖片:
力鏈圖:
后續各位可以根據自己的實際材料結果進行更多的研究。
工程師必備
- 項目客服
- 培訓客服
- 平臺客服
TOP




















