[Tutor] Optimizing a simple radioactive decay simulation

Tim Wilson wilson@visi.com
Thu Dec 12 18:26:01 2002


Hi everyone,

My students and I did a fun little simulation of C-14 decay today using=20
pennies to represent the atoms. We flipped the coins repeatedly until all=
=20
the pennies had "decayed" (by turning up heads) and used the results to=20
make a graph of the decay curve.

I thought it would be fun to replicate the demo on the computer so I coul=
d=20
expand the simulation to many more pennies. My first approach, which I wi=
ll=20
include below, was to create Coin and DecaySim classes that contain the=20
needed methods. This worked perfectly, but was quite slow. Since I'm=20
interested in using simulations to teach science, I wonder if anyone has=20
suggestions for optimizing this code. I realize that there is probably a=20
much simpler approach, but I found this one appealing because of the 1:1=20
mapping between it and the real-life penny simulation.

-Tim

--snip--
"""
decay.py by Tim Wilson <wilson@visi.com>

This program simulates radioactive decay using coins.

"""

import random

class DecaySim:
    """Radioactive decay simulator class.
   =20
    Class uses 'coins' to simulate decayed and undecayed atoms.
   =20
    """
   =20
    def __init__(self, numcoins):
        """Create decay simulator instance."""       =20
        self.contents =3D []
        for i in range(numcoins):
            self.contents.append(Coin(1))
   =20
    def __len__(self):
        """Return number of coins left in simulator."""
        return len(self.contents)
      =20
    def removeTails(self):
        """Remove all coins from the simulator that are 'tails'."""
        self.contents =3D [coin for coin in self.contents if coin.value =3D=
=3D 1]
       =20
    def decay(self):
        """Flip each coin in the simulator and see which ones decay."""
        for coin in self.contents:
            coin.flip()

class Coin:
    """Coin class for use in radioactive decay simulation."""
   =20
    def __init__(self, value):
        """Create a coin instance. 1 =3D heads, 2 =3D tails"""       =20
        self.value =3D value
       =20
    def flip(self):
        """Flip the coin."""
        self.value =3D random.randint(0, 1)

def main():
    """Run the decay simulator."""
    numcoins =3D raw_input("How many coins? ")
    ds =3D DecaySim(int(numcoins))
    halflives =3D 0
    while len(ds) > 0:
        print "Undecayed (heads): %s" % len(ds)
        ds.decay()
        halflives +=3D 1
        ds.removeTails()
    print "\n%s half-lives required." % halflives
   =20
if __name__ =3D=3D '__main__':
    main()

--snip--

Here's the output on my 1-GHz Athlon with 512 MB RAM.

wilsont@galileo:~/Documents> time python decay.py
How many coins? 1000000
Undecayed (heads): 1000000
Undecayed (heads): 500350
Undecayed (heads): 250901
Undecayed (heads): 125447
Undecayed (heads): 62783
Undecayed (heads): 31182
Undecayed (heads): 15479
Undecayed (heads): 7796
Undecayed (heads): 3972
Undecayed (heads): 2001
Undecayed (heads): 1016
Undecayed (heads): 515
Undecayed (heads): 287
Undecayed (heads): 138
Undecayed (heads): 76
Undecayed (heads): 33
Undecayed (heads): 18
Undecayed (heads): 12
Undecayed (heads): 6
Undecayed (heads): 6
Undecayed (heads): 2

21 half-lives required.

real    12m6.267s
user    8m26.820s
sys     0m1.190s

--=20
Tim Wilson
Twin Cities, Minnesota, USA
Science teacher, Linux fan, Zope developer, Grad. student, Daddy
mailto:wilson@visi.com | http://qwerk.org/ | public key: 0x8C0F8813