00001
00002 '''
00003 238U decay chain
00004 '''
00005
00006 import decay,chain
00007 from data import units
00008
00009
00010 class U238Tests(object):
00011
00012 _chain = chain.G4DataChain(92,238)
00013
00014 def __init__(self):
00015 import random
00016 self.random = random.Random()
00017 return
00018
00019 def isotope(self): return self.chain().head
00020 def chain(self): return U238Tests._chain
00021
00022 def setAbundance(self,grams):
00023 self.isotope().abundance = grams * 6.02e23/238.0
00024
00025 def meanRate(self):
00026 return self.isotope().lifetime/self.isotope().abundance
00027
00028 def singleDecays(self):
00029 target = 10000
00030 count = 0
00031 while count < target:
00032 count += 1
00033 rad = self.isotope().decay()
00034
00035 while rad:
00036 time,trans = rad
00037
00038 rad = trans.final.decay()
00039 continue
00040 continue
00041 for iso in self.chain().groundStates:
00042 print '%s abundance=%.3f'%(iso,iso.abundance)
00043 return
00044
00045 def radiateTransitions(self,dt_trans):
00046 '''Given list of (dt,transition), radiate the transitions. If
00047 a transition results in a excited daughter, immediately radate
00048 the gamma. A copy of dt_trans, with any gamma transitions
00049 appended, is returned.'''
00050
00051 ret = []
00052
00053
00054 for dt,tran in dt_trans:
00055
00056 tran.radiate()
00057
00058 ret.append((dt,tran))
00059
00060 try:
00061 t = tran.final.transitions[0]
00062 if type(t.radiation) == decay.GammaDecay:
00063 ret.append((dt,t))
00064 except IndexError:
00065 pass
00066 continue
00067 return ret
00068
00069
00070 def decayChainInterval(self,interval):
00071 import decay
00072 dt_trans = []
00073 for s in self.chain().groundStates:
00074 if s.abundance == 0.0: continue
00075 dks = s.decayInterval(interval)
00076
00077 if not dks: continue
00078 dt_trans += dks
00079 continue
00080 return self.radiateTransitions(dt_trans)
00081
00082 def trackAbundances(self,cycles,interval):
00083 abs = {}
00084 for s in self.chain().groundStates:
00085 abs[s] = []
00086 ntrans = []
00087 while cycles:
00088 cycles -= 1
00089 dks = self.decayChainInterval(interval)
00090 ntrans.append(len(dks))
00091 for s in self.chain().groundStates:
00092 abs[s].append(s.abundance)
00093 continue
00094 continue
00095 return abs,ntrans
00096
00097 def plotAbundances(self,abs):
00098 import matplotlib.pyplot as plt
00099 plt.figure(1)
00100
00101 nplots = sum([s.abundance > 0.0 and s.symbol != '238U' for s in abs.keys()])
00102
00103 nstates = len(abs)
00104 n = 0
00105 for s,ab in abs.iteritems():
00106 if s.abundance == 0.0 or s.symbol == '238U':
00107 print 'Skipping %s'%s
00108 continue
00109 n += 1
00110 end = len(ab)
00111 print 'Plotting %s with final abundance %f from 0 to %d'%(s,s.abundance,end)
00112 plt.subplot(nplots,1,n)
00113 plt.plot(range(0,end),ab,'r')
00114 plt.title(s.symbol)
00115 continue
00116 plt.show()
00117 return
00118
00119 def setSecularEquilibrium(self):
00120 '''Sets 8 isotopes starting subchains in secular equilibrium
00121 with the 238U. Returns a list with 238U and the 8 daughters'''
00122 daughters = ['234Th','234U','230Th','226Ra','222Rn','210Pb','210Bi','210Po']
00123 u238 = self.isotope()
00124 ret = [u238]
00125 for s in self.chain().groundStates:
00126 if not s.symbol in daughters: continue
00127 s.abundance = u238.abundance*s.halflife/u238.halflife
00128 ret.append(s)
00129 print '\n'.join(map(str,ret))
00130 return ret
00131
00132 def generateDecays(self,states,ndecays):
00133 '''Generate ndecays starting from the given list of parent
00134 states. Parent states are considered independent in the sense
00135 that a decay subchain is fortced to occur until either a
00136 stable state is reached or a state in the list of states is
00137 reached. A list of the resulting radiations will be returned.
00138 '''
00139 totalrate = 0
00140 for s in states:
00141 totalrate += s.abundance/s.halflife
00142 continue
00143
00144 decays = []
00145
00146 while ndecays:
00147 ndecays -= 1
00148
00149
00150 r = self.random.uniform(0,totalrate)
00151 goal = 0
00152 for s in states:
00153 goal += s.abundance/s.halflife
00154 if r < goal:
00155 goal = s
00156 break
00157 continue
00158
00159 print 'Starting %s (%f/%f)'%(goal,r,totalrate)
00160
00161
00162 while True:
00163 rad = goal.decay()
00164 decays.append(rad)
00165 trans = rad[1]
00166 trans.radiate()
00167 final = trans.final
00168 if final in states or final.symbol == '206Pb':
00169 break
00170 goal = final
00171 continue
00172 continue
00173 return decays
00174 pass
00175
00176 def seceq():
00177 u238 = U238Tests()
00178 u238.setAbundance(grams=20.0e-6)
00179 abs,ntrans = u238.trackAbundances(10000,1000)
00180 u238.plotAbundances(abs)
00181
00182 def decays():
00183 u238 = U238Tests()
00184 u238.setAbundance(grams=20.0e-6)
00185 heads = u238.setSecularEquilibrium()
00186 print '\n'.join(map(str,heads))
00187 dt_trans = u238.generateDecays(heads,10)
00188 print '%d transitions:'%len(dt_trans)
00189 for dt,trans in dt_trans:
00190 print '@%8.3f %s'%(dt,trans)
00191 return u238
00192
00193 if '__main__' == __name__:
00194
00195 decays()
00196
00197
00198