def help_test_slit_beamstop(component, passes): # Where the neutron is when it reaches the component. xs_arrived = np.arange(-9, 10) # 19 ys_arrived = np.arange(-9, 10) # 19 # How the neutron position is different before it reaches the component. dxs = np.arange(-3, 4) # 7 dys = np.arange(-3, 4) # 7 # Try various neutron weights. ws = deque(np.arange(0.2, 1.1, 0.2)) # Pattern of weights should be irregular against geometry of test data. assert gcd(len(ws), prod(map(len, [xs_arrived, ys_arrived, dxs, dys]))) == 1 # Fill a neutron buffer with a range of neutrons that approach the plane of # the component. neutrons_start = [] neutrons_end_expected = [] (any_pass, any_fail) = (False, False) for x_arrived in xs_arrived: for y_arrived in ys_arrived: for dx in dxs: for dy in dys: # Construct an incoming neutron 2m before. distance = sqrt(sum([2, pow(dx, 2), pow(dy, 2)])) position_start = [x_arrived + dx, y_arrived + dy, -2] velocity = [n / distance for n in [-dx, -dy, 2]] # 1 m/s w = ws[0] ws.rotate() # A different weight for the next neutron. neutrons_start.append(neutron( r=position_start, v=velocity, prob=w)) if passes(x_arrived, y_arrived, w): # Construct a neutron expected from the component. position_arrived = [x_arrived, y_arrived, 0] neutrons_end_expected.append(neutron( r=position_arrived, v=velocity, prob=w, time=distance)) any_pass = True else: any_fail = True assert any_pass and any_fail neutrons_end_expected = neutron_buffer_from_array(neutrons_end_expected) # Propagate the neutrons. neutrons_buffer = neutron_buffer_from_array(neutrons_start) component.process(neutrons_buffer) # Compare the actual neutrons with the expectation. tolerance = 1e-6 if get_numpy_floattype() == np.float32 else 1e-15 assert np.allclose(neutrons_as_npyarr(neutrons_buffer), neutrons_as_npyarr(neutrons_end_expected), atol=tolerance)
def process(self, neutrons): if not len(neutrons): return from mcni.neutron_storage import neutrons_as_npyarr, ndblsperneutron # number of doubles per neutrons thats means each neutron is represented by x, y, z, vx, vy, vz, s1, s2, t, t0, p (10 double variables) arr = neutrons_as_npyarr(neutrons) #converting the input neutrons to array arr.shape = -1, ndblsperneutron x = arr[:, 0]; y = arr[:, 1]; z = arr[:, 2] vx = arr[:, 3]; vy = arr[:, 4]; vz = arr[:, 5] s1 = arr[:, 6]; s2 = arr[:, 7]; t = arr[:, 8]; t0 = t.copy() p = arr[:, 9] # propagate to Z = 0 self._propagateToZ0(x, y, z, vx, vy, vz, t) # Filter ftr = (x >= -self.xwidth / 2) * (x < self.xwidth / 2) \ * (y >= -self.yheight / 2) * (y < self.yheight / 2) \ * (t > t0) # xindex = (x+self.xwidth/2)//self.dx; xindex[xindex<0] = 0; xindex[xindex>=self.Nx]=self.Nx-1 yindex = (y+self.yheight/2)//self.dy; yindex[yindex<0] = 0; yindex[yindex>=self.Ny]=self.Ny-1 index = yindex + xindex * self.Ny N = ftr.sum() from mccomponents.detector.event_utils import datatype events = np.zeros(N, dtype=datatype) events['pixelID'] = index[ftr] events['tofChannelNo']=t[ftr]*1e6/self.tofbinsize events['p'] = p[ftr] self._save(events) return
def process(self, neutrons): if not len(neutrons): return from mcni.neutron_storage import neutrons_as_npyarr, ndblsperneutron arr = neutrons_as_npyarr(neutrons) arr.shape = -1, ndblsperneutron x = arr[:,0]; y = arr[:,1]; z = arr[:,2] vx = arr[:,3]; vy = arr[:,4]; vz = arr[:,5] s1 = arr[:,6]; s2 = arr[:,7]; t = arr[:,8]; t0 = t.copy() p = arr[:,9] # propagate to z = 0 self._propagateToZ0(x,y,z,vx,vy,vz,t) # Apply filter if area is positive assert self.xwidth > 0 and self.yheight > 0 # Filter ftr = (x >= -self.xwidth/2)*(x <= self.xwidth/2)*(y >= -self.yheight/2)*(y <= self.yheight/2)*(t>t0) x = x[ftr]; y = y[ftr]; z = z[ftr]; vx = vx[ftr]; vy = vy[ftr]; vz = vz[ftr]; s1 = s1[ftr]; s2 = s2[ftr]; t = t[ftr]; p = p[ftr]; events = x,y,z,t,p self.save(events) return
def process(self, neutrons): """ Propagate a buffer of particles through this guide. Adjusts the buffer to include only the particles that exit, at the moment of exit. Parameters: neutrons: a buffer containing the particles """ (entrance_width, entrance_height, R0, Qc, alpha, m, W) = self.nature neutron_array = neutrons_as_npyarr(neutrons) neutron_array.shape = -1, ndblsperneutron threads_per_block = 256 number_of_blocks = ceil(len(neutrons) / threads_per_block) guide_process[number_of_blocks, threads_per_block](entrance_width, entrance_height, R0, Qc, alpha, m, W, self.sides, neutron_array) cuda.synchronize() mask = array(list(map(lambda weight: weight > 0, neutron_array.T[9])), dtype=bool) neutrons.resize(count_nonzero(mask), neutrons[0]) neutrons.from_npyarr(neutron_array[mask])
def process(self, neutrons): if not len(neutrons): return from mcni.neutron_storage import neutrons_as_npyarr, ndblsperneutron arr = neutrons_as_npyarr(neutrons) arr.shape = -1, ndblsperneutron x = arr[:,0]; y = arr[:,1]; z = arr[:,2] vx = arr[:,3]; vy = arr[:,4]; vz = arr[:,5] s1 = arr[:,6]; s2 = arr[:,7]; t = arr[:,8]; p = arr[:,9] # theta_osc = self.oscillation * np.random.rand(len(neutrons)) x1,y1,z1 = self.intersectCylinder( (z,x,y), (vz,vx,vy), (self.radius1, self.height1)) theta1 = np.arctan2(y1,x1) + theta_osc x2,y2,z2 = self.intersectCylinder( (z,x,y), (vz,vx,vy), (self.radius2, self.height2)) theta2 = np.arctan2(y2,x2) + theta_osc good = (x1==x1) \ * (z1<self.height1/2.) * (z1>-self.height1/2.) \ * (z2<self.height2/2.) * (z2>-self.height2/2.) \ * (theta1 > self.theta1) * (theta1 < self.theta2) \ * (theta2 > self.theta1) * (theta2 < self.theta2) \ * ((theta1-self.theta1)//self.dtheta == (theta2-self.theta1)//self.dtheta) good = arr[good, :] neutrons.resize(good.shape[0], neutrons[0]) neutrons.from_npyarr(good) return
def process(self, neutrons): from time import time from mcni.neutron_storage import neutrons_as_npyarr, ndblsperneutron t1 = time() neutron_array = neutrons_as_npyarr(neutrons) neutron_array.shape = -1, ndblsperneutron neutron_array_dtype_api = neutron_array.dtype neutron_array_dtype_int = self.get_numpy_floattype() needs_cast = neutron_array_dtype_api != neutron_array_dtype_int if needs_cast: neutron_array = neutron_array.astype(neutron_array_dtype_int) t2 = time() from ..config import ntotalthreads, threads_per_block self.call_process( self.__class__.process_kernel, neutron_array, ntotthreads=ntotalthreads, threads_per_block = threads_per_block, ) t3 = time() if needs_cast: neutron_array = neutron_array.astype(neutron_array_dtype_api) good = neutron_array[:, -1] > 0 neutrons.resize(int(good.sum()), neutrons[0]) neutrons.from_npyarr(neutron_array[good]) t4 = time() print(self.name, ":prepare input array: ", t2-t1) print(self.name, ":call_process: ", t3-t2) print(self.name, ":prepare output neutrons: ", t4-t3) return neutrons
def _write_neutrons(self, neutrons): # from mcni.neutron_storage import dump # dump( packet, os.path.join( self.path, filename ) ) stream = self.stream arr = neutrons_as_npyarr(neutrons) idfio.append(arr, stream=stream) return
def process(self, neutrons): if not len(neutrons): return from mcni.neutron_storage import neutrons_as_npyarr, ndblsperneutron arr = neutrons_as_npyarr(neutrons) arr.shape = -1, ndblsperneutron x = arr[:, 0] y = arr[:, 1] z = arr[:, 2] vx = arr[:, 3] vy = arr[:, 4] vz = arr[:, 5] s1 = arr[:, 6] s2 = arr[:, 7] t = arr[:, 8] p = arr[:, 9] # propagate to z = 0 self._propagateToZ0(x, y, z, vx, vy, vz, t) # Apply filter if area is positive assert self.xmax > self.xmin and self.ymax > self.ymin and self.tofmax > self.tofmin # Filter ftr = (x >= self.xmin) * (x < self.xmax) * (y >= self.ymin) * ( y < self.ymax) * (t >= self.tofmin) * (t < self.tofmax) x = x[ftr] # after filtering, there might be no neutrons left if len(x) == 0: return y = y[ftr] z = z[ftr] # vx = vx[ftr]; vy = vy[ftr]; vz = vz[ftr]; # s1 = s1[ftr]; s2 = s2[ftr]; t = t[ftr] p = p[ftr] # create empty events from mccomponents.detector import event_utils import numpy events = numpy.zeros(x.size, dtype=event_utils.datatype) # x,y dx = (self.xmax - self.xmin) / self.nx x_index = (x - self.xmin) / dx dy = (self.ymax - self.ymin) / self.ny y_index = (y - self.ymin) / dy events['pixelID'] = x_index * self.ny + y_index # t dt = (self.tofmax - self.tofmin) / self.ntof events['tofChannelNo'] = (t - self.tofmin) / dt # p events['p'] = p self.events = events return
def process(self, neutrons): if not len(neutrons): return from mcni.neutron_storage import neutrons_as_npyarr, ndblsperneutron arr = neutrons_as_npyarr(neutrons) arr.shape = -1, ndblsperneutron x = arr[:, 0] y = arr[:, 1] z = arr[:, 2] vx = arr[:, 3] vy = arr[:, 4] vz = arr[:, 5] s1 = arr[:, 6] s2 = arr[:, 7] t = arr[:, 8] p = arr[:, 9] # propagate to z = 0 self._propagateToZ0(x, y, z, vx, vy, vz, t) # Apply filter if area is positive assert self.xwidth > 0 and self.yheight > 0 # Filter ftr = (x >= -self.xwidth / 2) * (x <= self.xwidth / 2) * ( y >= -self.yheight / 2) * (y <= self.yheight / 2) x = x[ftr] y = y[ftr] z = z[ftr] vx = vx[ftr] vy = vy[ftr] vz = vz[ftr] s1 = s1[ftr] s2 = s2[ftr] t = t[ftr] p = p[ftr] # after filtering, there might be no neutrons left if len(x) == 0: return from numpy import sqrt # some expressions use 'sqrt()' function from numpy import histogramdd as hdd from mcni.utils import conversion sample = [eval(e) for e in self.expressions] bins = self.bins ranges = self.ranges self.histogram.I += hdd(sample, bins, ranges, weights=p)[0] self.histogram.E2 += hdd(sample, bins, ranges, weights=p * p)[0] return
def __call__(self, neutrons, context=None): if context: context.identify(self) from mcni.neutron_storage import neutrons_as_npyarr a = neutrons_as_npyarr(neutrons) a.shape = -1, 10 r = a[:, :3] v = a[:, 3:6] p = a[:, -1] self._store.append(_N(r, v, p)) sys.stdout.write(".") sys.stdout.flush() return
def process(self, neutrons): if not len(neutrons): return from mcni.neutron_storage import neutrons_as_npyarr, ndblsperneutron arr = neutrons_as_npyarr(neutrons) arr.shape = -1, ndblsperneutron x = arr[:,0]; y = arr[:,1]; z = arr[:,2] vx = arr[:,3]; vy = arr[:,4]; vz = arr[:,5] s1 = arr[:,6]; s2 = arr[:,7]; t = arr[:,8]; p = arr[:,9] # propagate to z = 0 self._propagateToZ0(x,y,z,vx,vy,vz,t) # Apply filter if area is positive assert self.xmax > self.xmin and self.ymax > self.ymin and self.tofmax > self.tofmin # Filter ftr = (x >= self.xmin)*(x < self.xmax)*(y >= self.ymin)*(y < self.ymax)*(t >= self.tofmin)*(t<self.tofmax) x = x[ftr] # after filtering, there might be no neutrons left if len(x) == 0: return y = y[ftr]; z = z[ftr]; # vx = vx[ftr]; vy = vy[ftr]; vz = vz[ftr]; # s1 = s1[ftr]; s2 = s2[ftr]; t = t[ftr]; p = p[ftr]; # create empty events from mccomponents.detector import event_utils import numpy events = numpy.zeros(x.size, dtype=event_utils.datatype) # x,y dx = (self.xmax-self.xmin)/self.nx x_index = (x-self.xmin)/dx dy = (self.ymax-self.ymin)/self.ny y_index = (y-self.ymin)/dy events['pixelID'] = x_index * self.ny + y_index # t dt = (self.tofmax-self.tofmin)/self.ntof events['tofChannelNo'] = (t-self.tofmin)/dt # p events['p'] = p self.events = events return
def test(neutron_fn=DEFAULT_NEUTRON_FILE, niter=1): # load file and store copy to avoid reloading for multiple iterations from mcni.neutron_storage import load, neutrons_from_npyarr, \ neutrons_as_npyarr, ndblsperneutron neutrons_orig = load(neutron_fn) neutrons_orig = neutrons_as_npyarr(neutrons_orig) neutrons_orig.shape = -1, ndblsperneutron from mcvine.acc.components.optics import guide_tapering g = guide_tapering.Guide( name='guide', option="file={}".format(guide11_dat), l=guide11_len, mx=guide11_mx, my=guide11_my, ) times = [] for i in range(niter): neutrons = neutrons_from_npyarr(neutrons_orig) t1 = time.time_ns() g.process(neutrons) delta = time.time_ns() - t1 times.append(delta) print("GPU processing time: {} ms ({} s)".format( 1e-6 * delta, 1e-9 * delta)) if niter > 1: # report average time over niter times = np.asarray(times) avg = times.sum() / len(times) print("--------") print("Average GPU time ({} iters): {} ms ({} s)".format( niter, 1e-6 * avg, 1e-9 * avg)) print("--------") neutrons = neutrons_from_npyarr(neutrons_orig) import mcvine.components as mc g = mc.optics.Guide_tapering( name='guide', option="file={}".format(guide11_dat), l=guide11_len, mx=guide11_mx, my=guide11_my, ) t1 = time.time() g.process(neutrons) print("CPU processing time:", time.time() - t1) return
def process(self, neutrons): # input neutron is buffer if not len(neutrons): return # Number of doubles per neutrons thats means each neutron is represented # by x, y, z, vx, vy, vz, s1, s2, t, t0, p (10 double variables) arr = neutrons_as_npyarr(neutrons) arr.shape = -1, ndblsperneutron x = arr[:, 0]; y = arr[:, 1]; z = arr[:, 2] vx = arr[:, 3]; vy = arr[:, 4]; vz = arr[:, 5] t = arr[:, 8]; t0 = t.copy() p = arr[:, 9] # Propagate to y = 0 self._propagateToY0(x, y, z, vx, vy, vz, t) # Apply filter if area is positive assert self.xwidth > 0 and self.zheight > 0 # Filter do_filter = True ftr = (x >= -self.xwidth / 2) * (x <= self.xwidth / 2) * (y >= -self.zheight / 2) * (y <= self.zheight / 2) * (t > t0) # Reflection speed = np.sqrt(vx**2+vy**2+vz**2) if do_filter: vy[ftr] *= -1 #q = 2.0*conversion.V2K*speed[ftr] * vy[ftr]/vz[ftr] q = 2.0*conversion.V2K*vy[ftr] p[ftr] *= self.reflectivity(self.rq, q) else: vy *= -1 #q = 2.0*conversion.V2K*speed * vy/vz q = 2.0*conversion.V2K*vy p *= self.reflectivity(self.rq, q) if DEBUG: for i in range(len(arr)): self.print_neutron(arr[i], q[i]) neutrons.from_npyarr(arr) return neutrons
def process(self, neutrons): if not len(neutrons): return from mcni.neutron_storage import neutrons_as_npyarr, ndblsperneutron arr = neutrons_as_npyarr(neutrons) arr.shape = -1, ndblsperneutron x = arr[:,0]; y = arr[:,1]; z = arr[:,2] vx = arr[:,3]; vy = arr[:,4]; vz = arr[:,5] s1 = arr[:,6]; s2 = arr[:,7]; t = arr[:,8]; p = arr[:,9] # propagate to z = 0 self._propagateToZ0(x,y,z,vx,vy,vz,t) # Apply filter if area is positive assert self.xwidth > 0 and self.yheight > 0 # Filter ftr = (x >= -self.xwidth/2)*(x <= self.xwidth/2)*(y >= -self.yheight/2)*(y <= self.yheight/2) x = x[ftr]; y = y[ftr]; z = z[ftr]; vx = vx[ftr]; vy = vy[ftr]; vz = vz[ftr]; s1 = s1[ftr]; s2 = s2[ftr]; t = t[ftr]; p = p[ftr]; # after filtering, there might be no neutrons left if len(x) == 0: return from numpy import sqrt # some expressions use 'sqrt()' function from numpy import histogramdd as hdd from mcni.utils import conversion sample = [eval(e) for e in self.expressions] bins = self.bins ranges = self.ranges self.histogram.I += hdd(sample, bins, ranges, weights=p)[0] self.histogram.E2 += hdd(sample, bins, ranges, weights=p*p)[0] return
def process(self, neutrons): """ Propagate a buffer of particles through this guide. Adjusts the buffer to include only the particles that exit, at the moment of exit. Parameters: neutrons: a buffer containing the particles """ t1 = time.time() neutron_array = neutrons_as_npyarr(neutrons) neutron_array.shape = -1, ndblsperneutron t2 = time.time() call_process(*self._params, neutron_array) t3 = time.time() good = neutron_array[:, -1]>0 neutrons.resize(int(good.sum()), neutrons[0]) neutrons.from_npyarr(neutron_array[good]) t4 = time.time() print("prepare input array: ", t2-t1) print("call_process: ", t3-t2) print("prepare output neutrons: ", t4-t3) return neutrons
def do_process(guide, neutrons): """ Testing helper function to run a neutron through the guide and return the result as a numpy array Parameters ---------- guide : instance of a Guide neutrons : a NeutronEvent or a list of NeutronEvents Returns ------- Numpy array containing: [x, y, z, vx, vy, vz, s1, s2, t, p] for each input in neutrons """ from mcni.mcnibp import NeutronEvent assert isinstance(guide, Guide) buffer = neutron_buffer(1) if isinstance(neutrons, list): buffer.resize(len(neutrons), neutron()) for i in range(len(neutrons)): buffer[i] = neutrons[i] elif isinstance(neutrons, NeutronEvent): buffer[0] = neutrons else: raise RuntimeError( "Expected a NeutronEvent or a list of NeutronEvents") guide.process(buffer) result = neutrons_as_npyarr(buffer) result.shape = -1, ndblsperneutron if result.shape[0] == 1: # return only a single dim array to make test comparisons easier result = result[0] return result
def process(self, neutrons): if not len(neutrons): return from mcni.neutron_storage import neutrons_as_npyarr, ndblsperneutron arr = neutrons_as_npyarr(neutrons) arr.shape = -1, ndblsperneutron x = arr[:, 0] y = arr[:, 1] z = arr[:, 2] vx = arr[:, 3] vy = arr[:, 4] vz = arr[:, 5] s1 = arr[:, 6] s2 = arr[:, 7] t = arr[:, 8] p = arr[:, 9] # theta_osc = self.oscillation * np.random.rand(len(neutrons)) x1, y1, z1 = self.intersectCylinder((z, x, y), (vz, vx, vy), (self.radius1, self.height1)) theta1 = np.arctan2(y1, x1) + theta_osc x2, y2, z2 = self.intersectCylinder((z, x, y), (vz, vx, vy), (self.radius2, self.height2)) theta2 = np.arctan2(y2, x2) + theta_osc good = (x1==x1) \ * (z1<self.height1/2.) * (z1>-self.height1/2.) \ * (z2<self.height2/2.) * (z2>-self.height2/2.) \ * (theta1 > self.theta1) * (theta1 < self.theta2) \ * (theta2 > self.theta1) * (theta2 < self.theta2) \ * ((theta1-self.theta1)//self.dtheta == (theta2-self.theta1)//self.dtheta) good = arr[good, :] neutrons.resize(good.shape[0], neutrons[0]) neutrons.from_npyarr(good) return
def process(self, neutrons): if not len(neutrons): return arr = neutrons_as_npyarr(neutrons) arr.shape = -1, ndblsperneutron # Filter out neutrons that do not hit guide entrance entrance_intersection, entrance_dur = \ self.entrance.intersection_duration(arr[:, 0:3], arr[:, 3:6]) mask = ((entrance_intersection[:, 0] < self.entrance_width / 2) & (entrance_intersection[:, 0] > -self.entrance_width / 2) & (entrance_intersection[:, 1] < self.entrance_height / 2) & (entrance_intersection[:, 1] > -self.entrance_height / 2) & ((entrance_dur.flatten() > 1e-10) | numpy.isclose(arr[:, 2], 0.0))).flatten() arr = arr[mask] entrance_dur = entrance_dur[mask] neutrons.from_npyarr(arr) if not len(neutrons): return position = arr[:, 0:3] # x, y, z velocity = arr[:, 3:6] # vx, vy, vz time = arr[:, 8].reshape((arr.shape[0], 1)) prob = arr[:, 9].reshape((arr.shape[0], 1)) # initialize arrays containing neutron duration and side index side = numpy.full((arr.shape[0], 1), -2, dtype=int) old_side = side.copy() new_duration = numpy.full((arr.shape[0], 1), numpy.inf) # propagate to the guide entrance plane position += numpy.multiply(velocity, entrance_dur) time += entrance_dur # Iterate until all neutrons hit end of guide or are absorbed iter = 0 while numpy.count_nonzero(side == 0) + numpy.count_nonzero( side == -1) != len(neutrons): duration = numpy.full((arr.shape[0], 1), numpy.inf) # Calculate minimum intersection time with all sides of the guide for s in range(0, len(self.sides)): intersection = self.sides[s].intersection_duration(position, velocity) new_duration = numpy.minimum(intersection[1], duration, where=((intersection[1] > 1e-10) & (s != old_side) & (old_side != 0) & (old_side != -1)), out=new_duration) # Update the index of which side was hit based on new minimum side = numpy.where(new_duration != duration, s, side) duration = new_duration.copy() # If duration is inf, mark the side as invalid side = numpy.where(duration == numpy.inf, -1, side) # Propagate the neutrons based on the minimum times mask = (old_side != side).flatten() position[mask] += velocity[mask, :] * duration[mask] time[mask] += duration[mask] velocity_before = velocity.copy() # Update the velocity due to reflection mask = numpy.logical_and(old_side != side, side > 0) for s in range(1, len(self.sides)): # Only update the velocity if reflecting on one of the guide sides side_mask = numpy.logical_and(mask, side == s).flatten() velocity[side_mask] = self.sides[s].reflect(velocity[side_mask]) # Calculate reflectivity mask = mask.flatten() reflectivity = self.calc_reflectivity(velocity_before[mask, :], velocity[mask, :]) prob[mask] = prob[mask] * reflectivity.reshape( reflectivity.shape[0], 1) side[prob <= 0] = -1 old_side = side.copy() iter += 1 print("process took {} iterations".format(iter)) # Update neutron positions, velocities and times and select those that hit the guide exit arr[:, 0:3] = position arr[:, 3:6] = velocity arr[:, 8] = time.reshape((arr.shape[0],)) arr[:, 9] = prob.reshape((arr.shape[0],)) good = arr[(side == 0).flatten(), :] neutrons.resize(good.shape[0], neutrons[0]) neutrons.from_npyarr(good)
def NEB_tonpyarr(self): from mcni.neutron_storage import neutrons_as_npyarr, ndblsperneutron arr = neutrons_as_npyarr(self) arr.shape = -1, ndblsperneutron return arr
def _write_header(self, stream): # create header by writing empty neutron buffer buffer = mcni.neutron_buffer(0) arr = neutrons_as_npyarr(buffer) idfio.write(arr, stream=stream) return