|
| 1 | +#!usr/bin/env python |
| 2 | +import sys |
| 3 | +sys.path.append('/../../Core/Tools') |
| 4 | +from RandomNumberspy import RandomNumbers |
| 5 | +from Particlepy import Particle |
| 6 | +from ClassToolspy import ClassTools |
| 7 | +import numpy as np |
| 8 | +import matplotlib.pyplot as plt |
| 9 | + |
| 10 | +## \brief Multi-D base geometry class - useless by itself, but other multi-D geometry classes inherit from it |
| 11 | + |
| 12 | +# |
| 13 | +# Base class for multi-D geometries |
| 14 | +# |
| 15 | +class Geometry_Base(ClassTools): |
| 16 | + def __init__(self): |
| 17 | + super(Geometry_Base,self).__init__() |
| 18 | + self.flshowplot = False; self.flsaveplot = False |
| 19 | + |
| 20 | + def __str__(self): |
| 21 | + return str(self.__dict__) |
| 22 | + |
| 23 | + ## \brief Define outer boundaries of parallelapided geometry and solve volume |
| 24 | + # |
| 25 | + # \param[in] xbounds, ybounds, zbounds lists of two floats, boundaries of problem domain |
| 26 | + # \returns initializes self.xbounds, self.ybounds, self.zbounds, and calcs self.Volume |
| 27 | + def defineGeometryBoundaries(self,xbounds=None,ybounds=None,zbounds=None): |
| 28 | + assert isinstance(xbounds,list) and isinstance(ybounds,list) and isinstance(zbounds,list) |
| 29 | + assert len(xbounds)==2 and len(ybounds)==2 and len(zbounds)==2 |
| 30 | + assert isinstance(xbounds[0],float) and isinstance(xbounds[1],float) and xbounds[0]<=xbounds[1] |
| 31 | + if self.Part.numDims<2: assert xbounds[0]==-np.inf and xbounds[1]==np.inf |
| 32 | + assert isinstance(ybounds[0],float) and isinstance(ybounds[1],float) and ybounds[0]<=ybounds[1] |
| 33 | + if self.Part.numDims<3: assert ybounds[0]==-np.inf and ybounds[1]==np.inf |
| 34 | + assert isinstance(zbounds[0],float) and isinstance(zbounds[1],float) and zbounds[0]<=zbounds[1] |
| 35 | + if self.GeomType=='Markovian': |
| 36 | + if not ( xbounds[0]==ybounds[0] and xbounds[0]==zbounds[0] and xbounds[1]==ybounds[1] and xbounds[1]==zbounds[1] and -xbounds[0]==xbounds[1] ): |
| 37 | + raise Exception("PlaybookMC's current 3D Markovian geometry implementation requires a cubic domain centered at the origin") |
| 38 | + |
| 39 | + self.xbounds = xbounds |
| 40 | + self.ybounds = ybounds |
| 41 | + self.zbounds = zbounds |
| 42 | + |
| 43 | + self.Volume = self.zbounds[1]-zbounds[0] |
| 44 | + if self.Part.numDims>=2: self.Volume *= (self.xbounds[1]-xbounds[0]) |
| 45 | + if self.Part.numDims==3: self.Volume *= (self.ybounds[1]-ybounds[0]) |
| 46 | + |
| 47 | + |
| 48 | + ## \brief Define boundary conditions |
| 49 | + # |
| 50 | + # \param[in] xBCs, yBCs, zBCs lists of two strings, 'vacuum' or 'reflective' |
| 51 | + # \returns initializes self.xBCs, self.yBCs, self.zBCs |
| 52 | + def defineBoundaryConditions(self,xBCs,yBCs,zBCs): |
| 53 | + assert isinstance(xBCs,list) and isinstance(yBCs,list) and isinstance(zBCs,list) |
| 54 | + assert len(xBCs)==2 and len(yBCs)==2 and len(zBCs)==2 |
| 55 | + |
| 56 | + if self.Part.numDims<2: assert xBCs[0]==None and xBCs[1]==None |
| 57 | + else : |
| 58 | + assert xBCs[0]=='vacuum' or xBCs[0]=='reflective' |
| 59 | + assert xBCs[1]=='vacuum' or xBCs[1]=='reflective' |
| 60 | + |
| 61 | + if self.Part.numDims<3: assert yBCs[0]==None and yBCs[1]==None |
| 62 | + else : |
| 63 | + assert yBCs[0]=='vacuum' or yBCs[0]=='reflective' |
| 64 | + assert yBCs[1]=='vacuum' or yBCs[1]=='reflective' |
| 65 | + |
| 66 | + assert zBCs[0]=='vacuum' or zBCs[0]=='reflective' |
| 67 | + assert zBCs[1]=='vacuum' or zBCs[1]=='reflective' |
| 68 | + |
| 69 | + self.xBCs = xBCs |
| 70 | + self.yBCs = yBCs |
| 71 | + self.zBCs = zBCs |
| 72 | + |
| 73 | + |
| 74 | + ## \brief Defines Cross Sections |
| 75 | + # |
| 76 | + # \param[in] totxs, list of floats, list of total cross sections |
| 77 | + # \param scatxs, list of floats, list of scattering cross sections |
| 78 | + # \returns sets cross sections |
| 79 | + def defineCrossSections(self,totxs=None,scatxs=None): |
| 80 | + assert isinstance(totxs,list) |
| 81 | + self.nummats = len(totxs) |
| 82 | + for i in range(0,self.nummats): |
| 83 | + assert isinstance(totxs[i],float) and totxs[i]>=0.0 |
| 84 | + self.totxs = totxs |
| 85 | + self.Majorant = max(totxs) |
| 86 | + if not scatxs==None: |
| 87 | + assert isinstance(scatxs,list) and len(scatxs)==self.nummats |
| 88 | + for i in range(0,self.nummats): |
| 89 | + assert isinstance(scatxs[i],float) and scatxs[i]>=0.0 and totxs[i]>=scatxs[i] |
| 90 | + self.scatxs = scatxs |
| 91 | + self.absxs = [] |
| 92 | + self.scatrat = [] |
| 93 | + for i in range(0,self.nummats): |
| 94 | + self.absxs.append( self.totxs[i]-self.scatxs[i] ) |
| 95 | + self.scatrat.append( self.scatxs[i]/self.totxs[i] ) |
| 96 | + |
| 97 | + ## \brief Associates random number object - must be instance of RandomNumbers class |
| 98 | + # |
| 99 | + # \param[in] Rng RandomNumbers object |
| 100 | + # \returns initializes self.Rng |
| 101 | + def associateRng(self,Rng): |
| 102 | + assert isinstance(Rng,RandomNumbers) |
| 103 | + self.Rng = Rng |
| 104 | + |
| 105 | + ## \brief Associates Particle object - must be instance of Particle class |
| 106 | + # |
| 107 | + # \param[in] Part Particle object |
| 108 | + # \returns initializes self.Part |
| 109 | + def associatePart(self,Part): |
| 110 | + assert isinstance(Part,Particle) |
| 111 | + self.Part = Part |
| 112 | + |
| 113 | + ## \brief Tests for a leakage or boundary reflection event, flags the first, evaluates the second |
| 114 | + # |
| 115 | + # \returns str 'reflect', 'transmit', 'sideleak', or 'noleak' |
| 116 | + def testForBoundaries(self): |
| 117 | + if self.isclose(self.Part.z,self.zbounds[0]): |
| 118 | + self.Part.z = self.zbounds[0] |
| 119 | + if self.zBCs[0]== 'vacuum': return 'reflect' |
| 120 | + elif self.zBCs[0]=='reflective': self.Part.reflect_z() |
| 121 | + if self.isclose(self.zbounds[1],self.Part.z): |
| 122 | + self.Part.z = self.zbounds[1] |
| 123 | + if self.zBCs[1]== 'vacuum': return 'transmit' |
| 124 | + elif self.zBCs[1]=='reflective': self.Part.reflect_z() |
| 125 | + |
| 126 | + if self.isclose(self.Part.x,self.xbounds[0]): |
| 127 | + self.Part.x = self.xbounds[0] |
| 128 | + if self.xBCs[0]== 'vacuum': return 'sideleak' |
| 129 | + elif self.xBCs[0]=='reflective': self.Part.reflect_x() |
| 130 | + if self.isclose(self.xbounds[1],self.Part.x): |
| 131 | + self.Part.x = self.xbounds[1] |
| 132 | + if self.xBCs[1]== 'vacuum': return 'sideleak' |
| 133 | + elif self.xBCs[1]=='reflective': self.Part.reflect_x() |
| 134 | + |
| 135 | + if self.isclose(self.Part.y,self.ybounds[0]): |
| 136 | + self.Part.y = self.ybounds[0] |
| 137 | + if self.yBCs[0]== 'vacuum': return 'sideleak' |
| 138 | + elif self.yBCs[0]=='reflective': self.Part.reflect_y() |
| 139 | + if self.isclose(self.ybounds[1],self.Part.y): |
| 140 | + self.Part.y = self.ybounds[1] |
| 141 | + if self.yBCs[1]== 'vacuum': return 'sideleak' |
| 142 | + elif self.yBCs[1]=='reflective': self.Part.reflect_y() |
| 143 | + |
| 144 | + return 'noleak' |
| 145 | + |
| 146 | + |
| 147 | + ## \brief Returns distance to geometry boundary, only boundary for WMC-based approach |
| 148 | + # |
| 149 | + # \returns positive float, distance along streaming path to boundary |
| 150 | + def calculateDistanceToBoundary(self): |
| 151 | + if self.isclose(self.Part.u,0.0): dbx = np.inf |
| 152 | + elif self.Part.u>0.0 : dbx = (self.xbounds[1]-self.Part.x)/self.Part.u |
| 153 | + else : dbx = (self.xbounds[0]-self.Part.x)/self.Part.u |
| 154 | + |
| 155 | + if self.isclose(self.Part.v,0.0): dby = np.inf |
| 156 | + elif self.Part.v>0.0 : dby = (self.ybounds[1]-self.Part.y)/self.Part.v |
| 157 | + else : dby = (self.ybounds[0]-self.Part.y)/self.Part.v |
| 158 | + |
| 159 | + if self.isclose(self.Part.w,0.0): dbz = np.inf |
| 160 | + elif self.Part.w>0.0 : dbz = (self.zbounds[1]-self.Part.z)/self.Part.w |
| 161 | + else : dbz = (self.zbounds[0]-self.Part.z)/self.Part.w |
| 162 | + |
| 163 | + return min(dbx,dby,dbz) |
| 164 | + |
| 165 | + |
| 166 | + ## \brief Samples new point, chooses to accept or reject, and chooses to absorb or scatter |
| 167 | + # |
| 168 | + # \returns drives sampling of new points and returns str 'reject', 'absorb', or 'scatter' |
| 169 | + # need to change to allow for standard tracking or Woodcock instead of just Woodcock |
| 170 | + # pseudocode: if woodcock, sample whether or not it is accepted. If it's not woodcock, |
| 171 | + # we just want to sample absorb or scatter. Will also do that if collision is accepted for woodcock. |
| 172 | + def evaluateCollision(self): |
| 173 | + if self.trackingType == "Woodcock": # is there a way to tell that we are using woodcock tracking at this point in the code??? If not, I think I need two functions |
| 174 | + self.samplePoint() #define new point |
| 175 | + if self.Rng.rand()>self.totxs[self.CurrentMatInd]/self.Majorant: return 'reject' #accept or reject potential collision |
| 176 | + return 'absorb' if self.Rng.rand()>self.scatrat[self.CurrentMatInd] else 'scatter' #choose collision type |
| 177 | + |
| 178 | + |
| 179 | + ## \brief samples random point within defined geometry |
| 180 | + # |
| 181 | + # \returns list of floats that are x, y, z values |
| 182 | + def _generateRandomPoint(self): |
| 183 | + x = self.Rng.uniform(self.xbounds[0],self.xbounds[1]) |
| 184 | + y = self.Rng.uniform(self.ybounds[0],self.ybounds[1]) |
| 185 | + z = self.Rng.uniform(self.zbounds[0],self.zbounds[1]) |
| 186 | + |
| 187 | + return [x,y,z] |
| 188 | + |
| 189 | + |
| 190 | + |
| 191 | + |
| 192 | + |
| 193 | + |
| 194 | + |
| 195 | + ## \brief Define mixing parameters (correlation length and material probabilities) |
| 196 | + # To be provided by non-base class |
| 197 | + def defineMixingParams(self,laminf=None,prob=None): |
| 198 | + assert 1==0 |
| 199 | + |
| 200 | + ## \brief Initializes list of material types and coordinate of location, initializes xyz boundary locations |
| 201 | + # To be provided by non-base class |
| 202 | + def initializeGeometryMemory(self): |
| 203 | + assert 1==0 |
| 204 | + |
| 205 | + ## \brief Samples a new point according to the selected rules |
| 206 | + # To be provided by non-base class |
| 207 | + def samplePoint(self): |
| 208 | + assert 1==0 |
0 commit comments