Data Files for “Using FISH Callbacks” Tutorial

callbacks1.p3dat

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
; fname: callbacks1.p3dat
;
; Demonstrate usage of the set fish callback command to insert balls at a
; given rate while cycling
;
;==============================================================================
model new
model random 10001
model title 'Using FISH Callbacks'

; Define the domain and the default contact model 
model domain extent -3 3
contact cmat default model linear property kn 1.0e6 dp_nratio 0.5

; Generate a box and set gravity
wall generate box -2 2
model gravity 10.0

; Define the add_ball function, which will be registered as a fish callback
; and will insert balls at a given frequency in the model
fish define add_ball
  local tcurrent = mech.time.total
  if tcurrent < tnext then
    exit
  endif
  tnext = tcurrent + freq
  local xvel = (math.random.uniform -0.5) * 2.0
  local yvel = (math.random.uniform -0.5) * 2.0
  local bp = ball.create(0.3,vector(0.0,0.0,1.75))
  ball.vel(bp) = vector(xvel,yvel,-2.0)
  ball.density(bp) = 1.1e3
  ball.damp(bp) = 0.1
end
; Set parameters and register the function add_ball with a fish callback at 
; position -11.0 in the cycle sequence. Model components cannot be inserted 
; in the model after the timestep has been evaluated, which corresponds to 
; position 0.0 in the cycle sequence
[freq = 0.25]
[time_start = mech.time.total]
[tnext  = time_start ]
fish callback add @add_ball -11.0

; Solve to a target time of 10.0 time-units
model solve time 10.0
model save 'intermediate'

; Continue cycling to an additional target time of 15.0 time-units
; Note that the fish callback is still active
model solve time 15.0

; Deactivate the fish callback and solve to equilibrium (default limit
; corresponds to an average ratio of 1e-5) 
fish callback remove @add_ball -11.0
model solve
model save 'settled'
return
;==============================================================================
; eof: callbacks1.p3dat

callbacks2.p3dat

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
; fname: callbacks2.p3dat
;
; Demonstrate usage of the set fish callback command to insert balls at a
; given rate while cycling and add applied forces to the balls
;==============================================================================
model new
model random 10001
model title 'Using FISH Callbacks'

; Define the domain and the default contact model 
model domain extent -3 3
contact cmat default model linear property kn 1.0e6 dp_nratio 0.5

; Generate a box and set gravity
wall generate box -2 2
model gravity 10.0

; Define the add_ball function, which will be registered as a fish callback
; and will insert balls at a given frequency in the model
fish define add_ball
  local tcurrent = mech.time.total
  if tcurrent < tnext then
    exit
  endif
  tnext = tcurrent + freq
  local xvel = (math.random.uniform -0.5) * 2.0
  local yvel = (math.random.uniform -0.5) * 2.0
  local bp = ball.create(0.3,vector(0.0,0.0,1.75))
  ball.vel(bp) = vector(xvel,yvel,-2.0)
  ball.density(bp) = 1.1e3
  ball.damp(bp) = 0.1
end
; Set parameters and register the function add_ball with a fish callback at 
; position -11.0 in the cycle sequence. Model components cannot be inserted 
; in the model after the timestep has been evaluated, which corresponds to 
; position 0.0 in the cycle sequence
[freq = 0.25]
[time_start = mech.time.total]
[tnext  = time_start ]
fish callback add @add_ball -11.0


