Fragmentation Analysis during a Uniaxial Compression with Crack Tracking Using Fractures

Problem Statement

Note

The project file for this example may be viewed/run in PFC.[1] The data files used are shown at the end of this example.

A simple bonded assembly is generated, then brought to failure under uniaxial, unconfined compression. The purpose of this example is to illustrate how fragmentation may be tracked using built-in PFC tools, not to detail the process of building a bonded assembly. For the latter, please refer to the tutorial “Generating a Bonded Assembly” and to the material-modeling support package.

PFC3D Model

A PFC3D bonded assembly is first generated using an approach similar to the one detailed in the “Generating a Bonded Assembly” section. The initial state before compression is shown in Figure 1. In this view, the contacts are colored by the value of the property pb_state (a value of 3 means that parallel bonds are installed) and translated for convenience.

../../../../../../../_images/p3d-fragment-system-initial.png

Figure 1: The initial state. Contacts colored by pb_state are translated for convenience.

To perform uniaxial compression, the assembly is confined between top and bottom wall platens (which are assigned equal and opposite velocities along the \(z\)-direction), and the model is cycled to a target age limit. The magnitude of the forces exerted by the specimen on the platens is monitored via two histories as a measure of the compressive stress applied to the specimen.

The compression is performed three times with different settings.

  • CASE 0 corresponds to a regular run.

  • For CASE 1, the fragment logic is activated and the ball results command is used to save partial state information every 0.1 [time-unit] during the course of the simulation.

  • For CASE 2, in addition to the use of the fragment logic and the ball results command, a FISH function is registered with the linear parallel bond bond_break callback event, which monitors bond breakage events and creates fractures using the Discrete Fracture Network logic to store their location, size, and orientation. Additionally, the fragments are computed only if a bond breakage event occurred, and ball result states are stored only if the number of fragments in the system changed. The FISH functions used to set up this crack-tracking environment are implemented in “fracture.fis”.

Model Results

All three cases produce the same results. The final state for CASE 2 is shown in Figure 2, where contacts and fractures are translated to the right-hand side for convenience. A combination of tensile and shear failures occurred in selected bonded contacts and resulted in the macroscopic failure of the specimen. Forces applied on the platens are identical in magnitude, as shown in Figure 3, and demonstrate the brittleness of the specimen.

../../../../../../../_images/p3d-fragment-system-final2.png

Figure 2: State of the system after loading (CASE 3). Right: balls (colored by fragment index). Left: contacts (colored by pb_state) and fractures (colored by shear/tension failure modes) translated for convenience.

../../../../../../../_images/p3d-fragment-wforce.png

Figure 3: Forces (magnitude) measured on the platens vs. time.

The ability to color the balls by their fragment index is a result of the activation of the fragment logic. This logic embeds additional utilities (please refer to the “Fragment” section for a detailed description). For instance, Figure 4 shows the evolution of the volume of the largest fragment (which consists of the whole assembly at the initial state) relative to its initial value, monitored during the course of the simulation.

../../../../../../../_images/p3d-fragment-fragvol-final2.png

Figure 4: Evolution of the largest fragment volume relative to its initial value.

For CASE 2 and CASE 3, ball configurations and fragment indexes have been saved intermittently during the course of the simulation. Animations can therefore be created using the FISH functions make_movie_case1 (for CASE 1) and make_movie_case2 (for CASE 2). This is an illustration of how the fragment logic and the ball results command can be used together to allow in-depth analysis of the results. Note, however, the costs in terms of memory usage of these two utilities: the sizes of the final model state (SAV) files for CASE 1 and CASE 2 are larger than for CASE 0 (more than 10 times larger for CASE 1). Using custom functions to store model results as performed in CASE 2 can save memory; alternatively, result configurations can be saved as binary files (instead of being stored in RAM) to maintain the memory-usage of the model at a reasonable level.

Conclusion

This example illustrates the steps that may be taken in order to perform a uniaxial compression test on a bonded-particle model with PFC. Moreover, this example describes how the Fragment and Discrete Fracture Network logic can be used, in combination with the ball results command, to track fragmentation and intermittently store pertinent information during the course of the simulation for reuse in a later post-processing step.

fragment.dat

