Exemplo n.º 1
0
def GetKM3NeTOMQuantumEfficiency(peakQE=None, wpdQE=False):
    """
    A function to return the quantum efficiency as instance of
    I3CLSimFunctionFromTable
    """
    if peakQE is None:
        if wpdQE: peakQE = 0.304
        else: peakQE = 0.32

    if wpdQE:
        # this is taken straight from the WPD document
        QEscale = peakQE / 0.304

        QEvals = [
            0.0, 0.0, 0.5, 3.1, 9.8, 17.5, 23.2, 26.5, 28.1, 28.1, 29.1, 30.1,
            30.4, 30.1, 29.9, 29.3, 28.6, 27.5, 26.5, 25.0, 23.2, 21.1, 19.6,
            18.5, 17.2, 15.4, 12.1, 9.3, 7.2, 6.2, 4.6, 3.6, 2.8, 2.1, 1.3,
            0.8, 0.5, 0.3, 0.0, 0.0
        ]
        QEvals = numpy.array(QEvals) * 0.01 * QEscale

        return I3CLSimFunctionFromTable(260. * I3Units.nanometer,
                                        10. * I3Units.nanometer, QEvals)

    else:
        # this is the version we used before the WPD document
        QEscale = peakQE

        QEvals = [0.00, 0.87, 1.00, 0.94, 0.78, 0.49, 0.24, 0.09, 0.02, 0.00]
        QEvals = numpy.array(QEvals) * QEscale

        return I3CLSimFunctionFromTable(250. * I3Units.nanometer,
                                        50. * I3Units.nanometer, QEvals)
Exemplo n.º 2
0
def GetWOMAcceptance(active_fraction=1.):
    """
    :param active_fraction: the fraction of the head-on geometric area that
       is photosensitive (i.e. the ratio of the area of the wavelength-shifting)
       tube to the area of the housing.
    """
    # probability that Cherenkov photon directly incident on the wavelength-
    # shifting paint is absorbed, and that the shifted photon is captured in
    # the plexiglass tube.
    # Pers. comm., D. Hebecker, April 2016
    capture_efficiency = [0.0,
                          0.34587,
                          0.45655,
                          0.48452,
                          0.46706,
                          0.47998,
                          0.48761,
                          0.48948,
                          0.49017,
                          0.4905,
                          0.49127,
                          0.49325,
                          0.4966,
                          0.49651,
                          0.4857,
                          0.40011,
                          0.15273,
                          0.00779,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0,
                          0.0]
    # KM3NeT PMT QE, weighted with the emission spectrum of the wavelength
    # shifter
    recapture_efficiency = 0.2403
    return I3CLSimFunctionFromTable(245*I3Units.nanometer, 10*I3Units.nanometer,
        [a*recapture_efficiency*active_fraction for a in capture_efficiency])
