def get(cls, cachedir): if os.path.isdir(cachedir): log.info("load chroma_geometry from %s " % cachedir) from chroma.loader import load_bvh instance = cls.load_instance(cachedir) instance.bvh = load_bvh(instance) else: instance = None pass return instance
def add_bvh(self, bvh_name="default", auto_build_bvh=True, read_bvh_cache=True, update_bvh_cache=True, cache_dir=None, cuda_device=None): """ As done by chroma.loader """ log.debug("ColladaToChroma adding BVH") self.chroma_geometry.bvh = load_bvh(self.chroma_geometry, bvh_name=bvh_name, auto_build_bvh=auto_build_bvh, read_bvh_cache=read_bvh_cache, update_bvh_cache=update_bvh_cache, cache_dir=cache_dir, cuda_device=cuda_device) log.debug("completed adding BVH")
def driver_funct(configname): from chroma.loader import load_bvh # Requires CUDA so only import it when necessary kabamland = Detector(lm.create_scintillation_material()) config = detectorconfig.configdict(configname) #get_lens_triangle_centers(vtx, rad_assembly, config.diameter_ratio, config.thickness_ratio, config.half_EPD, config.blockers, blocker_thickness_ratio=config.blocker_thickness_ratio, light_confinement=config.light_confinement, focal_length=config.focal_length, lens_system_name=config.lens_system_name) #print get_curved_surf_triangle_centers(config.vtx, config.half_EPD/config.EPD_ratio, config.detector_r, config.focal_length, config.nsteps, config.b_pixel)[0] build_lens_icosahedron( kabamland, config.vtx, config.half_EPD / config.EPD_ratio, config.diameter_ratio, config.thickness_ratio, config.half_EPD, config.blockers, blocker_thickness_ratio=config.blocker_thickness_ratio, light_confinement=config.light_confinement, focal_length=config.focal_length, lens_system_name=config.lens_system_name) #build_curvedsurface_icosahedron(kabamland, config.vtx, config.half_EPD/config.EPD_ratio, config.diameter_ratio, focal_length=config.focal_length, detector_r=config.detector_r, nsteps=config.nsteps, b_pxl=config.b_pixel) #build_pmt_icosahedron(kabamland, np.linalg.norm(config.vtx[0]), focal_length=config.focal_length) kabamland.flatten() kabamland.bvh = load_bvh(kabamland)
from chroma import make, view from chroma.sim import Simulation from chroma.sample import uniform_sphere from chroma.event import Photons from chroma.loader import load_bvh from chroma.generator import vertex from chroma.camera import Camera import matplotlib.pyplot as plt import sys from geometry_cylinder import build_detector g = build_detector() g.flatten() g.bvh = load_bvh(g) #view(g) ys.exit() sim = Simulation(g) n=1 gun = vertex.particle_gun(['mu-']*n, vertex.constant((0,10000,10000)), vertex.constant([1,0,-1]), vertex.constant(1000), vertex.constant(0)) i = 0 for ev in sim.simulate(gun,keep_detected_photons=True,
def load_or_build_detector(config, detector_material, g4_detector_parameters, force_build=False): configname = config.config_name filename_base = paths.detector_config_path + configname if not os.path.exists(paths.detector_config_path): os.makedirs(paths.detector_config_path) kabamland = None # How to ensure the material and detector parameters are correct?? if not force_build: try: detector_config = dd.io.load(filename_base + '.h5') kabamland = detector_config['detector'] logger.info("** Loaded HDF5 (deepdish) detector configuration: " + configname) except IOError as error: # Will dd throw an exception? try: with open(filename_base + '.pickle', 'rb') as pickle_file: kabamland = pickle.load(pickle_file) logger.info("** Loaded pickle detector configuration: " + configname) except IOError as error: pass if kabamland is not None: config_has_g4_dp = hasattr( kabamland, 'g4_detector_parameters' ) and kabamland.g4_detector_parameters is not None config_has_g4_dm = hasattr( kabamland, 'detector_material') and kabamland.detector_material is not None if g4_detector_parameters is not None: logger.info('*** Using Geant4 detector parameters specified' + (' - replacement' if config_has_g4_dp else '') + ' ***') kabamland.g4_detector_parameters = g4_detector_parameters elif config_has_g4_dp: logger.info( '*** Using Geant4 detector parameters found in loaded file ***' ) else: logger.info('*** No Geant4 detector parameters found at all ***') if detector_material is not None: logger.info('*** Using Geant4 detector material specified' + (' - replacement' if config_has_g4_dm else '') + ' ***') kabamland.detector_material = detector_material elif config_has_g4_dm: logger.info( '*** Using Geant4 detector material found in loaded file ***' ) else: logger.info('*** No Geant4 detector material found at all ***') else: from chroma.loader import load_bvh # Requires CUDA so only import it when necessary logger.info("** Building detector configuration: " + configname) kabamland = Detector(lm.create_scintillation_material(), g4_detector_parameters=g4_detector_parameters) kbl2.build_kabamland(kabamland, config) # view(kabamland) kabamland.flatten() kabamland.bvh = load_bvh(kabamland, bvh_name=config.config_name, read_bvh_cache=(not force_build)) ''' try: with open(filename_base+'.pickle','wb') as pickle_file: pickle.dump(kabamland, pickle_file) except IOError as error: logger.info("Error writing pickle file: " + filename_base+'.pickle') ''' # Write h5 file with configuration data structure logger.info('Saving h5 detector configuration. UUID: %s' % config.uuid) ''' # This was created to minimize what is saved from the Detector object. But for simplicity, we are currently pickling the whole object. detector_dict = { 'detector_material' : kabamland.detector_material, 'solids' : kabamland.solids, 'solid_rotations' : kabamland.solid_rotations, 'solid_displacements' : kabamland.solid_displacements, 'bvh' : kabamland.bvh, 'g4_detector_parameters' : kabamland.g4_detector_parameters, 'solid_id_to_channel_index' : kabamland.solid_id_to_channel_index, 'channel_index_to_solid_id' : kabamland.channel_index_to_solid_id, 'channel_index_to_channel_id' : kabamland.channel_index_to_channel_id, 'channel_id_to_channel_index' : kabamland.channel_id_to_channel_index, 'time_cdf' : kabamland.time_cdf, 'charge_cdf' : kabamland.charge_cdf } ''' # TODO: Saving the whole dict and the object is redundant # TODO: Also, saving all of kabamland vs. just the parameters above adds about 1 Meg to the file size (I think) import lenssystem ld_name = configname.split('_')[0][2:] lens_design = lenssystem.get_lens_sys(ld_name) config_data = { 'detector_config': config, 'detector_config_dict': vars(config), 'lens_config_dict': vars(lens_design) } detector_data = {'config': config_data, 'detector': kabamland} dd.io.save(filename_base + '.h5', detector_data) return kabamland
def main(n, wavelength, width, beamsize, regen=False): config_path = open('config/vars.txt', 'rb') test = config_path.readline() config_path.close() if not (abs(float(test) - width) < 0.1 / 25400): regen = True if os.path.exists('config/geometry.pickle') and regen == False: geometry_path = open('config/geometry.pickle', 'rb') world = cPickle.load(geometry_path) geometry_path.close() else: world = build(width) world.flatten() world.bvh = load_bvh(world) #Create bounding volume hierarchy sim = Simulation(world) def init_source(n, wavelength, width, beamsize): """Generates laser profile of n photons, with wavelength, emanating from position pos_offset with direction 'direction'.""" pos, direction = mfunctions.get_source(n, width, beamsize, wavelength / 25400000.0) #Note: Chroma only natively handles integer wavelengths, so we convert to inches here instead of earlier in the code. source_center = mfunctions.get_center('161') + np.array( (0, -0.1, 0)) #Position source just in front of slits pos = pos + np.tile(source_center, (n, 1)) pol = np.cross(direction, (0, 0, 1)) #Polarisation wavelengths = np.repeat(wavelength, n) return Photons(pos, direction, pol, wavelengths) start = [] end = [] print 'Simulating photons...' for ev in sim.simulate([init_source(n, wavelength, width, beamsize)], keep_photons_beg=True, keep_photons_end=True, run_daq=False, max_steps=100): #print ev.photons_end.flags start.append(ev.photons_beg.pos) end.append(ev.photons_end.pos) print 'Saving data to file...' photon_id = list(range(n)) flags = ev.photons_end.flags wavs = ev.photons_end.wavelengths ##### Saving data to file ##### current = dt.datetime.now() filename = 'results/' + current.strftime( '%Y-%m-%d_%H:%M') + '_%d:%d:%.2f:%.2f.dat' % (n, wavelength, width * 25400, beamsize * 25400) out_file = open(filename, 'w') out_file.write('\t'.join([ 'ID', 'xi', 'yi', 'zi', 'xf', 'yf', 'zf', 'wavelength (nm)', 'flag\n' ])) for i in range(n): output = [photon_id[i]] + [item for item in start[0][i]] + [ item for item in end[0][i] ] + [int(wavs[i]), flags[i]] out_file.write('\t'.join([str(item) for item in output]) + '\n') out_file.close() print 'Generating seed file...' seed = np.random.uniform( size=n) #This is the seed file for the analysis script np.savetxt('config/seed.dat', seed, delimiter=',') print 'Done.'
photon_track[i, :, 0] = photons.pos[:, 0] photon_track[i, :, 1] = photons.pos[:, 1] photon_track[i, :, 2] = photons.pos[:, 2] return photons, photon_track if __name__ == '__main__': config = "cfJiani3_2" #config = "cfSam1_1" kabamland = Detector(lm.ls) lens, surf = build_kabamland(kabamland, config) kabamland.flatten() kabamland.bvh = load_bvh(kabamland) #view(kabamland) #quit() sim = Simulation(kabamland, geant4_processes=0) runs = 1 numPhotons = 6 events, pos = photon_angle(rep=numPhotons) nr_hits = np.zeros((runs)) doRandom = getRandom() for ii in range(runs): photons, photon_track = propagate_photon(events, numPhotons, 20, kabamland, doRandom[0], doRandom[1], doRandom[2]) detected = (photons.flags & (0x1 << 2)).astype(bool) nr_hits[ii] = len(photons.pos[detected]) print " Number of photons detected ", nr_hits[ii]
def __init__(self, daefile, acrylic_detect=True, acrylic_wls=False, bvh_name="uboone_bvh_default", detector_volumes=[], wireplane_volumes=[], auto_build_bvh=True, read_bvh_cache=True, calculate_ndsar_tree=False, update_bvh_cache=True, cache_dir=None, bvh_method='grid', bvh_target_degree='3', cuda_device=None, cl_device=None, dump_node_info=False): if acrylic_detect and acrylic_wls: raise ValueError( 'cannot have acrylic act as both detector and wavelength shifter' ) # run constructor of base class if acrylic_detect: super(ubooneDet, self).__init__("Acrylic") elif acrylic_wls: super(ubooneDet, self).__init__("bialkali") else: print "Warning: no detector material specified" self.acrylic_detect = acrylic_detect self.acrylic_wls = acrylic_wls if len(detector_volumes) == 0: raise ValueError("No detector volumes specified!") # We use g4dae tools to create geometry with mesh whose triangles have materials assigned to them DAENode.parse(daefile, sens_mats=[]) self.collada2chroma = ColladaToChroma(DAENode, dump_node_info=False) geom = self.collada2chroma.convert_geometry_partial() # Look for wireplane alogorithms if len(wireplane_volumes) > 0: wireplaneset = map(lambda x: x[0], wireplane_volumes) for n, solid in enumerate(geom.solids): node = solid.node if node.pv.id in wireplaneset: for wireplane in wireplane_volumes: if wireplane[0] == node.pv.id: wireplane[1](solid) print "Found Solids to add wireplanes: ", len(wireplaneset) geom = self.collada2chroma.finish_converting_geometry() if dump_node_info: for n, solid in enumerate(geom.solids): node = solid.node mesh = solid.mesh material2names = map(lambda x: x.name, np.unique(solid.material2)) material1names = map(lambda x: x.name, np.unique(solid.material1)) surfaces = map( lambda x: x.name, filter(lambda x: x != None, solid.unique_surfaces)) print "[SOLID %d, NODE %05d:%s,%s]" % ( n, node.index, node.pv.id, node.lv.id ), " NTriangles=%d OuterMat=%s InnerMat=%s Surface=%s" % (len( mesh.triangles), material2names, material1names, surfaces) # copy member objects (maybe use copy module instead?) self.mesh = geom.mesh self.colors = geom.colors self.solids = geom.solids self.solid_id = geom.solid_id self.unique_materials = geom.unique_materials self.material1_index = geom.material1_index self.material2_index = geom.material2_index material_lookup = dict( zip(self.unique_materials, range(len(self.unique_materials)))) # Next we need to go through all the triangles and make sure they have the right surfaces attached to them # We use the material lists to loop over all triangles self.unique_surfaces = [] surface_index_dict = {} surface_indices = [] for id, mats in enumerate( zip(self.material1_index, self.material2_index)): existing_surface = geom.surface_index[id] if existing_surface != -1: print "Triangle %d already has specified surface: " % ( id), geom.unique_surfaces[existing_surface] surface = geom.unique_surfaces[existing_surface] else: surface = uboonesurfaces.get_boundary_surface( self.unique_materials[mats[0]].name, self.unique_materials[mats[1]].name) if surface == None: surface_indices.append(-1) else: if surface not in self.unique_surfaces: self.unique_surfaces.append(surface) surface_index_dict[surface] = self.unique_surfaces.index( surface) surface_indices.append(surface_index_dict[surface]) self.surface_index = np.array(surface_indices, dtype=np.int) print "number of surface indicies: ", len(self.surface_index) # Finally, setup channels self._setup_channels(acrylic_detect, detector_volumes) self._setup_photodetectors() if self.bvh is None: self.bvh = load_bvh(self, auto_build_bvh=auto_build_bvh, read_bvh_cache=read_bvh_cache, update_bvh_cache=update_bvh_cache, cache_dir=cache_dir, bvh_method=bvh_method, target_degree=bvh_target_degree, cuda_device=cuda_device, cl_device=cl_device) if calculate_ndsar_tree: # This tree helps with the navigation of the node tree (deprecated) print "Calculate node DSAR tree ...", sndsar = time.time() self.node_dsar_tree = NodeDSARtree(self.bvh) endsar = time.time() print " done ", endsar - sndsar, " secs."
g.add_solid(world) return g if __name__ == '__main__': from chroma.sim import Simulation from chroma.sample import uniform_sphere from chroma.event import Photons from chroma.loader import load_bvh from chroma.generator import vertex import matplotlib.pyplot as plt g = build_detector() g.flatten() g.bvh = load_bvh(g) sim = Simulation(g) # photon bomb from center def photon_bomb(n, wavelength, pos): pos = np.tile(pos, (n, 1)) dir = uniform_sphere(n) pol = np.cross(dir, uniform_sphere(n)) wavelengths = np.repeat(wavelength, n) return Photons(pos, dir, pol, wavelengths) # write it to a root file from chroma.io.root import RootWriter f = RootWriter('test.root')
def __init__(self, name, daefile, bvh_name="bvh_default", auto_build_bvh=True, read_bvh_cache=True, update_bvh_cache=True, cache_dir=None, bvh_method='grid', bvh_target_degree='3', cuda_device=None, cl_device=None, dump_node_info=False): super(UserVG4DEAGeo, self).__init__() # save data members self.Name = name self.daefile = os.path.basename(daefile) # setup geometry cache # We use g4dae tools to create geometry with mesh whose triangles have materials assigned to them DAENode.parse(daefile, sens_mats=[]) self.collada2chroma = ColladaToChroma(DAENode, dump_node_info=False) geom = self.collada2chroma.convert_geometry_partial() # Apply wireplane alogorith if len(self.wireplanevolumes()) > 0: nwireplanes = 0 for n, solid in enumerate(geom.solids): node = solid.node name = node.pv.id.split("0x")[0] if name in self.wireplanevolumes(): ok = self.setaswireplane(name, solid) if ok: nwireplanes += 1 print "Number of solids with wireplane surface: ", nwireplanes # Finish Geometry geom = self.collada2chroma.finish_converting_geometry() self.mesh = geom.mesh self.colors = geom.colors self.solids = geom.solids self.solid_id = geom.solid_id self.unique_materials = geom.unique_materials self.material1_index = geom.material1_index self.material2_index = geom.material2_index print "Materials: ", len(self.material1_index), len( self.material2_index) # Next we need to go through all the triangles and make sure they have the right surfaces attached to them # We use the material lists to generate pairs of materials to that require a surface # Note material index list is over all triangles already # Then we make a list of surfaces self.user_surfaces_dict = self.surfacesdict() self.unique_surfaces = [] surface_index_dict = {None: -1} surface_index_list = [] for id, mats in enumerate( zip(self.material1_index, self.material2_index)): surface = None if self.unique_materials[mats[0]].name != self.unique_materials[ mats[1]].name: existing_surface = geom.surface_index[id] if existing_surface != -1: print "Triangle %d already has specified surface: " % ( id), geom.unique_surfaces[existing_surface] surface = geom.unique_surfaces[existing_surface] else: mat1 = self.unique_materials[mats[0]].name.split("0x")[0] mat2 = self.unique_materials[mats[1]].name.split("0x")[0] if (mat1, mat2) in self.user_surfaces_dict: surface = self.user_surfaces_dict[(mat1, mat2)] elif (mat2, mat1) in self.user_surfaces_dict: surface = self.user_surfaces_dict[(mat2, mat1)] else: raise RuntimeError( "Could not assign a surface between materials %s and %s. Must provide through sufacesdict(self) method." % (mat1, mat2)) else: if geom.surface_index[id] != -1: print "Triangle %d already has specified surface: " % ( id), geom.unique_surfaces[existing_surface] surface = geom.unique_surfaces[existing_surface] else: surface = None if surface is not None and surface not in self.unique_surfaces: self.unique_surfaces.append(surface) surface_index_dict[surface] = self.unique_surfaces.index( surface) print "Registering new surface: [%d] %s" % ( surface_index_dict[surface], surface.name) surface_index_list.append(surface_index_dict[surface]) print "number of unique surfaces: ", len(self.unique_surfaces) print self.unique_surfaces self.surface_index = np.array(surface_index_list, dtype=np.int32) # Setup the channels self._setup_channels() # Setup the BVH if self.bvh is None: self.bvh = load_bvh(self, auto_build_bvh=auto_build_bvh, read_bvh_cache=read_bvh_cache, update_bvh_cache=update_bvh_cache, cache_dir=cache_dir, bvh_method=bvh_method, target_degree=bvh_target_degree, cuda_device=cuda_device, cl_device=cl_device)
def __init__(self, daefile, acrylic_detect=True, acrylic_wls=False, bvh_name="bvh_default", detector_volumes=[], wireplane_volumes=[], auto_build_bvh=True, read_bvh_cache=True, calculate_ndsar_tree=False, update_bvh_cache=True, cache_dir=None, bvh_method='grid', bvh_target_degree='3', cuda_device=None, cl_device=None, dump_node_info=False ): """ Loads a geometry for Chroma built using the COLLADA file exported by G4DAE. Parameters ---------- daefile : str string with path to COLLADA file acrylic_detect : bool hacky way to specify detector behavior. needs to be removed acrylic_wls : bool hacky way to specify that acrylic material should wavelength shift. needs to be removed bvh_name : string specifies name of BVH cache written to working directory detector_volumes : list of str logical volume names that will be marked as a sensitive detectors wireplane_volumes : list of (str,function) tuples If a Solid with an associated physical volume whose name that matches 'str', we give the function the Solid instance. The intention is for the user to provide one or more of the triangles in the Solid with a wireplane surface. For an example see: XXX auto_build_bvh : bool read_bvh_cache : bool update_bvh_cache : bool cache_dir : str bvh_method : str bvh_target_degree : str of number cuda_device : pycuda device instance build and store geometry on specified CUDA device cl_device : pyopencl device instance build and store geometry on specified OpenCL device calculate_ndsar_tree : bool after geometry specified, traverse BVH and build ropes. deprecated and will likely be removed dump_node_info : bool if true, will list all of the nodes in the geometry Returns ------- instance of object Raises ------ ValueError if both acrylic_detect and acrylic_wls are True. Need to remove. ValueError when no detector volumes are specified. likely will be removed. """ if acrylic_detect and acrylic_wls: raise ValueError('cannot have acrylic act as both detector and wavelength shifter') # run constructor of base class if acrylic_detect: super( ubooneDet, self ).__init__( "Acrylic" ) elif acrylic_wls: super( ubooneDet, self ).__init__( "bialkali" ) else: print "Warning: no detector material specified" self.acrylic_detect = acrylic_detect self.acrylic_wls = acrylic_wls if len( detector_volumes )==0: raise ValueError( "No detector volumes specified!" ) # We use g4dae tools to create geometry with mesh whose triangles have materials assigned to them DAENode.parse( daefile, sens_mats=[] ) self.collada2chroma = ColladaToChroma( DAENode, dump_node_info=False ) geom = self.collada2chroma.convert_geometry_partial() # Look for wireplane alogorithms if len(wireplane_volumes)>0: wireplaneset = map( lambda x: x[0], wireplane_volumes ) for n,solid in enumerate(geom.solids): node = solid.node if node.pv.id in wireplaneset: for wireplane in wireplane_volumes: if wireplane[0]==node.pv.id: wireplane[1]( solid ) print "Found Solids to add wireplanes: ",len(wireplaneset) geom = self.collada2chroma.finish_converting_geometry() if dump_node_info: for n,solid in enumerate(geom.solids): node = solid.node mesh = solid.mesh material2names = map( lambda x: x.name, np.unique(solid.material2) ) material1names = map( lambda x: x.name, np.unique(solid.material1) ) surfaces = map( lambda x: x.name, filter( lambda x: x!=None, solid.unique_surfaces ) ) print "[SOLID %d, NODE %05d:%s,%s]"%(n, node.index,node.pv.id,node.lv.id)," NTriangles=%d OuterMat=%s InnerMat=%s Surface=%s"%(len(mesh.triangles), material2names, material1names,surfaces) # copy member objects (maybe use copy module instead?) self.mesh = geom.mesh self.colors = geom.colors self.solids = geom.solids self.solid_id = geom.solid_id self.unique_materials = geom.unique_materials self.material1_index = geom.material1_index self.material2_index = geom.material2_index material_lookup = dict(zip(self.unique_materials, range(len(self.unique_materials)))) # Next we need to go through all the triangles and make sure they have the right surfaces attached to them # We use the material lists to loop over all triangles self.unique_surfaces = [] surface_index_dict = {} surface_indices = [] for id, mats in enumerate( zip(self.material1_index, self.material2_index) ): existing_surface = geom.surface_index[ id ] if existing_surface!=-1: print "Triangle %d already has specified surface: "%(id),geom.unique_surfaces[ existing_surface ] surface = geom.unique_surfaces[ existing_surface ] else: surface = uboonesurfaces.get_boundary_surface( self.unique_materials[mats[0]].name, self.unique_materials[mats[1]].name ) if surface==None: surface_indices.append( -1 ) else: if surface not in self.unique_surfaces: self.unique_surfaces.append( surface ) surface_index_dict[ surface ] = self.unique_surfaces.index( surface ) surface_indices.append( surface_index_dict[ surface ] ) self.surface_index = np.array( surface_indices, dtype=np.int ) print "number of surface indicies: ",len(self.surface_index) # Finally, setup channels print "SETUP UBOONE CHANNELS from solids list (",len(self.solids)," solids)" self.solid_id_to_channel_index.resize( len(self.solids) ) self.solid_id_to_channel_index.fill(-1) # default no channels self.solid_id_to_channel_id.resize( len(self.solids) ) self.solid_id_to_channel_id.fill(-1) print len( self.solid_id_to_channel_index ), len( self.solid_id_to_channel_id ) # prevous calls to add_solid by collada_to_chroma sized this array for n,solid in enumerate(self.solids): if acrylic_detect and any( volnames in solid.node.lv.id for volnames in detector_volumes ): solid_id = n channel_index = len(self.channel_index_to_solid_id) channel_id = channel_index # later can do more fancy channel indexing/labeling self.solid_id_to_channel_index[solid_id] = channel_index self.solid_id_to_channel_id[solid_id] = channel_id # resize channel_index arrays before filling self.channel_index_to_solid_id.resize(channel_index+1) self.channel_index_to_solid_id[channel_index] = solid_id self.channel_index_to_channel_id.resize(channel_index+1) self.channel_index_to_channel_id[channel_index] = channel_id # dictionary does not need resizing self.channel_id_to_channel_index[channel_id] = channel_index print "Number of Channels Added: ",len(self.channel_index_to_solid_id) if self.bvh is None: self.bvh = load_bvh(self, auto_build_bvh=auto_build_bvh, read_bvh_cache=read_bvh_cache, update_bvh_cache=update_bvh_cache, cache_dir=cache_dir, bvh_method=bvh_method, target_degree=bvh_target_degree, cuda_device=cuda_device, cl_device=cl_device) self._setup_photodetectors() if calculate_ndsar_tree: # This tree helps with the navigation of the node tree (deprecated) print "Calculate node DSAR tree ...", sndsar = time.time() self.node_dsar_tree = NodeDSARtree( self.bvh ) endsar = time.time() print " done ",endsar-sndsar," secs."