# Plotting cracks in 3DEC

**URL:** <https://forum.itascainternational.com/t/plotting-cracks-in-3dec/1899>\
**Category:** 3DEC\
**Tags:** tips\
**Created:** [January 15, 2025, 9:23pm UTC](https://forum.itascainternational.com/t/plotting-cracks-in-3dec/1899 "2025-01-15T21:23:51Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![jhazzard](https://avatars.discourse-cdn.com/v4/letter/j/4af34b/32.png) [@jhazzard](https://forum.itascainternational.com/u/jhazzard)\
**Post date:** [January 15, 2025, 9:23pm UTC](https://forum.itascainternational.com/t/plotting-cracks-in-3dec/1899/1 "2025-01-15T21:23:51Z")

</div>

In 3DEC, joint failure is associated with subcontacts. However the subcontacts represent points, so it is not easy to plot them as 2D “cracks”. This is different from UDEC where the contacts are lines that can be easily plotted.

Assuming you have a BBM type model (i.e. a model with lots of blocks and contacts, rather than a model with a few large joints), you could group the contacts according to the subcontact failures, and then plot joints and range by the group names. Example FISH function below. This generates the plot shown below for the [fragmentation](https://docs.itascacg.com/itasca930/3dec/docproject/source/examples/UCS_Fragmentation.html?node7470) example in the manual.

```
fish def plot_cracks
  loop foreach cp block.contact.list
    count = 0
    broken = 0
    loop foreach cx block.contact.subcontact(cp)
      count += 1
      if block.subcontact.state(cx) > 0
        broken += 1
      endif
    end_loop

    if broken = count
      block.contact.group(cp) = 'fully-cracked'
    else if broken > 0
      block.contact.group(cp) = 'partially-cracked'
    endif
  end_loop
end
[plot_cracks]

; same function multi-threaded
fish operator plot_cracks_multi(cp)
    local count = 0
    local broken = 0
    loop foreach local cx block.contact.subcontact(cp)
      count += 1
      if block.subcontact.state(cx) > 0
        broken += 1
      endif
    end_loop

    if broken = count
      block.contact.group(cp) = 'fully-cracked'
    else if broken > 0
      block.contact.group(cp) = 'partially-cracked'
    endif
end

```

 ![cracks1](https://canada1.discourse-cdn.com/flex031/uploads/itasca/original/2X/3/3a7f0afb55b65727ac9a13ec7fddca6ddf5ff8f7.png)  
[plot\_cracks\_multi(::block.contact.list)]

---

<div class="post-metadata">

**Author:** ![jhazzard](https://avatars.discourse-cdn.com/v4/letter/j/4af34b/32.png) [@jhazzard](https://forum.itascainternational.com/u/jhazzard)\
**Post date:** [January 16, 2025, 2:56pm UTC](https://forum.itascainternational.com/t/plotting-cracks-in-3dec/1899/2 "2025-01-16T14:56:25Z")

</div>

Follow up. If you want to plot cracks by failure mode, you can use the code below. Note however that:

1. This gives the state when the function is called, not when the crack first forms. If you want to record the state when the crack first forms, you would need to use a fish callback with event subcontact\_state\_change
2. Generally when a subcontact fails in tension, it will also quickly fail in shear because the cohesion drops to 0 and the frictional force will also be 0 (no normal force). To prevent this, you can specify a residual cohesion that is not 0

> fish operator plot\_crack\_type(cp)  
> local tensile = 0  
> local shear = 0  
> loop foreach local cx block.contact.subcontact(cp)  
> if math.and(block.subcontact.state(cx),4) # 0  
> shear += 1  
> endif  
> if math.and(block.subcontact.state(cx),8) # 0  
> tensile += 1  
> endif  
> end\_loop
> 
> ```
> if shear > tensile
> block.contact.group(cp) = 'shear'
> else if tensile > shear
> block.contact.group(cp) = 'tensile'
> else if shear > 0
> block.contact.group(cp) = 'mixed'
> endif
> 
> ```
> 
> end  
> [plot\_crack\_type(::block.contact.list)]