Exemplo n.º 3
0
def GetIceCubeDOMAcceptance(domRadius=0.16510 * I3Units.m,
                            efficiency=1.0,
                            highQE=False):
    """
    this is taken from photonics/lib/efficiency.h:
    
    Adopted into photonics Juli 1 2007 /Johan. Interpolation of data
    from Kotoyo Hoshina <*****@*****.**>: 
    Jan 15 K.Hoshina :
    Found a wrong value at 260nm whicn I didn't offer in July 1st 2007.
    Copied a value from 270nm.

          0.0002027029 -> 0.0000064522


    ROMEO wavelength effective area

    This is the table of photo-electron acceptance of the
    IceCube PMT after through the glass+gel + PMT photocathode,
    as a function of wavelength.
    It corresponds to a 0p.e. threshold.
    The injection angle (off-axis angle) is 0deg.
    
    The acceptances are calculated by:
    
    acceptance = NPEs generated by photo-cathode (0P.E threshold)\
              / Nphotons_inject_to_1m^2
    """
    dom2007a_eff_area = [
        0.0000064522, 0.0000064522, 0.0000064522, 0.0000064522, 0.0000021980,
        0.0001339040, 0.0005556810, 0.0016953000, 0.0035997000, 0.0061340900,
        0.0074592700, 0.0090579800, 0.0099246700, 0.0105769000, 0.0110961000,
        0.0114214000, 0.0114425000, 0.0111527000, 0.0108086000, 0.0104458000,
        0.0099763100, 0.0093102500, 0.0087516600, 0.0083225800, 0.0079767200,
        0.0075625100, 0.0066377000, 0.0053335800, 0.0043789400, 0.0037583500,
        0.0033279800, 0.0029212500, 0.0025334900, 0.0021115400, 0.0017363300,
        0.0013552700, 0.0010546600, 0.0007201020, 0.0004843820, 0.0002911110,
        0.0001782310, 0.0001144300, 0.0000509155
    ]
    dom2007a_eff_area = numpy.array(
        dom2007a_eff_area
    ) * I3Units.meter2  # apply units (this is an effective area)
    domArea = math.pi * domRadius**2.
    dom2007a_efficiency = efficiency * (dom2007a_eff_area / domArea)

    if highQE:
        wv, rde = numpy.loadtxt(
            expandvars(
                '$I3_BUILD/ice-models/resources/models/wavelength/wv.rde')).T
        dom2007a_efficiency *= numpy.interp(
            260 + 10 * numpy.arange(len(dom2007a_efficiency)), wv, rde)

    domEfficiency = I3CLSimFunctionFromTable(260. * I3Units.nanometer,
                                             10. * I3Units.nanometer,
                                             dom2007a_efficiency)

    return domEfficiency
Exemplo n.º 4
0
def GetIceCubeFlasherSpectrum(spectrumType = I3CLSimFlasherPulse.FlasherPulseType.LED405nm):
    if spectrumType in [I3CLSimFlasherPulse.FlasherPulseType.SC1, I3CLSimFlasherPulse.FlasherPulseType.SC2]:
        # special handling for Standard Candles:
        # these currently have single-wavelength spectra
        spectrum = I3CLSimFunctionDeltaPeak(337.*I3Units.nanometer)
        return spectrum
    else:
        data = GetIceCubeFlasherSpectrumData(spectrumType)
        spectrum = I3CLSimFunctionFromTable(data[0], data[1])
        return spectrum
Exemplo n.º 5
0
def GetAntaresOMGelAbsorptionLength():
    """
    A function to return the absorption length
    the gel of an ANTARES OM
    Note: The file hit-ini_optic.f has three different 
    datasets for this absorption length!
    However in the file hit.f it always is initialized with the
    same (gel_id=1). Thus this one is implemented here.
    """

    # Data copied from the km3 file hit-ini_optic.f
    # GEL WACKER (default)
    al_gel_default_reverse = [
        100.81,  # at 610 nm
        99.94,  # at 600 nm
        99.89,
        96.90,
        96.42,
        94.36,
        89.09,
        90.10,
        86.95,
        85.88,
        84.49,
        81.08,
        78.18,
        76.48,
        74.55,
        72.31,
        68.05,
        66.91,
        64.48,
        62.53,
        59.38,
        56.64,
        53.29,
        48.96,
        45.71,
        41.88,
        37.14,
        30.49,
        23.08,
        15.60,
        8.00,
        0.00  # at 300 nm
    ]

    # Apply units
    al_gel_default_reverse = [(i * I3Units.cm) for i in al_gel_default_reverse]
    al_gel_default_reverse.reverse()  # reverse the list (in-place)

    return I3CLSimFunctionFromTable(300. * I3Units.nanometer,
                                    10. * I3Units.nanometer,
                                    al_gel_default_reverse)
