【PFC6.0】隨機多邊形區域劃分及顆粒填充
0 引言
在做巖石的時候,粗糙一點就認為巖石是一個均勻的整體,對整體參數進行標定,達到一個單元層次的宏觀特性對應。精細點做的話就需要考慮礦物,這樣我們會認為礦物內部是一個均勻的整體,這樣的話就需要對巖石內部的區域進行劃分,規定每種礦物成分的區域,然后用顆粒進行填充模擬。
本文主要目的是將區域進行隨機多邊形劃分,并且往其中填充顆粒。使用到的技術主要是rblock中的merge命令。
1 區域劃分
我們主要使用rblock的建模特性作為過渡,得到隨機的多邊形區域。
model newmodel domain extent -10 10geometry set "box"geometry generate box -5 5def parorigin_rad_min=0.2origin_rad_max=origin_rad_min*1.5scale=3block_radius_max=origin_rad_max*scaleblock_radius_min=origin_rad_min*scaleend@parrblock construct from-geometry "box" minimum-edge @origin_rad_min ...@origin_rad_max group "origin" slot "1"
第一步是利用rblock construct命令可以對區域進行三角劃分,如果可以直接對區域進行多邊形劃分肯定是更好的。但就我目前對rblock的理解來說,還做不到這種程度,目前只能做到對區域進行三角劃分,這里可以指定三角形的邊長范圍。
我們生成了一堆三角形的rblock,如下圖:
第二步就是用所得到的三角形進行隨機的合并,這里我們用的是長方形區域進行合并。
def inbox(pos,pointer)groupName=rblock.group(pointer)if groupName#"1=origin" theninbox=falseexitendifvl=vector(x_pos_random-sousuo_rad_x,y_pos_random-sousuo_rad_y)vh=vector(x_pos_random+sousuo_rad_x,y_pos_random+sousuo_rad_y)rbpos=rblock.pos(pointer)if comp.x(rbpos)>comp.x(vl) & comp.x(rbpos)<comp.x(vh) &comp.y(rbpos)>comp.y(vl) & comp.y(rbpos)<comp.y(vh) theninbox=trueexitendifinbox=falseenddef conbine_rblockstop_flag=truename_count=1loop while stop_flagx_pos_random=math.random.uniform*10-5y_pos_random=math.random.uniform*10-5sousuo_rad_x=math.random.uniform*(block_radius_max-block_radius_min)+block_radius_minsousuo_rad_y=math.random.uniform*(block_radius_max-block_radius_min)+block_radius_minishaveRb=falseloop foreach rb rblock.listvl=vector(x_pos_random-sousuo_rad_x,y_pos_random-sousuo_rad_y)vh=vector(x_pos_random+sousuo_rad_x,y_pos_random+sousuo_rad_y)if inbox(vl,rb) thenishaveRb=trueexit loopendifendloopgroup_name=string.build("zu_%1",name_count)name_count+=1if ishaveRb=true thencommandrblock merge group "new" slot "1" group @group_name slot "10" ...range fish @inboxmodel cleanendcommandendiforgin_count=0loop foreach rb rblock.groupmap("origin",1)orgin_count+=1endloopif orgin_count==0 thenstop_flag=falseendifendloopend@conbine_rblock
我們每次隨機獲得一個長寬的長方形,將長方形中的“origin”組的rblock合并成一個新的rblock。
這里有個邏輯需要注意是,merge的概念不一定需要rblock緊貼在一起,就算rblock分開一段距離,他們之間的范圍也會合并到新的rblock中,所以合并得到的rblock實際上是有重疊的。
我們看一下新的rblock。
可以發現的是,大部分的rblock都被合并了,但是有少部分rblock是被“剩余合并”的,所謂“剩余合并”的概念就是某個rblock或者某幾個會被單獨剩余下來,最終形成一個rblock,而這個rblock是不滿足長寬要求的。
所以我們還需要進行第三步,也就是把這些小的rblock合并到它周圍的大rblock中。
def findMinRbVLimit=origin_rad_min*origin_rad_min*10loop foreach rb rblock.groupmap("new",1)if rblock.vol(rb)<VLimit*4 thenrblock.group(rb,1)="minRB"endifendloopend@findMinRbdef findNearestRb(pos)minPos=1e100minId=0loop foreach rbfind rblock.groupmap("new",1)vecLenghth=rblock.pos(rbfind)-posif math.mag(vecLenghth)<minPos thenminPos=math.mag(vecLenghth)minId=rblock.id(rbfind)endifendloopfindNearestRb=minIdenddef solveMinRbloop foreach rb rblock.groupmap("minRB",1)rbNearest=rblock.find(findNearestRb(rblock.pos(rb)))rblock.group(rb,20)="dai"rblock.group(rbNearest,20)="dai"group_name=string.build("zu_%1",name_count)name_count+=1commandrblock merge group "new" slot "1" group @group_name ...slot "10" range group "20=dai"endcommandloop foreach rbdai rblock.groupmap("dai",20)rblock.group(rbdai,20)="none"endloopendloopend@solveMinRb
通過以上的命令,我們可以找到小的顆粒,當然我們也可以調整“小的顆粒”的范圍,從而調整模型中區域的精細度。
運行完的效果如圖:
這個就是我們區域的范圍。
2 顆粒填充
由于沒有指定隨機數,導致本文出現的圖和我既有算例的分布有區別,這里給出我算完的一個sav。如下圖:
可以看到區域大小基本一致,只是形狀不同,這里也體現隨機性的概念。
model restore "rblock_slip"rblock export to-geometry "allgeo"cmat default type ball-facet model linear method deform emod 100e6 kratio 1.5 property fric 0.5cmat default type ball-ball model linear method deform emod 100e6 kratio 1.5 property fric 0.5def GetGeogeoname_count=1loop foreach rb rblock.listgroupName=string.build("geo_%1",geoname_count)idRblock=rblock.id(rb)commandrblock export to-geometry @groupName range id @idRblockendcommandgeoname_count+=1endloopend@GetGeorblock delete
顆粒填充前我們需要把rblock的邊界都導出為geometry,方便后面根據區域進行顆粒生成。
可以看一下區域圖:
由于rblock有重疊,導致geometry也是有重疊的,所以顆粒的生成規則我們需要進行優化。
首先定一個考慮區域重疊的規則。
區域交集優先被id小的geometry使用。
也就是說id為3區域需要減去其與id 1和id 2區域的交集,作為對應顆粒的生成范圍。
榆樹我們可以得到某個區域的顆粒投放邏輯,如下:
def ballDeleteGeo(geo_count_single)if geo_count_single=1 thenexitendifthisGroup=string.build("geo_%1",geo_count_single)loop n(1,geo_count_single-1)groupName=string.build("geo_%1",n)commandball delete range geometry-space @groupName count 1 group @thisGroupendcommandendloopenddef GenerateBallIn(geo_count_single)groupName=string.build("geo_%1",geo_count_single)commandball distribute porosity 0.1 radius 0.03 0.06 group @groupName range geometry-space @groupName count 1ball attribute density 2.7e3 damp 0.3endcommandballDeleteGeo(geo_count_single)end
第二個邏輯是顆粒的平衡邊界,每個區域的顆粒投放后都需要平衡,其邊界應當考慮id小于當前geo id的區域,所以需要控制墻體的生成和刪除。
wall import from-geometry "box" id 100def genWalls(geo_count_single)loop n(1,geo_count_single)groupName=string.build("geo_%1",n)commandwall import from-geometry @groupName id [n+10000]endcommandendloopenddef deleWalls(geo_count_single)loop n(1,geo_count_single)commandwall delete walls range id [n+10000]endcommandendloopend
def genAllBallloop gen_cur(1,geoname_count-1)genWalls(gen_cur)commandmodel calmball fix velocity spinendcommandGenerateBallIn(gen_cur)groupName=string.build("geo_%1",gen_cur)commandmodel cycle 2000 calm 20ball delete range geometry-space @groupName count 1 not group @groupNameendcommandballDeleteGeo(gen_cur)commandmodel solve ratio-average 1e-5 or cycles 10000model save @groupNameendcommanddeleWalls(gen_cur)endloopend@genAllBallball free velocity spinmodel cycle 1model solvemodel save "sample"
最后便是函數的調用,每次生成新的區域的時候,舊的區域顆粒需要進行固定。
效果如下:
每次投放都保存了save文件,可以進行查看。
本算例所有代碼都已公開在上方,同學們可以自行組裝。若組裝有困難,可以轉發朋友圈集齊50贊,可以獲得本案例的文件。
工程師必備
- 項目客服
- 培訓客服
- 平臺客服
TOP




















