
Percolation Simulation

This is a simulation of aspects of mathematical percolation theory.

For other percolation simulations, see Category:Percolation Simulations, or:
1D finite grid simulation
Mean run density 
2D finite grid simulations
Site percolation | Bond percolation | Mean cluster density

Given an 



M
×
N


{\displaystyle M\times N}

 rectangular array of cells numbered 




c
e
l
l

[
0..
M
−
1
,
0..
N
−
1
]


{\displaystyle \mathrm {cell} [0..M-1,0..N-1]}

assume 



M


{\displaystyle M}

 is horizontal and 



N


{\displaystyle N}

 is downwards.

Assume that the probability of any cell being filled is a constant 



p


{\displaystyle p}

 where

 



0.0
≤
p
≤
1.0


{\displaystyle 0.0\leq p\leq 1.0}


The task

Simulate creating the array of cells with probability 



p


{\displaystyle p}

 and then
testing if there is a route through adjacent filled cells from any on row 



0


{\displaystyle 0}

 to any on row 



N


{\displaystyle N}

, i.e. testing for site percolation.

Given 



p


{\displaystyle p}

 repeat the percolation 



t


{\displaystyle t}

 times to estimate the proportion of times that the fluid can percolate to the bottom for any given 



p


{\displaystyle p}

.

Show how the probability of percolating through the random grid changes with 



p


{\displaystyle p}

 going from 



0.0


{\displaystyle 0.0}

 to 



1.0


{\displaystyle 1.0}

 in 



0.1


{\displaystyle 0.1}

 increments and with the number of repetitions to estimate the fraction at any given 



p


{\displaystyle p}

 as 



t
>=
100


{\displaystyle t>=100}

.

Use an 



M
=
15
,
N
=
15


{\displaystyle M=15,N=15}

 grid of cells for all cases.

Optionally depict a percolation through a cell grid graphically.

Show all output on this page.

my $block = '▒';
my $water = '+';
my $pore  = ' ';
my $grid  = 15;
my @site;
 
enum Direction <DeadEnd Up Right Down Left>;
 
say 'Sample percolation at .6';
percolate(.6);
.join.say for @site;
say "\n";
 
my $tests = 1000;
say "Doing $tests trials at each porosity:";
for .1, .2 ... 1 -> $p {
    printf "p = %0.1f: %0.3f\n", $p, (sum percolate($p) xx $tests) / $tests
}
 
sub infix:<deq> ( $a, $b ) { $a.defined && ($a eq $b) }
 
sub percolate ( $prob  = .6 ) {
    @site[0] = [$pore xx $grid];
    @site[$grid + 1] = [$pore xx $grid];
 
    for ^$grid X 1..$grid -> ($x, $y) {
        @site[$y;$x] = rand < $prob ?? $pore !! $block
    }
    @site[0;0] = $water;
 
    my @stack;
    my $current = [0;0];
 
    loop {
        if my $dir = direction( $current ) {
            @stack.push: $current;
            $current = move( $dir, $current )
        }
        else {
            return False unless @stack;
            $current = @stack.pop
        }
        return True if $current[1] > $grid
    }
 
    sub direction( [$x, $y] ) {
        (Down  if @site[$y + 1][$x] deq $pore) ||
        (Left  if @site[$y][$x - 1] deq $pore) ||
        (Right if @site[$y][$x + 1] deq $pore) ||
        (Up    if @site[$y - 1][$x] deq $pore) ||
        DeadEnd
    }
 
    sub move ( $dir, @cur ) {
        my ( $x, $y ) = @cur;
        given $dir {
            when Up    { @site[--$y][$x] = $water }
            when Down  { @site[++$y][$x] = $water }
            when Left  { @site[$y][--$x] = $water }
            when Right { @site[$y][++$x] = $water }
        }
        [$x, $y]
    }
}