Exemplo n.º 6
0
def GetAntaresOMGlassAbsorptionLength():
    """
    A function to return the absoprtion length of
    the glass sphere of an ANTARES OM
    """

    # Data copied from the km3 file hit-ini_optic.f
    # as measured by Pavel
    # the last 3 bins contain measurements from Saclay (6/3/98)
    al_glass_reverse = [
        148.37,  # at 610 nm
        142.87,  # at 600 nm
        135.64,
        134.58,
        138.27,
        142.40,
        147.16,
        151.80,
        150.88,
        145.68,
        139.70,
        126.55,
        118.86,
        113.90,
        116.08,
        109.23,
        81.63,
        65.66,
        77.30,
        73.02,
        81.25,
        128.04,
        61.84,
        19.23,
        27.21,
        18.09,
        8.41,
        3.92,
        1.82,
        0.84,
        0.39,
        0.17  # at 300 nm
    ]

    # Apply units
    al_glass_reverse = [(i * I3Units.cm) for i in al_glass_reverse]
    al_glass_reverse.reverse()  # reverse the list (in-place)

    return I3CLSimFunctionFromTable(300. * I3Units.nanometer,
                                    10. * I3Units.nanometer, al_glass_reverse)
def MakeAntaresMediumProperties():
    m = I3CLSimMediumProperties(mediumDensity=1.039 * I3Units.g / I3Units.cm3,
                                layersNum=1,
                                layersZStart=-310. * I3Units.m,
                                layersHeight=2500. * I3Units.m,
                                rockZCoordinate=-310. * I3Units.m,
                                airZCoordinate=2500. * I3Units.m -
                                310. * I3Units.m)

    antaresScatModel = GetAntaresScatteringCosAngleDistribution()
    m.SetScatteringCosAngleDistribution(antaresScatModel)

    # no ice/water anisotropy. all of these three are no-ops
    m.SetDirectionalAbsorptionLengthCorrection(I3CLSimScalarFieldConstant(1.))
    m.SetPreScatterDirectionTransform(I3CLSimVectorTransformConstant())
    m.SetPostScatterDirectionTransform(I3CLSimVectorTransformConstant())

    # no "ice" tilt
    m.SetIceTiltZShift(I3CLSimScalarFieldConstant(0.))

    antaresScattering = I3CLSimFunctionScatLenPartic(
        volumeConcentrationSmallParticles=0.0075 * I3Units.perMillion,
        volumeConcentrationLargeParticles=0.0075 * I3Units.perMillion)
    antaresPhaseRefIndex = I3CLSimFunctionRefIndexQuanFry(
        pressure=215.82225 * I3Units.bar,
        temperature=13.1,
        salinity=38.44 * I3Units.perThousand)

    # these are for ANTARES (mix of Smith&Baker water and Antares site measurements)
    # absorption lengths starting from 290nm in 10nm increments
    absLenTable = [
        4.65116279, 7.1942446, 9.17431193, 10.57082452, 12.62626263,
        14.08450704, 15.89825119, 18.93939394, 21.14164905, 24.09638554,
        27.54820937, 30.76923077, 34.36426117, 39.21568627, 42.19409283,
        45.87155963, 50., 52.35602094, 54.94505495, 54.94505495, 51.02040816,
        38.91050584, 28.01120448, 20.96436059, 19.72386588, 17.92114695,
        15.67398119, 14.12429379, 12.51564456, 9.25925926, 6.36942675,
        4.09836066, 3.46020761
    ]
    antaresAbsorption = I3CLSimFunctionFromTable(290. * I3Units.nanometer,
                                                 10. * I3Units.nanometer,
                                                 absLenTable)

    m.SetAbsorptionLength(0, antaresAbsorption)
    m.SetScatteringLength(0, antaresScattering)
    m.SetPhaseRefractiveIndex(0, antaresPhaseRefIndex)

    return m
Exemplo n.º 8
0
def GetAntaresOMQuantumEfficiency():
    """
    A function to return the quantum efficiency as instance of
    I3CLSimFunctionFromTable
    """
    # Data copied from the km3 file hit-ini_optic.f
    # BB5912 from Hamamatsu
    q_eff_0 = 0.01
    q_eff_reverse = [
        1.988,  # at 610 nm
        2.714,  # at 600 nm
        3.496,
        4.347,
        5.166,
        6.004,
        6.885,
        8.105,
        10.13,
        13.03,
        15.29,
        16.37,
        17.11,
        17.86,
        18.95,
        20.22,
        21.26,
        22.10,
        22.65,
        23.07,
        23.14,
        23.34,
        22.95,
        22.95,
        22.74,
        23.48,
        22.59,
        20.61,
        17.68,
        13.18,
        7.443,
        2.526  # at 300 nm
    ]

    q_eff_reverse = [(q_eff_0 * i) for i in q_eff_reverse]
    q_eff_reverse.reverse()  # reverse the list (in-place)

    return I3CLSimFunctionFromTable(300. * I3Units.nanometer,
                                    10. * I3Units.nanometer, q_eff_reverse)