; fname: fragment.dat
;
; Illustrate how the Fragment, DFN and Model Result logic can be used
; to study the fragmentation of a Bonded Particle Model.
;
;=============================================================================
model new
model large-strain on
model precision 15
model title 'Fragmentation of a Bonded Particle Model'

;-----------------------------------------------------------------------------
; --------------- INITIAL PHASE: CREATION OF A BONDED SPECIMEN ---------------
;-----------------------------------------------------------------------------

model domain extent -5 5 -5 5 -7.5 7.5 condition destroy
contact cmat default model linear property kn 1e7
contact cmat default type ball-ball model linearpbond ...
                                    property kn 5e6 proximity 0.1

wall generate box -2.5 2.5 -2.5 2.5 -5 5
model random 10001
ball distribute porosity 0.3 radius 0.25 0.3 box -2.5 2.5 -2.5 2.5 -5 5
ball attribute density 1.0e3 damp 0.7

model cycle 2000 calm 10
model solve calm 1000 ratio-average 5e-3

contact method bond gap 0.1
contact property pb_kn 1e7 pb_ks 1e7 pb_ten 4e5 pb_coh 4e5 pb_fa 20.0

wall delete
contact cmat default type ball-facet model linear ...
                                     property kn 1e7 ks 1e7 fric 0.5

wall generate id 1 name 'top' polygon -4.0 -4.0 5.0 ...
                                      -4.0  4.0 5.0 ...
                                       4.0  4.0 5.0 ...
                                       4.0 -4.0 5.0


wall generate id 2 name 'bottom' polygon -4.0 -4.0 -5.0 ...
                                         -4.0  4.0 -5.0 ...
                                          4.0  4.0 -5.0 ...
                                          4.0 -4.0 -5.0

wall attribute rotation-center 0.0 0.0  5.0 range position-z  5.0
wall attribute rotation-center 0.0 0.0 -5.0 range position-z -5.0
model clean
model cycle 10
model solve elastic ratio-average 5e-3
wall attribute velocity-z 0.0 gradient 0.0 0.0 -0.001
model history name '1' mechanical time-total
wall history name '2' force-contact id 1
wall history name '3' force-contact id 2
model save 'initial'

;-----------------------------------------------------------------------------
; ------------ CASE 0: NO TRACKING OF FRAGMENTS - NO BALL RESULTS ------------
;-----------------------------------------------------------------------------

model solve time 50.0
model save 'final-case0'

;-----------------------------------------------------------------------------
; ------------ CASE 1: CONTINUOUS UPDATE OF FRAGMENTS WITH BALL RESULTS ------
;-----------------------------------------------------------------------------
model restore 'initial'

fragment register ball-ball
fragment activate time 0.1
model mechanical time-total 0.0
model result interval mechanical 0.1
ball result add-attribute fragment
wall result add-attribute velocity

model solve time 50.0
model save 'final-case1'

;program call post_treat.fis
;[make_movie_case1]

;-----------------------------------------------------------------------------
; ------------ CASE 2: CUSTOM UPDATE OF FRAGMENTS AND BALL RESULTS -----------
;-----------------------------------------------------------------------------
model restore 'initial'

program call 'fracture.fis'
[track_init]
model solve time 50.0
[track_end]
model save 'final-case2'

;program call post_treat.fis
;[make_movie_case2]

program return 
;=============================================================================
; eof: fragment.dat

fracture.fis

; fname: fracture.fis
;
; Simple environment to track fragmentation in a BPM.
; Monitor LinearPBond model "bond_break" events and turn them into fractures.
; Use the Fragment and Ball Result logic to record fragment IDs 
;
;=============================================================================