; Define the add_fluidforces function, which will be registered as a fish 
; callback and will apply fluid forces (buoyancy and drag) to the balls
fish define add_fluidforces
  global vf = 0.0
  loop foreach ball ball.list
    local vi = 0.0
    local d1 = ball.pos.z(ball) - ball.radius(ball)
    if ball.pos.z(ball) - ball.radius(ball) >= zf_ 
      ; above water level
      ball.force.app(ball) = vector(0.0,0.0,0.0)
    else 
      local fdrag = -6.0*math.pi*etaf_*ball.radius(ball)*ball.vel(ball)
      local vbal = 4.0*math.pi*ball.radius(ball)^3 / 3.0
      if ball.pos.z(ball) + ball.radius(ball) <= zf_ then
        ; totally immerged
        vi = 4.0*math.pi*ball.radius(ball)^3 / 3.0
      else
        ; partially immerged
        if ball.pos.z(ball) >= zf_ then
          global h = ball.radius(ball) - (ball.pos.z(ball)-zf_)
          global vcap = math.pi*h^2*(3*ball.radius(ball) - h) /3.0
          vi = vcap
        else
          h = ball.radius(ball) - (zf_ - ball.pos.z(ball))
          vcap = math.pi*h^2*(3*ball.radius(ball) - h) /3.0
          vi = vbal - vcap
        endif
      endif
      global fb = -1.0*rhof_*vi*global.gravity
      ball.force.app(ball) = fb + (vi/vbal) *fdrag
    endif
    vf = vf + vi
  endloop
end

; Define the move_surface function, which will be registered as a fish 
; callback and will update the fluid surface position to account for 
; immersed balls volume
fish define move_surface
  zf_ = zf0_ + (vf/16.0)
  loop foreach node geom.node.list(gset_)
    geom.node.pos.z(node) = zf_
  endloop
end


; Set parameters and create a polygon with the geometry logic to 
; visualize the fluid surface. Store a pointer to the geometry set
; to be used by the move_surface function.
[rhof_ = 1.26e3]
[zf0_ = -1.0]
[zf_ = zf0_]
[etaf_ = 1.49]
geometry set 'surface' polygon create by-position -2.0 -2.0 @zf0_ ...
                                       2.0 -2.0 @zf0_ ...
                                       2.0  2.0 @zf0_ ...
                                      -2.0  2.0 @zf0_ 
[gset_ = geom.set.find('surface')]

; Register the add_fluidforces and move_surface functions
; at cycle points 50.0 and 50.1 in the cycle sequence respectively.
; The operations will occur after force-displacement calculation, and 
; the applied forces will affect the balls at the next step. 
; The move_surface function will be called after fluid forces have been
; applied to all the balls (and immersed volumes updated)
fish callback add @add_fluidforces 50.0
fish callback add @move_surface 50.1

; Solve to a target time of 10.0 time-units
model solve time 10.0
model save 'fluid-intermediate'

; Continue cycling to an additional target time of 15.0 time-units
; Note that the fish callback is still active
model solve time 15.0

; Deactivate the add_ball fish callback and solve to equilibrium (default
; limit corresponds to an average ratio of 1e-5) 
fish callback remove @add_ball -11.0
model solve
model save 'fluid-final'
return
;==============================================================================
; eof: callbacks2.p3dat

callbacks3.p3dat

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
; fname: callbacks3.p3dat
;
; Demonstrate usage of the set fish callback command to insert balls at a 
; given rate while cycling and add fluid forces
;==============================================================================
model restore 'settled'

[todelete = map()]
fish define delete_balls
  loop foreach key map.keys(todelete)
    local ball = map.remove(todelete,key)
    ball.delete(ball)  
  endloop
end

fish callback add @delete_balls -12.0
model gravity 10.0 0.0 0.0

model save 'sink-initial'

; Register a function with the contact_create event
fish define catch_contacts(cp)
  if type.pointer(cp) # 'ball-facet' then
    exit
  endif
  wfp = contact.end2(cp)
  if wall.id(wall.facet.wall(wfp)) # 2 then
    exit
  endif
  map.add(todelete,ball.id(contact.end1(cp)),contact.end1(cp))
end
fish callback add @catch_contacts event contact_create
model solve time 5.0
model save 'sink-final1'

; Register a function with the contact_activated event
model restore 'sink-initial'

fish define catch_contacts(arr)
  local cp = arr(1)
  if type.pointer(cp) # 'ball-facet' then
    exit
  endif
  local wfp = contact.end2(cp)
  if wall.id(wall.facet.wall(wfp)) # 2 then
    exit
  endif
  map.add(todelete,ball.id(contact.end1(cp)),contact.end1(cp))
end
fish callback add @catch_contacts event contact_activated
model solve time 5.0
model save 'sink-final2'

return
;==============================================================================
; eof: callbacks3.p3dat