Exemplo n.º 9
0
def GetAntaresOMAcceptance(domRadius=0.2159 * I3Units.m):  # 17 inch diameter
    """
    The main function to return the effective area
    of the Antares OM
    """

    # Load the constants
    glass_width = GetAntaresOMGlassThickness()
    gel_width = GetAntaresOMGelThickness()
    pmt_collection_efficiency = GetAntaresPMTCollectionEfficiency()
    pmt_diameter = GetAntaresPMTDiameter()

    # Geometrical area of the om profile
    pmt_area = math.pi * (pmt_diameter / 2.)**2  #is im square meters
    om_area = math.pi * domRadius**2.

    # Get the tables from above
    q_eff = GetAntaresOMQuantumEfficiency()
    abs_glass = GetAntaresOMGlassAbsorptionLength()
    abs_gel = GetAntaresOMGelAbsorptionLength()

    # Each of the tables above has 32 bins in the wavelength range of 300nm - 610nm,
    # where the exact value is at the beginning of each bin, means
    # value of bin  0 belongs to 300nm
    # value of bin  1 belongs to 310nm
    # value of bin 31 belongs to 610nm
    # Now combine them
    om_eff_area = [
        0.
    ]  # use a single entry at 290nm to have the same range as other functions(wlen)
    for wavelength in range(300, 611, 10):
        this_abs_glass = abs_glass.GetValue(wavelength * I3Units.nanometer)
        this_abs_gel = abs_gel.GetValue(wavelength * I3Units.nanometer)

        if (this_abs_glass <= 0.) or (this_abs_gel <= 0.):
            current_om_eff_area = 0.
        else:
            current_om_eff_area = pmt_area * \
                                  pmt_collection_efficiency * \
                                  q_eff.GetValue(wavelength*I3Units.nanometer) * \
                                  math.exp( -( glass_width / this_abs_glass ) ) * \
                                  math.exp( -( gel_width / this_abs_gel ) )

        om_eff_area.append(current_om_eff_area)

    return I3CLSimFunctionFromTable(290. * I3Units.nanometer,
                                    10. * I3Units.nanometer,
                                    numpy.array(om_eff_area) / om_area)
