Data Files for “Ribbon Blender” Example
- BlenderBalls.p3dat (3D ball example)
- ImportBlenderGeometry.p3dat (3D all examples)
- BlenderClumps.p3dat (3D clump example)
- BlenderClusters.p3dat (3D cluster example)
- ClusterMakeCluster.p3dat (3D cluster example)
- ClusterSizeDistribution.p3dat (3D cluster example)
BlenderBalls.p3dat
; fname: BlenderBalls.p3dat
model new
wall resolution full
call '../blender_geometry/ImportBlenderGeometry.p3dat'
model domain extent [lbx-0.05*dx] [ubx+0.05*dx] [lby-0.05*dy] ...
[uby+0.05*dy] [lbz-0.05*dz] [ubz+dz] ...
condition destroy
contact cmat default model linear prop dp_nratio 0.8 dp_mode 1
wall import from-geom 'rotor1' clean id 1
wall import from-geom 'rotor2' clean id 2
wall import from-geom 'rotor3' clean id 3
wall import from-geom 'rotor4' clean id 4
wall import from-geom 'rotor5' clean id 5
wall import from-geom 'rotor6' clean id 6
wall import from-geom 'rotor7' clean id 7
wall import from-geom 'rotor8' clean id 8
wall import from-geom 'blade1' clean id 9
wall import from-geom 'blade2' clean id 10
wall import from-geom 'blade3' clean id 11
wall import from-geom 'blade4' clean id 12
wall import from-geom 'blade5' clean id 13
wall import from-geom 'blade6' clean id 14
wall import from-geom 'blade7' clean id 15
wall import from-geom 'blade8' clean id 16
wall group 'facetassembly' facet
wall group 'wallassembly'
wall import from-geom 'bin' clean id 17
wall active-side top range position-z [ubz-0.05*ubz] [ubz+0.05*ubz]
wall active-side top range name 'facetassembly'
model save 'blender'
fish def setup(rpm)
global rp_ = vector(0,0,0) ;rotation point
global spin_ = vector(0,-1,0)*2*math.pi*rpm/60.0 ;axis of rotation
global knB_ = 1e4
global ksB_ = 1e4
global knW_ = 1e6
global ksW_ = 1e6
global fric_ = 0.18 ;friction
global dens_ = 2000 ;density
end
@setup(60)
;generate some balls in the box
fish def inBlender(pos,b)
inBlender = 0
if type.pointer.id(b) = ball.typeid
wp = wall.find(17);
inBlender = wall.inside(wp,ball.pos(b))
endif
end
fish def inBody(pos,b)
inBody = 0
if type.pointer.id(b) = ball.typeid
local tmp = 0
loop foreach local wp wall.list
if wall.id(wp) # 17
tmp = wall.inside(wp,ball.pos(b))
if tmp = 1
inBody = 1
exit
endif
endif
endloop
endif
end
ball distribute porosity 0.45 ...
resolution 1.5e-2 ...
bin 1 ...
radius 1.0 1.5 ...
volume-fraction 1.0 ...
box [lbx] [ubx] [lby] [uby] [lbz] [lbz+0.3*dz] ...
range fish @inBlender ...
fish @inBody not
model gravity 0,0,-9.81
ball prop 'kn' @knB_ 'ks' @ksB_ 'fric' @fric_
wall prop 'kn' @knW_ 'ks' @ksW_ 'fric' [fric_*0.5]
ball attr density @dens_ damp 0.7
model cycle 2000 calm 500
model mechanical timestep scale
model solve ratio-average 1e-3
model mechanical timestep auto
wall attribute rotation-center @rp_ range group 'wallassembly'
wall attribute spin @spin_ range group 'wallassembly'
;set up groups for mixing
ball group 'FrontLeft' range position-x [lbx-0.05*dx] 0.0 ...
position-y [lby-0.05*dy] 0.5
ball group 'FrontRight' range position-x 0.0 [ubx+0.05*dx] ...
position-y [lby-0.05*dy] 0.5
ball group 'BackLeft' range position-x [lbx-0.05*dx] 0.0 ...
position-y 0.5 [uby+0.05*dy]
ball group 'BackRight' range position-x 0.0 [ubx+0.05*dx] ...
position-y 0.5 [uby+0.05*dy]
model save 'ball_model'
model solve time 1.0
model save 'end_blenderball'
;=============================================================================
; eof: BlenderBalls.p3dat
importBlenderGeometry.p3dat
; fname: ImportBlenderGeometry.p3dat
geom import 'rotor1.stl'
geom import 'rotor2.stl'
geom import 'rotor3.stl'
geom import 'rotor4.stl'
geom import 'rotor5.stl'
geom import 'rotor6.stl'
geom import 'rotor7.stl'
geom import 'rotor8.stl'
geom import 'blade1.stl'
geom import 'blade2.stl'
geom import 'blade3.stl'
geom import 'blade4.stl'
geom import 'blade5.stl'
geom import 'blade6.stl'
geom import 'blade7.stl'
geom import 'blade8.stl'
geom import 'bin.stl'
;calculate the dimensions of the box needed
fish def cdim
lbx = 1e5
lby = 1e5
lbz = 1e5
ubx = -1e5
uby = -1e5
ubz = -1e5
local gs = geom.set.find(17)
loop foreach local gn geom.node.list(gs)
local pos = geom.node.pos(gn)
if lbx > comp.x(pos)
lbx = comp.x(pos)
endif
if lby > comp.y(pos)
lby = comp.y(pos)
endif
if lbz > comp.z(pos)
lbz = comp.z(pos)
endif
if ubx < comp.x(pos)
ubx = comp.x(pos)
endif
if uby < comp.y(pos)
uby = comp.y(pos)
endif
if ubz < comp.z(pos)
ubz = comp.z(pos)
endif
endloop
dx = ubx - lbx
dy = uby - lby
dz = ubz - lbz
end
@cdim
;=============================================================================
; eof: ImportBlenderGeometry.p3dat
BlenderClumps.p3dat
; fname: BlenderClumps.p3dat
model new
wall resolution full
call '../blender_geometry/ImportBlenderGeometry.p3dat'
model domain extent [lbx-0.05*dx] [ubx+0.05*dx] [lby-0.05*dy] ...
[uby+0.05*dy] [lbz-0.05*dz] [ubz+dz] ...
condition destroy
wall import from-geom 'rotor1' clean id 1
wall import from-geom 'rotor2' clean id 2
wall import from-geom 'rotor3' clean id 3
wall import from-geom 'rotor4' clean id 4
wall import from-geom 'rotor5' clean id 5
wall import from-geom 'rotor6' clean id 6
wall import from-geom 'rotor7' clean id 7
wall import from-geom 'rotor8' clean id 8
wall import from-geom 'blade1' clean id 9
wall import from-geom 'blade2' clean id 10
wall import from-geom 'blade3' clean id 11
wall import from-geom 'blade4' clean id 12
wall import from-geom 'blade5' clean id 13
wall import from-geom 'blade6' clean id 14
wall import from-geom 'blade7' clean id 15
wall import from-geom 'blade8' clean id 16
wall group 'facetassembly' facet
wall group 'wallassembly'
wall import from-geom 'bin' clean id 17
wall active-side top range position-z [ubz-0.05*ubz] [ubz+0.05*ubz]
wall active-side top range name 'facetassembly'
model save 'blender'
fish def setup(rpm)
rp_ = vector(0,0,0)
spin_ = vector(0,-1,0)*2*math.pi*rpm/60.0
knB_ = 1e4
ksB_ = 1e4
knW_ = 1e8
ksW_ = 1e8
fric_ = 0.18
dens_ = 2000
end
@setup(60)
geometry import 'ellipsoid.stl'
clump template create name 'pill' geometry 'ellipsoid' ...
surfcalc bubblepack ratio 0.5 distance 150
contact cmat default type Pebble-Pebble model Linear ...
property kn 10e4 inh off ks 10e4 inh off fric 0.18
contact cmat default type Pebble-Facet model Linear ...
property kn 10e5 inh off ks 10e5 inh off fric 0.09
clump distribute porosity 0.45 ...
resolution 5e-2 ...
number-bins 1 ...
diameter ...
bin 1 size 1.0 1.20 ...
volume-fraction 1 ...
template 'pill' ...
az 90 90 ...
el 0 0 ...
tilt 0 0 ...
box [lbx] [ubx] [lby] [uby] [lbz] [lbz+0.3*dz]
fish def inBlender(pos,c)
inBlender = 1
if type.pointer.id(c) = clump.typeid
loop foreach local pb clump.pebblelist(c)
local tmp = 0
wp = wall.find(17);
tmp = wall.inside(wp,clump.pebble.pos(pb))
if tmp = 0
inBlender = 0
exit
endif
endloop
endif
end
clump delete range fish @inBlender not
fish def inBody(pos,c)
inBody = 0
if type.pointer.id(c) = clump.typeid
loop foreach local pb clump.pebblelist(c)
local tmp = 0
loop foreach local wp wall.list
if wall.id(wp) # 17
tmp = wall.inside(wp,clump.pebble.pos(pb))
if tmp = 1
inBody = 1
exit
endif
endif
endloop
endloop
endif
end
clump delete range fish @inBody
model gravity 0,0,-9.81
clump attr density @dens_ damp 0.7
model cycle 2000 calm 500
model mechanical timestep scale
model solve ratio-average 1e-1
model mechanical timestep auto
clump attr damp 0.0
wall attr rotation-center @rp_ range group 'wallassembly'
wall attr spin @spin_ range group 'wallassembly'
;set up groups for mixing
clump group 'FrontLeft' range position-x [lbx-0.05*dx] 0.0 ...
position-y [lby-0.05*dy] 0.5
clump group 'FrontRight' range position-x 0.0 [ubx+0.05*dx] ...
position-y [lby-0.05*dy] 0.5
clump group 'BackLeft' range position-x [lbx-0.05*dx] 0.0 ...
position-y 0.5 [uby+0.05*dy]
clump group 'BackRight' range position-x 0.0 [ubx+0.05*dx] ...
position-y 0.5 [uby+0.05*dy]
model save 'clump_model'
model solve time 0.5
model save 'end_blenderclump'
;=============================================================================
; eof: BlenderClumps.p3dat
BlenderClusters.p3dat
; fname: BlenderClusters.p3dat
model new
wall resolution full
call 'ClusterMakeCluster.p3dat'
call 'ClusterSizeDistribution.p3dat'
call '../blender_geometry/ImportBlenderGeometry.p3dat'
geometry import 'ellipsoid.stl'
model domain extent [lbx-0.05*dx] [ubx+0.05*dx] [lby-0.05*dy] ...
[uby+0.05*dy] [lbz-0.05*dz] [ubz+dz] ...
condition destroy
wall import from-geom 'rotor1' clean id 1
wall import from-geom 'rotor2' clean id 2
wall import from-geom 'rotor3' clean id 3
wall import from-geom 'rotor4' clean id 4
wall import from-geom 'rotor5' clean id 5
wall import from-geom 'rotor6' clean id 6
wall import from-geom 'rotor7' clean id 7
wall import from-geom 'rotor8' clean id 8
wall import from-geom 'blade1' clean id 9
wall import from-geom 'blade2' clean id 10
wall import from-geom 'blade3' clean id 11
wall import from-geom 'blade4' clean id 12
wall import from-geom 'blade5' clean id 13
wall import from-geom 'blade6' clean id 14
wall import from-geom 'blade7' clean id 15
wall import from-geom 'blade8' clean id 16
wall group 'facetassembly' facet
wall group 'wallassembly'
wall import from-geom 'bin' clean id 17
wall active-side top range position-z [ubz-0.05*ubz] [ubz+0.05*ubz]
wall active-side top range name 'facetassembly'
fish define setup(rpm)
rp_ = vector(0,0,0)
spin_ = vector(0,-1,0)*2*math.pi*rpm/60.0
knB_ = 1e4
ksB_ = 1e4
knW_ = 1e8
ksW_ = 1e8
fric_ = 0.18
dens_ = 2000
end
@setup(60)
clump template create name 'pill' geometry 'ellipsoid' ...
surfcalc bubblepack ratio 0.5 distance 150
contact cmat default type pebble-pebble model linear ...
property kn 10e4 inh off ks 10e4 inh off fric 0.18
contact cmat default type pebble-facet model linear ...
property kn 10e5 inh off ks 10e5 inh off fric 0.09
clump distribute porosity 0.45 ...
number-bins 1 ...
diameter ...
resolution 1.0 ...
bin 1 size 0.05 0.075 ...
volume-fraction 1 ...
template 'pill' ...
az 90 90 ...
el 0 0 ...
tilt 0 0 ...
box [lbx] [ubx] [lby] [uby] [lbz] [lbz+0.3*dz]
fish def inBlender(pos,c)
inBlender = 1
if type.pointer.id(c) = clump.typeid
loop foreach local pb clump.pebblelist(c)
local tmp = 0
wp = wall.find(17)
tmp = wall.inside(wp,clump.pebble.pos(pb))
if tmp = 0
inBlender = 0
exit
endif
endloop
endif
end
clump delete range fish @inBlender not
fish def inBody(pos,c)
inBody = 0
if type.pointer.id(c) = clump.typeid
loop foreach local pb clump.pebblelist(c)
local tmp = 0
loop foreach local wp wall.list
if wall.id(wp) # 17
tmp = wall.inside(wp,clump.pebble.pos(pb))
if tmp = 1
inBody = 1
exit
endif
endif
endloop
endloop
endif
end
clump delete range fish @inBody
model gravity 0,0,-9.81
clump attr density @dens_ damp 0.7
model cycle 2000 calm 500
@ini_clusters
@replace
@order_clusters
@list_clusters
fish define inclump(extra, ct)
inclump = 0
if type.pointer.id(ct) = contact.typeid("ball-ball")
if ball.extra(contact.end1(ct),1) == ball.extra(contact.end2(ct),1) then
inclump = 1
exit
endif
endif
end
contact cmat default type ball-ball model linear ...
property kn 10e4 inh off ks 10e4 inh off fric 0.18 inh off
contact cmat default type ball-facet model Linear ...
property kn 10e5 inh off ks 10e5 inh off fric 0.09 inh off
contact cmat add 1 model linearPBond ...
property fric 0.0 kn 0.0 inh off ks 0.0 inh off dp_nratio 0.2 ...
range fish @inclump
model clean
contact cmat apply
@applybonds
fish def restorefriction(arr)
ct=arr(1)
if ball.extra(contact.end1(ct),1) == ball.extra(contact.end2(ct),1)
io.out(string.build("Contact broken! %1",contact.prop(ct,'pb_state')))
contact.model(ct) = 'Linear'
contact.prop(ct,'kn') = 10e4
contact.prop(ct,'ks') = 10e4
contact.prop(ct,'lin_mode') = 1
idc = idc + 1
blist = array.create(1)
blist(1) = contact.end1(ct)
size = array.size(blist,1)
ind = 0
stop = 0
loop while stop = 0
newbonds = 0
newvisited = 0
loop local i (1,size+ind)
if ball.extra(blist(i),2) = 0 ;not visited
newvisited = newvisited + 1
loop foreach local con ball.contactmap(blist(i))
if contact.model(con) # "Linear"
if contact.prop(con,'pb_state')=3
if ball.extra(contact.end1(con),2) = 0
;not visited
if ball.extra(contact.end2(con),2) = 0
;not visited
newbonds = newbonds + 1
endif
endif
endif
endif
endloop
ball.extra(blist(i),2) = 1 ;isvisited
ball.extra(blist(i),1) = idc
endif
endloop
if newbonds#0
oldblist = blist
blist = array.create(size+ind+newbonds)
loop local k (1,size+ind)
blist(k) = oldblist(k)
endloop
loop local ii (size+ind+1-newvisited,size+ind)
clist = ball.contactmap(blist(ii))
loop foreach local jj clist
if contact.model(jj) # "linear"
if contact.prop(jj,'pb_state')=3
if ball.extra(contact.end1(jj),2) = 0 ;not visited
ind = ind + 1
blist(size+ind) = contact.end1(jj)
else if ball.extra(contact.end2(jj),2) = 0 ;not visited
ind = ind + 1
blist(size+ind) = contact.end2(jj)
endif
endif
endif
endloop
endloop
else
stop = 1
endif
endloop
endif
loop foreach local bp ball.list
ball.extra(bp,2) = 0 ;not visited
endloop
end
ball attr density 2000 damp 0.7
fish callback add @restorefriction event bond_break
model mechanical timestep auto
model cycle 2000 calm 500
ball attr damp 0.0
wall attribute rotation-center @rp_ range group 'wallassembly'
wall attribute spin @spin_ range group 'wallassembly'
fish def initializeTime
mp_age_c = mech.time.total
global tinc = 0.01
global tnext = tinc
end
@initializeTime
fish def buildPSD
whilestepping
global temps = mech.time.total-mp_age_c
if temps > tnext then
sizedistribution(20)
tnext = tnext + tinc
endif
end
@sizedistribution(20)
model save 'cluster_model'
model solve time 0.1
model save 'end_blendercluster'
;=============================================================================
; eof: BlenderClusters.p3dat
ClusterMakeCluster.p3dat
; fname: ClusterMakeCluster.p3dat
fish define ini_clusters
global cluster_head = null
global bnumber=0
clt = clump.template.find('pill')
loop foreach p clump.template.pebblelist(clt)
bnumber = bnumber + 1
endloop
io.out(string.build("number of pebbles = %1", bnumber))
end
fish define make_cluster(clump)
; replace a clump with a set of balls
newclus = memory.create(bnumber+3)
memory(newclus) = cluster_head
cluster_head = newclus
global idc = clump.id(clump)
local num=1
memory(newclus+num) = idc
num=num+1
loop foreach local p clump.pebblelist(clump)
global prad = clump.pebble.radius(p)
global ppos = clump.pebble.pos(p)
global idp = clump.pebble.id(p)
command
ball create id @idp rad @prad pos @ppos
endcommand
num = num + 1
local bp = ball.find(idp)
if num>3
if comp.x(ball.pos(bp)) < comp.x(ball.pos(bfirst))
bfirst = bp
endif
else
bfirst = bp
endif
ball.extra(bp,1) = idc
memory(newclus+num) = bp
endloop
memory(newclus+2) = bfirst
clump.delete(clump)
end
fish define replace
loop foreach clump clump.list
make_cluster(clump)
endloop
end
fish define order_clusters
cluster = cluster_head
loop while cluster # null
newcluster = array.create(9)
newcluster(1) = memory(cluster+2)
loop j(2,9)
referenceball = newcluster(j-1)
dist=1000
loop i(1,bnumber)
thisball = memory(cluster+2+i)
newdist = comp.x(ball.pos(thisball))-comp.x(ball.pos(referenceball))
io.out(string.build("newdist = %1",newdist))
if newdist > 0
if newdist < dist
nearestball = thisball
dist = newdist
endif
endif
endloop
newcluster(j) = nearestball
endloop
loop i(1,bnumber)
memory(cluster+i+2) = newcluster(i)
endloop
cluster = memory(cluster)
endloop
end
fish define list_clusters
cluster = cluster_head
loop while cluster # null
local idc = memory(cluster+1)
local bleft = memory(cluster+2)
io.out(string.build("--cluster with ID %1 : ",idc))
io.out(string.build("--left most ball id : %1",ball.id(bleft)))
loop i(1,bnumber)
bp = memory(cluster+i+2)
io.out(string.build(" - ball id %1",ball.id(bp)))
endloop
cluster = memory(cluster)
endloop
end
fish def applybonds
cluster = cluster_head
loop while cluster # null
loop i(1,bnumber-1)
bp = memory(cluster+i+2)
bp_next=memory(cluster+i+3)
local clist = ball.contactmap(bp)
section
loop foreach local con clist
ok=0
if contact.end1(con) = bp_next
ok=1
else if contact.end2(con) = bp_next
ok=1
endif
if ok=1
local arg = array.create(1,2)
arg(1,1) = 'gap'
arg(1,2) = 0.0
contact.method(con,"bond",arg)
contact.prop(con,"pb_kn")=1e12
contact.prop(con,"pb_ks")=1e12
contact.prop(con,"pb_ten")=1e8
contact.prop(con,"pb_coh")=1e6
contact.prop(con,"pb_rmul")=0.8
exit section
endif
endloop
endsection
endloop
cluster = memory(cluster)
endloop
end
;=============================================================================
; eof: ClusterMakeCluster.p3dat
ClusterSizeDistribution.p3dat
; fname: ClusterSizeDistribution.p3dat
fish def clumpvolumes
global volumes = array.create(idc)
loop local i (1,array.size(volumes,1))
volumes(i)=0.0
endloop
loop foreach bp ball.list
volumes(ball.extra(bp,1)) = volumes(ball.extra(bp,1)) ...
+ 1.3333*math.pi*ball.radius(bp)^3
endloop
end
fish def sizedistribution(intervals)
command
@clumpvolumes
endcommand
io.out(string.build("size volumes = %1", array.size(volumes,1)))
nentries = array.size(volumes,1)
radius = array.create(nentries)
minD = 1000
maxD = -1
local nonzeroentries = 0
loop local i (1,array.size(volumes,1))
radius(i) = ((3*volumes(i))/(4*math.pi))^(0.33333)
if radius(i)#0
nonzeroentries = nonzeroentries + 1
minD = math.min(radius(i)*2,minD)
maxD = math.max(radius(i)*2,maxD)
endif
endloop
io.out(string.build("minD = %1 , maxD = %2", minD, maxD))
increment = (maxD-minD)/intervals
passing = array.create(intervals+1)
aveD = array.create(intervals+1)
t = string.build("sizedist%1",nentries)
dist = table.get(t)
loop local j (1,array.size(aveD,1))
aveD(j) = minD + increment*(j-1)
passing(j) = 0.0
endloop
table(t,aveD(1))=passing(1)
loop local p (2,array.size(passing,1))
pass = 0
loop local r (1,array.size(radius,1))
d = radius(r)*2
if d#0
if d<=aveD(p)
pass = pass+1
endif
endif
endloop
passing(p) = 100*(float(pass)/nonzeroentries)
table(t,aveD(p))=passing(p)
endloop
loop local tt (1,array.size(aveD,1))
io.out(string.build("passing[%1] = %2", tt, passing(tt)))
endloop
end
;=============================================================================
; eof: SizeDistribution.p3dat
Was this helpful? ... | PFC 6.0 © 2019, Itasca | Updated: Nov 19, 2021 |