00001
00002
00003 class units:
00004
00005 second = 1.
00006 minute = 60*second
00007 hour = 60*minute
00008 day = 24*hour
00009 year = 365*day
00010
00011 MeV = 1.
00012 eV = 1.0e-6*MeV
00013 keV = 1.0e-3*MeV
00014 GeV = 1.0e+3*MeV
00015
00016 electron_mass_c2 = 0.51099906 * MeV
00017 pass
00018
00019
00020 class Isotope(object):
00021 '''A nuclide'''
00022
00023 def __init__(self,Z=0,A=0,halflife=0.0,
00024 level=0.0,abundance=0):
00025 import elements
00026 self.name = '%s(%d)'%(elements.name(Z),A)
00027 self.symbol = '%d%s'%(A,elements.symbol(Z))
00028 self.A=A
00029 self.Z=Z
00030 self.halflife=halflife
00031 self.level=level
00032 self.abundance=abundance
00033 self.transitions=[]
00034 return
00035
00036 def __getattr__(self,name):
00037 if name == 'N': return self.A - self.Z
00038 if name == 'lifetime':
00039 import math
00040 return self.halflife/math.log(2.0)
00041 raise AttributeError,'no such attribute ' + name
00042
00043 def __str__(self):
00044 return '%s (%.3f)'%(self.symbol,self.level/units.MeV)
00045
00046 def decayInterval(self,interval):
00047 '''Decay a number of isotopes drawn from the mean for the
00048 given interval. Returns a list of tuples (dt,tranition)'''
00049 from numpy import random
00050 rate = self.abundance/self.lifetime
00051 mean = rate*interval
00052 ndecays = random.poisson(mean)
00053
00054 ret = []
00055
00056
00057 self.abundance -= ndecays
00058
00059
00060 while ndecays:
00061 ndecays -= 1
00062 dt,trans = self.decay(False)
00063 dt = random.uniform(0,interval)
00064 ret.append((dt,trans))
00065 continue
00066
00067
00068 ret.sort()
00069
00070 return ret
00071
00072 def decay(self,reduceAbundance = True):
00073 'Decay this isotope, return [time,Transition]. Does NOT radiate() the Transition'
00074
00075
00076
00077 from numpy import random
00078 import math
00079
00080 total = sum([t.fraction for t in self.transitions])
00081 u = random.uniform(0.0,total)
00082 total = 0.0
00083 trans = None
00084
00085 for t in self.transitions:
00086 total += t.fraction
00087 if u < total:
00088 trans = t
00089 break
00090 continue
00091 if trans is None: return ()
00092
00093 u = random.uniform(0,1)
00094 dt = ((-1*math.log(u)) * self.lifetime/self.abundance)
00095 if reduceAbundance:
00096 self.abundance -= 1
00097
00098 return (dt,trans)
00099
00100 pass
00101
00102
00103
00104
00105 class Transition(object):
00106 '''Transition from an initial to final nuclide states radioactive
00107 emission'''
00108
00109 def __init__(self,initial=None,final=None,radiation=None,
00110 lifetime=0.0,fraction=1.0):
00111 self.initial=initial
00112 self.final=final
00113 self.radiation=radiation
00114 self.fraction=fraction
00115 self.count = 0
00116 self.initial.transitions.append(self)
00117
00118 return
00119
00120 def __str__(self):
00121 return 'Transition[%7.3f%%]: %s --> %s + %s'%(self.fraction*100,self.initial,self.final,self.radiation)
00122
00123 def radiate(self):
00124 self.count += 1
00125 self.final.abundance += 1
00126 return
00127
00128 pass
00129
00130 class PrettyPrint(object):
00131
00132 _tab = ' '
00133
00134 def __init__(self,iso,depth=0):
00135 self.iso = iso
00136 self.depth = depth
00137 return
00138
00139 def tab(self): return PrettyPrint._tab*self.depth
00140
00141 def __str__(self):
00142 import decay
00143 ret = [self.tab()+str(self.iso)]
00144
00145 iso2process = []
00146 for t in self.iso.transitions:
00147
00148
00149
00150 ret.append(self.tab()+str(t))
00151
00152
00153 if t.final.transitions:
00154 ft = t.final.transitions[0]
00155
00156 if type(ft.radiation) == decay.GammaDecay:
00157
00158 ret.append(self.tab()+PrettyPrint._tab+str(ft))
00159 if not ft.final in iso2process:
00160 iso2process.append(ft.final)
00161 continue
00162
00163
00164 if not t.final in iso2process:
00165 iso2process.append(t.final)
00166 continue
00167 for iso in iso2process:
00168 pp = PrettyPrint(iso,self.depth+1)
00169 ret.append(str(pp))
00170
00171 return '\n'.join(ret)
00172
00173
00174
00175 if __name__ == '__main__':
00176 plot_64Cu()
00177