Exemplo n.º 10
0
def MakeIceCubeMediumPropertiesPhotonics(tableFile,
                                         detectorCenterDepth = 1948.07*I3Units.m):
    ### read ice information from a photonics-compatible table

    file = open(tableFile, 'r')
    rawtable = file.readlines()
    file.close()
    del file

    # get rid of comments and split lines at whitespace
    parsedtable = [line.split() for line in rawtable if line.lstrip()[0] != "#"]

    nlayer_lines = [line for line in parsedtable if line[0].upper()=="NLAYER"]
    nwvl_lines =   [line for line in parsedtable if line[0].upper()=="NWVL"]

    if len(nlayer_lines) == 0:
        raise RuntimeError("There is no \"NLAYER\" entry in your ice table!")
    if len(nlayer_lines) > 1:
        raise RuntimeError("There is more than one \"NLAYER\" entry in your ice table!")
    if len(nwvl_lines) == 0:
        raise RuntimeError("There is no \"NWVL\" entry in your ice table!")
    if len(nwvl_lines) > 1:
        raise RuntimeError("There is more than one \"NWVL\" entry in your ice table!")

    nLayers = int(nlayer_lines[0][1])
    nWavelengths = int(nwvl_lines[0][1])
    startWavelength = float(nwvl_lines[0][2])*I3Units.nanometer
    stepWavelength = float(nwvl_lines[0][3])*I3Units.nanometer

    startWavelength += stepWavelength/2.

    # make a list of wavelengths
    wavelengths = numpy.linspace(start=startWavelength, stop=startWavelength+float(nWavelengths)*stepWavelength, num=nWavelengths, endpoint=False)

    print("The table file {0} has {1} layers and {2} wavelengths, starting from {3}ns in {4}ns steps".format(tableFile, nLayers, nWavelengths, startWavelength/I3Units.nanometer, stepWavelength/I3Units.nanometer))


    # replace parsedtable with a version without NLAYER and NWVL entries
    parsedtable = [line for line in parsedtable if ((line[0].upper()!="NLAYER") and (line[0].upper()!="NWVL"))]

    if len(parsedtable) != nLayers*6:
        raise RuntimeError("Expected {0}*6={1} lines [not counting NLAYER and NWVL] in the icetable file, found {2}".format(nLayers, nLayers*6, len(parsedtable)))

    if parsedtable[0][0].upper() != "LAYER":
        raise RuntimeError("Layer definitions should start with the LAYER keyword (reading {0})".format(tableFile))

    # parse the lines
    layers = []

    layerdict = dict()
    for line in parsedtable:
        keyword = line[0].upper()

        if keyword == "LAYER":
            if len(layerdict) != 0:
                layers.append(layerdict)

            #re-set layerdict
            layerdict = dict()
        else:
            # some other keyword
            if keyword in layerdict:
                raise RuntimeError("Keyword {0} is used twice for one layer (reading {1})".format(keyword, tableFile))

        # optional units
        unit = 1.                                       # no units by default
        if keyword == "LAYER": unit = I3Units.meter     # coordinates
        if keyword == "ABS": unit = 1./I3Units.meter    # absorption coefficient
        if keyword == "SCAT": unit = 1./I3Units.meter   # scattering coefficient

        layerdict[keyword] = [float(number)*unit for number in line[1:]]

    # last layer
    if len(layerdict) != 0:
        layers.append(layerdict)

    if len(layers) < 1:
        raise RuntimeError("At least one layers is requried (reading {0})".format(tableFile))

    layerHeight = abs(layers[0]['LAYER'][1] - layers[0]['LAYER'][0])
    print("layer height is {0}m".format(layerHeight/I3Units.m))

    # sort layers into dict by bottom z coordinate and check some assumptions
    layersByZ = dict()
    for layer in layers:
        layerBottom = layer['LAYER'][0]
        layerTop = layer['LAYER'][1]

        if layerBottom > layerTop:
            print("a layer is upside down. compensating. (reading {0})".format(tableFile))
            dummy = layerBottom
            layerBottom = layerTop
            layerTop = dummy

        # check layer height
        if abs((layerTop-layerBottom) - layerHeight) > 0.0001:
            raise RuntimeError("Differing layer heights while reading {0}. Expected {1}m, got {2}m.".format(tableFile, layerHeight, layerTop-layerBottom))

        layersByZ[layerBottom] = layer


    layers = []
    endZ = None
    for dummy, layer in sorted(layersByZ.items()):
        startZ = layer['LAYER'][0]
        if (endZ is not None) and (abs(endZ-startZ) > 0.0001):
            raise RuntimeError("Your layers have holes. previous layer ends at {0}m, next one starts at {1}m".format(endZ/I3Units.m, startZ/I3Units.m))
        endZ = layer['LAYER'][1]
        layers.append(layer)

    # check even more assumptions
    meanCos=None
    for layer in layers:
        if meanCos is None: meanCos = layer['COS'][0]

        for cosVal in layer['COS']:
            if abs(cosVal-meanCos) > 0.0001:
                raise RuntimeError("only a constant mean cosine is supported by clsim (expected {0}, got {1})".format(meanCos, cosVal))

        if len(layer['COS']) != len(wavelengths):
            raise RuntimeError("Expected {0} COS values, got {1}".format(len(wavelengths), len(layer['COS'])))
        if len(layer['ABS']) != len(wavelengths):
            raise RuntimeError("Expected {0} ABS values, got {1}".format(len(wavelengths), len(layer['ABS'])))
        if len(layer['SCAT']) != len(wavelengths):
            raise RuntimeError("Expected {0} SCAT values, got {1}".format(len(wavelengths), len(layer['SCAT'])))
        if len(layer['N_GROUP']) != len(wavelengths):
            raise RuntimeError("Expected {0} N_GROUP values, got {1}".format(len(wavelengths), len(layer['N_GROUP'])))
        if len(layer['N_PHASE']) != len(wavelengths):
            raise RuntimeError("Expected {0} N_PHASE values, got {1}".format(len(wavelengths), len(layer['N_PHASE'])))

        for i in range(len(wavelengths)):
            if abs(layer['N_GROUP'][i]-layers[0]['N_GROUP'][i]) > 0.0001:
                raise RuntimeError("N_GROUP may not be different for different layers in this version of clsim!")

            if abs(layer['N_PHASE'][i]-layers[0]['N_PHASE'][i]) > 0.0001:
                raise RuntimeError("N_PHASE may not be different for different layers in this version of clsim!")

        #print "start", layer['LAYER'][0], "end", layer['LAYER'][1]


    ##### start making the medium property object

    m = I3CLSimMediumProperties(mediumDensity=0.9216*I3Units.g/I3Units.cm3,
                                layersNum=len(layers),
                                layersZStart=layers[0]['LAYER'][0],
                                layersHeight=layerHeight,
                                rockZCoordinate=-870.*I3Units.m,
                                # TODO: inbetween: from 1740 upwards: less dense ice (factor 0.825)
                                airZCoordinate=1940.*I3Units.m)


    iceCubeScatModel = I3CLSimRandomValueHenyeyGreenstein(meanCosine=meanCos)
    m.SetScatteringCosAngleDistribution(iceCubeScatModel)

    # no ice/water anisotropy. all of these three are no-ops
    m.SetDirectionalAbsorptionLengthCorrection(I3CLSimScalarFieldConstant(1.))
    m.SetPreScatterDirectionTransform(I3CLSimVectorTransformConstant())
    m.SetPostScatterDirectionTransform(I3CLSimVectorTransformConstant())

    # no ice tilt
    m.SetIceTiltZShift(I3CLSimScalarFieldConstant(0.))

    phaseRefIndex = I3CLSimFunctionFromTable(startWavelength, stepWavelength, layers[0]['N_PHASE'])
    groupRefIndex = I3CLSimFunctionFromTable(startWavelength, stepWavelength, layers[0]['N_GROUP'])
    #phaseRefIndex = I3CLSimFunctionRefIndexIceCube(mode="phase")
    #groupRefIndex = I3CLSimFunctionRefIndexIceCube(mode="group")

    for i in range(len(layers)):
        #print "layer {0}: depth at bottom is {1} (z_bottom={2}), b_400={3}".format(i, depthAtBottomOfLayer[i], layerZStart[i], b_400[i])

        m.SetPhaseRefractiveIndex(i, phaseRefIndex)
        m.SetGroupRefractiveIndexOverride(i, groupRefIndex)

        absLenTable = [1./absCoeff for absCoeff in layers[i]['ABS']]
        absLen = I3CLSimFunctionFromTable(startWavelength, stepWavelength, absLenTable, storeDataAsHalfPrecision=True)
        m.SetAbsorptionLength(i, absLen)

        scatLenTable = [(1./scatCoeff)*(1.-meanCos) for scatCoeff in layers[i]['SCAT']]
        scatLen = I3CLSimFunctionFromTable(startWavelength, stepWavelength, scatLenTable, storeDataAsHalfPrecision=True)
        m.SetScatteringLength(i, scatLen)

    return m