fish define add_crack(entries)
  local contact    = entries(1)
  local mode       = entries(2)
  local strength   = entries(3)
  local frac_pos   = contact.pos(contact)
  local norm       = contact.normal(contact)
  local dfn_label  = 'crack'
  local frac_dip
  local frac_dipdir
  local frac_size = contact.prop(contact,'pb_radius')
  
  local len2 = math.sqrt(comp.x(norm)*comp.x(norm)+comp.y(norm)*comp.y(norm))
  if len2 = 0
    len2 = 1
  endif
  frac_dipdir = math.atan2(comp.x(norm)/len2,comp.y(norm)/len2) / math.degrad
  local len3 = math.sqrt(len2*len2+comp.z(norm)*comp.z(norm))
  if len3 = 0
    len3 = 1
  endif
  frac_dip = math.atan2(len2/len3,comp.z(norm)/len3) / math.degrad
  if frac_dip<0.0
    frac_dip = -frac_dip
    frac_dipdir = frac_dipdir + 180.0
  endif
  if frac_dip>90.0
    frac_dip = 180.0-frac_dip
    frac_dipdir = frac_dipdir + 180.0
  endif
  if frac_dipdir<0.0
    frac_dipdir = frac_dipdir + 360.0
  endif
  if frac_dipdir > 360.0
    frac_dipdir = frac_dipdir - 360.0
  endif
  if mode = 1 then 
    ; failed in tension
    dfn_label = dfn_label + '_tension'
  else if mode = 2 then
    ; failed in shear
    dfn_label = dfn_label + '_shear'
  endif
  local arg = array.create(5)
  arg(1) = 'disk'
  arg(2) = frac_pos
  arg(3) = frac_size
  arg(4) = frac_dip
  arg(5) = frac_dipdir 

  global dfn = dfn.find(dfn_label)
  if dfn = null then
    dfn = dfn.create(dfn_label)
  endif
  local fnew = fracture.create(dfn,arg)
  fracture.prop(fnew,'failure_strength') = strength
  fracture.prop(fnew,'age')  = mech.time.total
  crack_added = true
end

fish define track_fname
  track_fcount += 1
  track_fname = string.build('frag%1.p3result',track_fcount)
end

fish define track_init
  command
    fracture delete
    model result clear-map
    fragment clear
    fragment register ball-ball
    ball result add-attribute fragment
    wall result add-attribute velocity
  endcommand
  ; activate fishcalls
  command
    fish callback remove add_crack event bond_break
    fish callback add add_crack event bond_break
    fish callback remove monitor 100.0
    fish callback add monitor 100.0
  endcommand
  ; reset global variables
  global crack_added = false
  global track_fcount = 0
  command
    fragment compute
    model result export [track_fname]
  endcommand
  global track_map = map(mech.time.total,fragment.num(1))
end

fish define monitor
  if crack_added = true then
    local numfrag = fragment.num()
    command 
      fragment compute
    endcommand
    if fragment.num() # numfrag then
      command
        model result export [track_fname]
      endcommand
      map.add(track_map,mech.time.total,numfrag)
    endif
  endif
  crack_added = false
end

fish define make_table
  local frag1 = fragment.find(1)
  local tab = table.create('volfrag1')
  loop foreach local value map.keys(track_map)
    table(tab,value) = ...
       fragment.vol(frag1,fragment.catalog.num(value)) / fragment.vol(frag1,1)
  endloop
end

fish define track_end
  local numfrag = fragment.num()
  command 
    fragment compute
  endcommand
  if fragment.num() # numfrag then
    command
      model result export [track_fname]
    endcommand
    map.add(track_map,mech.time.total,numfrag)
  endif
  make_table
end


;=============================================================================
; eof: fracture.p3fis

post_treat.fis

fish define make_movie_case1
  command
    set echo off
    ball result map [track_map]
  endcommand
  local count = 1
  loop foreach local value track_map
    global fname = string.build('fragments_case1_%1.png',count)
    command
      domain extent -10 10
      ball result load [count] nothrow on
      wall result load [count] nothrow on
      plot current view 'the system'
      plot bitmap filename [fname] 
    endcommand
    count += 1
  endloop
  command
    set echo on
  endcommand
end

fish define make_movie_case2
  local keys = map.keys(track_map)
  local count = 1
  command
    set echo off
  endcommand
  loop foreach value keys
    local fname = string.build('fragments_case2_%1.png',count)
    command
      domain extent -10 10
      ball result load [count] nothrow on
      wall result load [count] nothrow on
      plot current view 'Fragments and Cracks'
      plot mod 4 dfn colorby numericproperty "age" coloropt scaled ...
           ramp max [value] above none map translate 10 0 0 
      plot mod 5 table xaxis max [value]
      plot bitmap filename [fname] 
    endcommand
    count += 1
  endloop
  command
    set echo on
  endcommand
end

Endnotes