/search.css" rel="stylesheet" type="text/css"/> /search.js">
00001 #!/usr/bin/env python 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 #print "Got %d from %f %s"%(ndecays,mean,self) 00054 ret = [] 00055 00056 # reduce abundance by hand to avoid subtracting by small numbers 00057 self.abundance -= ndecays 00058 00059 # generate decay products 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 # sorts by time 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 # t(n) = t(n-1) * exp(-t/tL) 00075 # u = uniform() 00076 # dt = ((-1*math.log(u)) * lifetime) 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 #print 'Checking',len(self.transitions),'transitions with u',u 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 #trans.radiate() 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 #print self 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: # assume only be non-GammaDecay 00147 00148 # Add this transition 00149 #print self.tab()+str(t) 00150 ret.append(self.tab()+str(t)) 00151 00152 # if daughter not stable 00153 if t.final.transitions: 00154 ft = t.final.transitions[0] 00155 # and if daugther decays by gamma 00156 if type(ft.radiation) == decay.GammaDecay: 00157 # save string rep and ground state for later processing 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 # otherwise, save for recursion 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