Exemplo n.º 11
0
def GetDEggAcceptance(active_fraction=1.):
    """
    :param active_fraction: the fraction of the head-on geometric area that
       is photosensitive (i.e. the ratio of the photocathode area to the
       geometric area)
    """
    # Combined efficiency for D-Egg glass (10 mm), high-UV transparency gel
    # (5 mm), and Hamamatsu R5912-100 at the center of the photocathode
    # Pers. comm., Lu Lu, April 2016

    logging.log_warn("DeprecationWarning: The numbers here are outdated! Also this functionality is now part of the 'mDOM-WOM-simulation' project. Please check it out!")

    center_efficiency = [0.0,
                         0.0,
                         0.0,
                         0.0005,
                         0.0093,
                         0.058,
                         0.1473,
                         0.2358,
                         0.2904,
                         0.3139,
                         0.3237,
                         0.3336,
                         0.339,
                         0.3373,
                         0.3292,
                         0.3195,
                         0.3087,
                         0.3017,
                         0.2873,
                         0.2717,
                         0.2532,
                         0.2305,
                         0.2119,
                         0.1962,
                         0.1832,
                         0.1708,
                         0.1523,
                         0.1227,
                         0.0928,
                         0.0728,
                         0.0597,
                         0.0494,
                         0.0404,
                         0.0318,
                         0.0241,
                         0.0174,
                         0.0118,
                         0.0076,
                         0.0047,
                         0.0027,
                         0.0,
                         0.0,
                         0.0,
                         0.0]
    # Hamamatsu quotes a minimum photocathode diameter of 190 mm. Pending a real
    # 2D average of the capture efficiency, approximate with 90% of the center
    # efficiency times the minimum photocathode area.
    active_fraction *= 0.9*(190./300.)**2
    return I3CLSimFunctionFromTable(250*I3Units.nanometer, 10*I3Units.nanometer,
        [a*active_fraction for a in center_efficiency])
