def testBulkReemission(self): '''Test bulk reemission Start a bunch of monoenergetic photons at the center of a wavelength- shifting sphere, forcing reemission, and check that the final wavelength distribution matches the wls spectrum. ''' import scipy.stats nphotons = 1e5 # set up detector -- a sphere of 'scintillator' surrounded by a # detecting sphere scint = Material('scint') scint.set('refractive_index', 1) scint.set('absorption_length', 1.0) scint.set('scattering_length', 1e7) scint.set('reemission_prob', 1) x = np.arange(0,1000,10) norm = scipy.stats.norm(scale=50, loc=600) pdf = 10 * norm.pdf(x) cdf = norm.cdf(x) scint.reemission_cdf = np.array(zip(x, cdf)) detector = Surface('detector') detector.set('detect', 1) world = Geometry(vacuum) world.add_solid(Solid(sphere(1000), vacuum, vacuum, surface=detector)) world.add_solid(Solid(sphere(500), scint, vacuum)) w = create_geometry_from_obj(world, update_bvh_cache=False) sim = Simulation(w, geant4_processes=0) # initial photons -- isotropic 250 nm at the origin pos = np.tile([0,0,0], (nphotons,1)).astype(np.float32) dir = np.random.rand(nphotons, 3).astype(np.float32) * 2 - 1 dir /= np.sqrt(dir[:,0]**2 + dir[:,1]**2 + dir[:,2]**2)[:,np.newaxis] pol = np.zeros_like(pos) t = np.zeros(nphotons, dtype=np.float32) wavelengths = np.ones(nphotons).astype(np.float32) * 250 photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) # run simulation and extract final wavelengths event = sim.simulate([photons], keep_photons_end=True).next() mask = (event.photons_end.flags & SURFACE_DETECT) > 0 final_wavelengths = event.photons_end.wavelengths[mask] # compare wavelength distribution to scintillator's reemission pdf hist, edges = np.histogram(final_wavelengths, bins=x) print 'detected', hist.sum(), 'of', nphotons, 'photons' hist_norm = 1.0 * hist / (1.0 * hist.sum() / 1000) pdf /= (1.0 * pdf.sum() / 1000) chi2 = scipy.stats.chisquare(hist_norm, pdf[:-1])[1] print 'chi2 =', chi2 # show histogram comparison #plt.figure(1) #width = edges[1] - edges[0] #plt.bar(left=edges, height=pdf, width=width, color='red') #plt.bar(left=edges[:-1], height=hist_norm, width=width) #plt.show() self.assertTrue(chi2 > 0.75)
from chroma.geometry import Material from chroma.geometry import Surface from Geant4.hepunit import * import numpy as np ls_refractive_index = 1.5 lensmat_refractive_index = 2.0 lensmat_ohara_refractive_index = 1.923 # This is elemental helium - vs. G4_HE he = Material('He') he.set('refractive_index', 1.0) he.set('absorption_length', 1e8) he.set('scattering_length', 1e8) he.density = 0.5 he.composition = { 'He' : 1.0 } lensmat = Material('lensmat') lensmat.set('refractive_index', lensmat_refractive_index) lensmat.set('absorption_length', 1e8) lensmat.set('scattering_length', 1e8) lensmat_ohara = Material('lensmat_ohara') lensmat_ohara.set('refractive_index', lensmat_ohara_refractive_index) lensmat_ohara.set('absorption_length', 1e8) lensmat_ohara.set('scattering_length', 1e8) blackhole = Material('blackhole') blackhole.set('refractive_index', 1.0)
def create_scintillation_material(): global _ls if _ls is None: # ls stands for "liquid scintillator" _ls = Material('liquid-scintillator') _ls.set('refractive_index', ls_refractive_index) _ls.set('absorption_length', 1e8) _ls.set('scattering_length', 1e8) _ls.density = 0.780 _ls.composition = {'H': 0.663210, 'C': 0.336655, 'N': 1.00996e-4, 'O': 3.36655e-5} #_ls.set('refractive_index', np.linspace(ls_refractive_index, ls_refractive_index, 38)) # Scintillation properties energy_scint = list((2 * pi * hbarc / (np.linspace(320, 300, 11).astype(float) * nanometer))) spect_scint = list([0.04, 0.07, 0.20, 0.49, 0.84, 1.00, 0.83, 0.55, 0.40, 0.17, 0.03]) # See https://geant4.web.cern.ch/geant4/UserDocumentation/UsersGuides/ForApplicationDeveloper/html/ch02s03.html # Need to validate that the types are being passed through properly. Previously was using list(Scnt_PP.astype(float) _ls.set_scintillation_property('FASTCOMPONENT', energy_scint, spect_scint) # TODO: These keys much match the Geant4 pmaterial property names. (Magic strings) _ls.set_scintillation_property('SCINTILLATIONYIELD', 8000. / MeV) # Was 10000 originally _ls.set_scintillation_property('RESOLUTIONSCALE', 1.0) # Was 1.0 originally _ls.set_scintillation_property('FASTTIMECONSTANT', 1. * ns) _ls.set_scintillation_property('YIELDRATIO', 1.0) # Was 0.8 - I think this is all fast # Required for scintillation yield per particle # Commenting out these three lines causes a "malloc: *** error for object 0x1298c02d0: pointer being freed was not allocated" WTF? electron_energy_scint = list([0., 1. * MeV, 10. * MeV, 100. * MeV]) electron_yield = list([0, 8000., 80000., 800000.]) _ls.set_scintillation_property('ELECTRONSCINTILLATIONYIELD', electron_energy_scint, electron_yield) proton_energy_scint = list([0 * MeV, 0.1 * MeV, 0.5 * MeV, 1 * MeV, 1.5 * MeV, 2 * MeV, 2.5 * MeV, 3 * MeV, 3.5 * MeV, 4 * MeV, 4.4 * MeV, 5 * MeV, 6 * MeV, 7 * MeV, 8 * MeV, 9 * MeV, 10 * MeV, 12 * MeV, 14 * MeV, 16 * MeV, 18 * MeV, 19.9]) proton_yield = list([0, 43, 581, 1637, 2988, 4562, 6316, 8219, 10249, 12389, 14171, 16946, 21809, 26921, 32240, 37736, 43383, 55059, 67150, 79575, 92277, 104558]) _ls.set_scintillation_property('PROTONSCINTILLATIONYIELD', proton_energy_scint , proton_yield) return _ls
#!/usr/bin/env python from chroma.geometry import Material, Solid, Surface import numpy as np #*************************************************************************** #*************************************************************************** sipm = Material('sipm') sipm.set('detection', 1) copper = Material('copper') copper.set( 'refractive_index', 0.97333 ) # 0.87 #https://refractiveindex.info/?shelf=main&book=Cu&page=Werner with wavelength 175nm extrapolated on TREND function excel copper.set('absorption_length', 50) #1058100 copper.set('scattering_length', 1e6) #10e6 copper.density = 8.96 copper.composition = {'Cu': 1.00} #*************************************************************************** #*************************************************************************** vacuum = Material('vac') vacuum.set('refractive_index', 1.0) vacuum.set('absorption_length', 0) vacuum.set('scattering_length', 1e6) vacuum.set('reemission_prob', 0) #*************************************************************************** #*************************************************************************** LXenon = Material('LXenon') LXenon.set( 'refractive_index', 1.69 ) #https://arxiv.org/ftp/physics/papers/0307/0307044.pdf #possibly 1.57 but lower occurances #1.69 LXenon.set('absorption_length', 1e6) #20000 Changed 364 --> 0 8/9/2018, used 1000mm June 11 2019
import numpy as np from chroma.geometry import Material, Surface vacuum = Material('vacuum') vacuum.set('refractive_index', 1.0) vacuum.set('absorption_length', 1e6) vacuum.set('scattering_length', 1e6) lambertian_surface = Surface('lambertian_surface') lambertian_surface.set('reflect_diffuse', 1) black_surface = Surface('black_surface') black_surface.set('absorb', 1) shiny_surface = Surface('shiny_surface') shiny_surface.set('reflect_specular', 1) glossy_surface = Surface('glossy_surface') glossy_surface.set('reflect_diffuse', 0.5) glossy_surface.set('reflect_specular', 0.5) red_absorb_surface = Surface('red_absorb') red_absorb_surface.set('absorb', [0.0, 0.0, 1.0], [465, 545, 685]) red_absorb_surface.set('reflect_diffuse', [1.0, 1.0, 0.0], [465, 545, 685]) # r7081hqe photocathode material surface # source: hamamatsu supplied datasheet for r7081hqe pmt serial number zd0062 r7081hqe_photocathode = Surface('r7081hqe_photocathode') r7081hqe_photocathode.detect = \ np.array([(260.0, 0.00), (270.0, 0.04), (280.0, 0.07), (290.0, 0.77), (300.0, 4.57),
def convert_materials(self, debug=False): """ #. creates chroma Material instances for each collada material #. fills in properties from the collada extras #. records materials in a map keyed by material.name Chroma materials default to None, 3 settings: * refractive_index * absorption_length * scattering_length And defaults to zero, 2 settings: * reemission_prob * reemission_cdf G4DAE materials have an extra attribute dict that contains keys such as * RINDEX * ABSLENGTH * RAYLEIGH Uncertain of key correspondence, especially REEMISSIONPROB and what about reemission_cdf ? Possibly the many Scintillator keys can provide that ? Probably many the scintillator keys are only relevant to photon production rather than photon propagation, so they are irrelevant to Chroma. Which materials have each:: EFFICIENCY [1 ] Bialkali -------------- assumed to not apply to optical photons --------- FASTTIMECONSTANT [2 ] GdDopedLS,LiquidScintillator SLOWTIMECONSTANT [2 ] GdDopedLS,LiquidScintillator YIELDRATIO [2 ] GdDopedLS,LiquidScintillator GammaFASTTIMECONSTANT [2 ] GdDopedLS,LiquidScintillator GammaSLOWTIMECONSTANT [2 ] GdDopedLS,LiquidScintillator GammaYIELDRATIO [2 ] GdDopedLS,LiquidScintillator AlphaFASTTIMECONSTANT [2 ] GdDopedLS,LiquidScintillator AlphaSLOWTIMECONSTANT [2 ] GdDopedLS,LiquidScintillator AlphaYIELDRATIO [2 ] GdDopedLS,LiquidScintillator NeutronFASTTIMECONSTANT [2 ] GdDopedLS,LiquidScintillator NeutronSLOWTIMECONSTANT [2 ] GdDopedLS,LiquidScintillator NeutronYIELDRATIO [2 ] GdDopedLS,LiquidScintillator SCINTILLATIONYIELD [2 ] GdDopedLS,LiquidScintillator RESOLUTIONSCALE [2 ] GdDopedLS,LiquidScintillator --------------------------------------------------------------------- ReemissionFASTTIMECONSTANT [2 ] GdDopedLS,LiquidScintillator for opticalphoton ReemissionSLOWTIMECONSTANT [2 ] GdDopedLS,LiquidScintillator ReemissionYIELDRATIO [2 ] GdDopedLS,LiquidScintillator FASTCOMPONENT [2 ] GdDopedLS,LiquidScintillator "Fast_Intensity" SLOWCOMPONENT [2 ] GdDopedLS,LiquidScintillator "Slow_Intensity" REEMISSIONPROB [2 ] GdDopedLS,LiquidScintillator "Reemission_Prob" ------------------------------------------------------------------------ RAYLEIGH [5 ] GdDopedLS,Acrylic,Teflon,LiquidScintillator,MineralOil RINDEX [14] Air,GdDopedLS,Acrylic,Teflon,LiquidScintillator,Bialkali, Vacuum,Pyrex,MineralOil,Water,NitrogenGas,IwsWater,OwsWater,DeadWater ABSLENGTH [20] PPE,Air,GdDopedLS,Acrylic,Teflon,LiquidScintillator,Bialkali, Vacuum,Pyrex,UnstStainlessSteel,StainlessSteel, ESR,MineralOil,Water,NitrogenGas,IwsWater,ADTableStainlessSteel,Tyvek,OwsWater,DeadWater Observations: #. no RAYLEIGH for water """ keymap = { "RINDEX": 'refractive_index', "ABSLENGTH": 'absorption_length', "RAYLEIGH": 'scattering_length', "REEMISSIONPROB": 'reemission_prob', } keymat = {} collada = self.nodecls.orig for dmaterial in collada.materials: material = Material(dmaterial.id) if DEBUG: material.dae = dmaterial # vacuum like defaults ? is that appropriate ? what is the G4 equivalent ? material.set('refractive_index', 1.0) material.set('absorption_length', 1e6) material.set('scattering_length', 1e6) if dmaterial.extra is not None: props = dmaterial.extra.properties for dkey, dval in props.items(): if dkey not in keymat: keymat[dkey] = [] keymat[dkey].append( material.name ) # record of materials that have each key if dkey in keymap: key = keymap[dkey] material.set(key, dval[:, 1], wavelengths=dval[:, 0]) log.debug( "for material %s set Chroma prop %s from G4DAE prop %s vals %s " % (material.name, key, dkey, len(dval))) else: log.debug( "for material %s skipping G4DAE prop %s vals %s " % (material.name, dkey, len(dval))) pass self.setup_cdf(material, props) pass pass self.materials[material.name] = material pass log.debug("convert_materials G4DAE keys encountered : %s " % len(keymat)) if debug: for dkey in sorted(keymat, key=lambda _: len(keymat[_])): mats = keymat[dkey] print " %-30s [%-2s] %s " % (dkey, len(mats), ",".join( map(matshorten, mats)))
import numpy as np from chroma.geometry import Material, Surface from chroma.demo.optics import vacuum, r7081hqe_photocathode import math glass = Material('glass') glass.set('refractive_index', 1.49) glass.absorption_length = \ np.array([(200, 0.1e-6), (300, 1000), (330, 1000.0), (500, 2000.0), (600, 1000.0), (770, 500.0), (800, 0.1e-6)]) glass.set('scattering_length', 1e6) silica = np.array([(180, .9), (200, .93), (220,.94), (240, .95), (260, .95), (280, .95), (800,.95)]) gel = np.array([(180, 0.0), (260, 0.0),(280, .09),(300.,.4), (320, .83), (365,.98), (404.7,0.99), (480,1.0), (800,1.0)]) mirror = np.array([(180, 0), (220, 0), (240,.0), (260, .1), (280, .4), (300, .7), (340,.88), (360, .95), (400, .97), (550, .97), (600, .95), (700, .92), (800, .87)]) mcp_boro_photocathode = Surface('mcp_boro_photocathode') mcp_silica_photocathode = Surface('mcp_silica_photocathode') ''' mcp_boro_photocathode.detect = \ np.array([(240.0, 0.00), (250.0, 0.04), (260.0, 2), (270.0, 8.77), (280.0, 24), (290.0, 26), (300.0, 27), (310.0, 28.00), (320.0, 28.8), (330.0, 29.7), (340.0, 30.1), (350.0, 30.52), (360.0, 31.0), (370.0, 31.30), (380.0, 31.20), (390.0, 31.00), (400.0, 30.90), (410.0, 30.50), (420.0, 30.16), (430.0, 29.24), (440.0, 28.31), (450.0, 27.41), (460.0, 26.25), (470.0, 24.90), (480.0, 23.05), (490.0, 21.58), (500.0, 19.94), (510.0, 18.48), (520.0, 17.01), (530.0, 15.34), (540.0, 12.93), (550.0, 10.17), (560.0, 7.86), (570.0, 6.23), (580.0, 5.07), (590.0, 4.03), (600.0, 3.18), (610.0, 2.38), (620.0, 1.72), (630.0, 0.95), (640.0, 0.71), (650.0, 0.44), (660.0, 0.25),