Exemplo n.º 12
0
def GetKM3NeTDOMAcceptance(domRadius=(17. / 2.) * 0.0254 * I3Units.m,
                           peakQE=None,
                           wpdQE=False,
                           withWinstonCone=False):  # 17 inch diameter
    """
    The main function to return the effective area
    of the KM3NeT DOM
    """

    # the multiPMT simulation expects photons on a sphere of 17" diameter.
    # The result of this function is supposed to be used for emission
    # spectrum biassing only, so only allow 17" spheres just to be safe.
    if domRadius != (17. / 2.) * 0.0254 * I3Units.m:
        raise RuntimeError(
            "GetKM3NeTDOMAcceptance is currently only valid for a diameter of 17inch."
        )

    # Load the constants
    glass_width = GetKM3NeTOMGlassThickness()
    gel_width = GetKM3NeTOMGelThickness()
    pmt_collection_efficiency = GetKM3NeTPMTCollectionEfficiency()

    # Get the tables from above
    q_eff = GetKM3NeTOMQuantumEfficiency(peakQE=peakQE, wpdQE=wpdQE)
    abs_glass = GetKM3NeTOMGlassAbsorptionLength()
    abs_gel = GetKM3NeTOMGelAbsorptionLength()

    if withWinstonCone:
        coneScaler = 2.0  # correction factor at cos(theta)=1
    else:
        coneScaler = 1.

    # Each of the tables above has 32 bins in the wavelength range of 300nm - 610nm,
    # where the exact value is at the beginning of each bin, means
    # value of bin  0 belongs to 300nm
    # value of bin  1 belongs to 310nm
    # value of bin 31 belongs to 610nm
    # Now combine them
    om_eff_area = [
        0.
    ]  # use a single entry at 290nm to have the same range as other functions(wlen)
    for wavelength in range(300, 611, 10):
        this_abs_glass = abs_glass.GetValue(wavelength * I3Units.nanometer)
        this_abs_gel = abs_gel.GetValue(wavelength * I3Units.nanometer)

        if (this_abs_glass <= 0.) or (this_abs_gel <= 0.):
            current_om_eff_area = 0.
        else:
            current_om_eff_area = pmt_collection_efficiency * \
                                  q_eff.GetValue(wavelength*I3Units.nanometer) * \
                                  coneScaler
            # do not include these two (they assume a fixed photon path length through glass which
            # currently is not the smallest possible length..
            #math.exp( -( glass_width / this_abs_glass ) ) * \
            #math.exp( -( gel_width / this_abs_gel ) )

        om_eff_area.append(current_om_eff_area)

    return I3CLSimFunctionFromTable(290. * I3Units.nanometer,
                                    10. * I3Units.nanometer,
                                    numpy.array(om_eff_area))