Beispiel #1
0
def cs_total(element,energy):
    """
    Get the total cross section for a given element when
    excitated with x-rays of a given energy (keV) 
    using the xraylib backend
    This is the total absorption cross section which is the 
    sum of the photoionization cross section, 
    the Rayleigh scattering cross section 
    and the Compton scattering cross section
    
    Parameters:
        element : Name, Symbol or Atomic Number (Z) as input
        energy  : energy in keV  - scalar, list, tuple or numpy array
                    
    Returns:
        cs_total: float or numpy array - same size as input energy 
                  total cross section for this element at this incident 
                  energy in cm2/g.
    
    """
    z = elementDB[element]["Z"]
    if isinstance(energy, (list, tuple, np.ndarray)):
        xsec = np.zeros(len(energy))
        for i,enrg in enumerate(energy):
            xsec[i] = xraylib.CS_Total(z,enrg)
    else:
        xsec = xraylib.CS_Total(z,energy)
    return xsec
Beispiel #2
0
    def set_attenuation(__self__, energy):
        """ Sets the linear and total attenuation coefficients according to input.
        Values are taken from xraylib (Brunetti et al., 2004), which is constantly
        updated.

        --------------------------------------------------------------------------

        INPUT:
            energy; int or string """

        mu1_w, mu2_w = 0, 0
        if type(energy) == int:
            for element in __self__.weight:
                ele_no = EnergyLib.Element_No[element]
                print(ele_no, element)
                mu1 = xlib.CS_Total(ele_no, energy)
                mu2 = 0
                mu1_w += mu1 * __self__.weight[element]
                mu2_w += mu2 * __self__.weight[element]
        else:
            for element in __self__.weight:
                attenuated_no = EnergyLib.Element_No[energy]
                ele_no = EnergyLib.Element_No[element]
                attenergy_a = EnergyLib.Energies[attenuated_no]
                attenergy_b = EnergyLib.kbEnergies[attenuated_no]
                mu1, mu2 = xlib.CS_Total(ele_no, attenergy_a), xlib.CS_Total(
                    ele_no, attenergy_b)
                mu1_w += mu1 * __self__.weight[element]
                mu2_w += mu2 * __self__.weight[element]
        __self__.tot_att = (mu1_w, mu2_w)
        __self__.lin_att = (__self__.density * mu1_w, __self__.density * mu2_w)
Beispiel #3
0
def detector_efficiency_convolution(
        data,
        spectrum_size,
        scatt_orders,
        rivelatore):
    
    Z = rivelatore.Detect_Z
    thickness = rivelatore.Detect_thickness
    Z_window = rivelatore.Detect_window_Z
    window_thick = rivelatore.Detect_window_thickness
    energy_max = rivelatore.energy_max

    #FILE *file_in,*file_out;
    i,j,k = 0,0,0
    sigma_var = 0
    density, density1 = 0, 0 
    density_air = 0.0012
    attenuation = 0
    attenuation_window = 0 
    attenuation_air = 0
    energy = 0
    air_thickness = rivelatore.AirThick

    #xrl_error **error;

    spectrum_temp = np.zeros(spectrum_size, dtype=np.double)
    spectrum_conv = np.zeros([scatt_orders,spectrum_size], dtype=np.double)

    k=0
    print("Efficiency correction")
    #########################################################################
    #NOTE: No longer performs the convolution PER ORDER. Instead, we sum
    #all orders and apply it only once
    #########################################################################
    for k in range(scatt_orders):
        spectrum_temp += data[k,:] 
    #########################################################################

        density = xlib.ElementDensity(Z)
        density1 = xlib.ElementDensity(Z_window)
        i=0
        for i in range(spectrum_size): 
            energy = i*rivelatore.energy_max/rivelatore.MCA_chns
            print(f"{energy} - Progress {k}: {i}/{spectrum_size}", end="\r")
            if energy > 0:
                attenuation = xlib.CS_Total(Z, energy)
                attenuation_window = xlib.CS_Total(Z_window, energy)
                attenuation_air = 0.7804 * xlib.CS_Total(7, energy) + 0.20946 * xlib.CS_Total(8, energy) + 0.00934 * xlib.CS_Total(18, energy)
                spectrum_conv[k][i] = spectrum_temp[i] * (1.0-np.exp(-attenuation*thickness*density)) * np.exp(-attenuation_window * window_thick * density1-attenuation_air * air_thickness*density_air)
            else:
                spectrum_conv[k][i] = 0.0
    return spectrum_conv
Beispiel #4
0
def CS_Total(ID,E=None):
  if E==None:
    E=pypsepics.get("SIOC:SYS0:ML00:AO627")/1000
  E=eV(E)/1000
  z=elementZ[ID]
  CS=xraylib.CS_Total(z,E)  
  CS=CS*AtomicMass[ID]/c['NA']/u['cm']**2
  return CS
Beispiel #5
0
 def calc_cross_section(z, energy):
     """
     Calculate the total cross section in cm^2/g
     using xraylib...
     Returns a numpy array...
     """
     result = np.zeros_like(energy)
     for i, en in np.ndenumerate(energy):
         result[i] = xraylib.CS_Total(z, en)
     return result
def GetMaterialMu(E, data): # send in  the photon energy and the dictionary holding the layer information
    Ele = data['Element']
    Mol = data['MolFrac']
    t = 0
    for i in range(len(Ele)):
            t += xraylib.AtomicWeight(xraylib.SymbolToAtomicNumber(Ele[i]))*Mol[i]
    mu=0
    for i in range(len(Ele)):
            mu+= (xraylib.CS_Total(xraylib.SymbolToAtomicNumber(Ele[i]),E) * 
                        xraylib.AtomicWeight(xraylib.SymbolToAtomicNumber(Ele[i]))*Mol[i]/t)
    return mu # total attenuataion w/ coherent scattering in cm2/g
Beispiel #7
0
def test_attenuator():

    #
    # create preprocessor file
    #
    symbol = "Cu"
    number_of_rays = 10000
    cm_or_mm = 0  # 0=using cm, 1=using mm

    #
    # run prerefl
    #
    density = xraylib.ElementDensity(xraylib.SymbolToAtomicNumber(symbol))

    Shadow.ShadowPreprocessorsXraylib.prerefl(interactive=0,
                                              SYMBOL=symbol,
                                              DENSITY=density,
                                              FILE="prerefl.dat",
                                              E_MIN=5000.0,
                                              E_MAX=15000.0,
                                              E_STEP=100.0)

    #
    # run SHADOW for a sample of thickness 10 um
    #

    if cm_or_mm == 0:
        beam = run_example_attenuator(user_units_to_cm=1.0,
                                      npoint=number_of_rays)
    else:
        beam = run_example_attenuator(user_units_to_cm=0.1,
                                      npoint=number_of_rays)

    print("Intensity: %f" % (beam.intensity(nolost=1)))

    #
    # check SHADOW results against xraylib attenuation
    #
    cs1 = xraylib.CS_Total(xraylib.SymbolToAtomicNumber(symbol), 10.0)

    # print("xralib Fe cross section [cm^2/g]: %f"%cs1)
    # print("xralib mu  [cm^-1]: %f"%(cs1*density))

    sh100 = 100 * beam.intensity(nolost=1) / number_of_rays
    xrl100 = 100 * numpy.exp(-cs1 * density * 10e-4)
    print("xralib attenuation [per cent] for 10 um %s at 10 keV: %f" %
          (symbol, xrl100))
    print("Transmission [per cent]: %f" % (sh100))

    numpy.testing.assert_almost_equal(sh100, xrl100, 2)
    '10%': estimate_measurement_time(0.10),
    '5%': estimate_measurement_time(0.05),
    '1%': estimate_measurement_time(0.01),
    '0.5%': estimate_measurement_time(0.005),
    '0.1%': estimate_measurement_time(0.001)
}

#estimate the amount of element of interest in the sample

#convert the absorption edge string to energy
edge_element, edge_shell = inputs['edge_string'].split('-')
Z = xrl.SymbolToAtomicNumber(edge_element)
edge_energy = xrl.EdgeEnergy(Z, _SHELL_MACROS[edge_shell])

murho = [
    xrl.CS_Total(Z, edge_energy - 0.001),
    xrl.CS_Total(Z, edge_energy + 0.001)
]

mass_surface_density = deltamux / (murho[1] - murho[0])

print('')
print('OUTPUT:')
print(
    u'    Estimated sample µx (below edge, above edge, edge step):    %.3f, %.3f, %.3f '
    % (mux_below, mux_above, deltamux))
print(
    u'    Estimated sample µx (below edge, above edge, edge step):    %.3f, %.3f, %.3f '
    % (mux_below, mux_above, deltamux))
print(u'    Optimal transmitted-to-direct beam acquisition time ratio:  %.2f' %
      time_ratio)
Beispiel #9
0
def outgoing_cmam(p, q, maia_d, angle, energy, increasing_ix=True):
    """Compute and return the outgoing cumulative multiplicative absorption map
    (cmam), aka xi'.

    Parameters
    ----------
    p : Phantom2d object
        p.energy - incident beam photon energy (keV).
        p.um_per_px - length of one pixel of the map (um).
    q : int
        Maia detector channel id
    maia_d : Maia() instance
    angle : float
        Tomography projection angle (degree)
    energy : float
        outgoing radiation energy (keV)
    increasing_ix : bool, optional
        If False, performs cumulative sum in opposite direction (in direction of
        decreasing y-index). Note, for the standard Radon transform,
        this direction is unimportant, but for the Radon transform with
        attenuation, we should project in the beam propagation direction.
        (default True).

    Returns
    -------
    2d ndarray of float
        cumulative multiplicative absorption map.

    """
    # The linear absorption map mu = ma_M * mu_M + sum_k ( ma_k * mu_k )
    mu = p.matrix.ma(energy) * p.el_maps['matrix']
    for el in p.el_maps:
        if el == 'matrix':
            continue
        Z = xrl.SymbolToAtomicNumber(el)
        mu += xrl.CS_Total(Z, energy) * p.el_maps[el]

    # project at angle theta by rotating the phantom by angle -theta and
    # projecting along the z-axis (along columns)

    # rotate by the sum of the projection angle and local detector angle
    # Get angle to rotate maps so that propagation toward detector plane
    # corresponds with direction to maia detector element
    phi_x = maia_d.pads[q].angle_X_rad
    phix_deg = rad_to_deg(phi_x)

    # Apply local rotation, accumulation and rotation operators

    # Apply R_{-theta} operator to mu
    # Apply R_{-phi} operator
    mu = rotate(mu, angle + 180 - phix_deg)

    saveflag = np.isclose(
        angle, config.cmam_angle_save) and config.save_projection_images
    if saveflag:
        path = os.path.join(config.mlem_im_path,
                            'project_cmam1_%03d.tif' % config.i)
        helpers.write_tiff32(path, mu)

    # Apply C_z operator
    if increasing_ix:
        mu = np.cumsum(mu, axis=0)
    else:
        mu = np.cumsum(mu[::-1], axis=0)[::-1]

    if saveflag:
        path = os.path.join(config.mlem_im_path,
                            'project_cmam2_%03d.tif' % config.i)
        helpers.write_tiff32(path, mu)

    # Apply R_{phi} operator
    mu = rotate(mu, 180 + phix_deg)
    t = p.um_per_px / UM_PER_CM

    if saveflag:
        path = os.path.join(config.mlem_im_path,
                            'project_cmam3_%03d.tif' % config.i)
        helpers.write_tiff32(path, mu)

    phi = maia_d.pads[q].out_of_xz_plane_angle
    cmam = mu * t / np.cos(phi)
    return cmam
Beispiel #10
0
def irradiance_map(p, angle, n0=1.0, increasing_ix=True, matrix_only=False):
    """Generates the image-sized map of irradiance [1/(cm2 s)] at each 2d pixel
    for a given angle accounting for absorption at the incident energy by the
    full elemental distribution.
    Note: In the full biological approximation, where we only need to consider absorption by
    the matrix and not by the full elemental composition, we could cache this result,
    possibly by adding the memoization decorator I use in Sakura here:
    https://github.com/AustralianSynchrotron/Sakura/blob/master/utils.py
    https://github.com/AustralianSynchrotron/Sakura/blob/master/memoize_core.py

    Parameters
    ----------
    p : phantom object
        p.energy - incident beam energy (keV)
        p.um_per_px - length of one pixel of the map (um)
    angle : float
        tomography angle in degrees. The rotation axis is the y-axis in a conventional xyz
        right-handed coordinate system, so positive rotation in the xz-plane is ccw. i.e.
        with y(out-of-page) o--> x
                            |
                            v
                            z
        therefore, using our rotate function, which assumes 2d rotation
    n0 : float
        incident irradiance (default 1.0).
    increasing_ix : bool, optional
        If False, performs cumulative sum in opposite direction (in direction of
        decreasing y-index). Note, for the standard Radon transform,
        this direction is unimportant, but for the Radon transform with
        attenuation, we should project in the beam propagation direction.
        (default True).
    matrix_only : bool, optional
        If True, the map only considers the matrix and doesn't consider the
        other elements in the model.
        (default False).

    Returns
    -------
    2d ndarray of float
        The irradiance map.

    """
    # matrix_map = zero_outside_circle(p.el_maps['matrix'])

    # The linear absorption map mu0 = ma_M * mu_M + sum_k ( ma_k * mu_k )
    mu0 = p.matrix.ma(p.energy) * p.el_maps['matrix']
    if not config.absorb_with_matrix_only:
        for el in p.el_maps:
            if el == 'matrix':
                continue
            Z = xrl.SymbolToAtomicNumber(el)
            mu0 += xrl.CS_Total(Z, p.energy) * p.el_maps[el]

    # project at angle theta by rotating the phantom by angle -theta and
    # projecting along the z-axis (along columns)
    im = rotate(mu0, angle)  # rotate by angle degrees ccw
    t = p.um_per_px / UM_PER_CM
    # accumulate along z-axis (image defined in xz-coordinates, so accumulate
    # along image rows), consistent with matlab sinogram convention.
    # See http://www.mathworks.com/help/images/radon-transform.html
    if increasing_ix:
        cmam = t * np.cumsum(im, axis=0)
    else:
        cmam = t * np.cumsum(im[::-1], axis=0)[::-1]
    if config.no_in_absorption:
        n_map = n0 + np.zeros_like(cmam)
    else:
        n_map = n0 * exp(-cmam)
    return n_map
Beispiel #11
0
 def ma(self, energy):
     return sum([
         self.cp[el] * xrl.CS_Total(xrl.SymbolToAtomicNumber(el), energy)
         for el in self.cp
     ])
Beispiel #12
0
def calc_escape_peak_ratios(lineE, detectorelement='Si'):
    """
    Calculate ratio of escape peak to main peak based on emperical calculation
    from Alves et. al. 

    Parameters
    ----------
    detectorelement : string
        "Si" or "Ge"
 
    Returns
    -------
    ratio of a single Si K escape peak to a single input peak 
    or
    ratio of Ge Ka, Kb escape peaks to a single input peak

    References
    ----------
    [1]
    "Experimental X-Ray peak-shape determination for a Si(Li) detector",
     L.C. Alves et al., Nucl. Instr. and Meth. in Phys. Res. B 109|110
    (1996) 129-133.  
    
    """

    if (detectorelement == 'Si'):
        #
        # For Si the K peak is 95% of the transition
        # and the photoionization to total cross section is ~ 95%
        # Si escape peak is typically only 0.2-1% (bigger at lower energies)
        #
        jump = xl.JumpFactor(14, xl.K_SHELL)
        fluy = xl.FluorYield(14, xl.K_SHELL)
        corr = fluy * (jump - 1.0) / jump
        corr_photo = xl.CS_Photo(14, lineE) / xl.CS_Total(14, lineE)
        corr_trans = xl.RadRate(14, xl.KA_LINE) + xl.RadRate(14, xl.KB_LINE)
        mu_si = xl.CS_Total(14, lineE)
        mu_internal = xl.CS_Total(14, 1.73998)
        r = mu_internal / mu_si
        eta = corr_trans * corr_photo * corr * 0.5 * (1.0 -
                                                      r * log(1.0 + 1.0 / r))
        ratio = eta / (1.0 - eta)
        #
        # escape peak sigma should be narrower than  the main peak.
        #
        return ratio
    else:
        #
        # Ge detector...
        # Ge has a large escape peak ratio ~ 5-15% and a Ka and kb component
        #
        if (lineE < 11.5):
            return 0.0, 0.0
        jump = xl.JumpFactor(32, xl.K_SHELL)
        fluy = xl.FluorYield(32, xl.K_SHELL)
        corr = fluy * (jump - 1.0) / jump
        corr_photo = xl.CS_Photo(32, lineE) / xl.CS_Total(32, lineE)
        corr_trans_ka = xl.RadRate(32, xl.KA_LINE)
        corr_trans_kb = xl.RadRate(32, xl.KB_LINE)
        mu_ge = xl.CS_Total(32, lineE)  #
        # one for the Ka and one for the Kb peak...
        mu_internal_ka = xl.CS_Total(32, xl.LineEnergy(32, xl.KA_LINE))
        r_ka = mu_internal_ka / mu_ge
        eta_ka = corr_trans_ka * corr_photo * corr * 0.5 * (
            1.0 - r_ka * log(1.0 + 1.0 / r_ka))
        ratio_ka = eta_ka / (1.0 - eta_ka)

        mu_internal_kb = xl.CS_Total(32, xl.LineEnergy(32, xl.KB_LINE))
        r_kb = mu_internal_kb / mu_ge
        eta_kb = corr_trans_kb * corr_photo * corr * 0.5 * (
            1.0 - r_kb * log(1.0 + 1.0 / r_kb))
        ratio_kb = eta_kb / (1.0 - eta_kb)

        return ratio_ka, ratio_kb
Beispiel #13
0
    def test_refractiveindex(self):
        density = float(2.328)
        c = compoundfromformula.CompoundFromFormula("Si", density, name="silicon")
        energy = np.asarray([5, 10], dtype=float)
        Z = 14

        # Xraylib (TODO: n_im sign is wrong!)
        n_re0 = np.asarray(
            [xraylib.Refractive_Index_Re("Si", e, density) for e in energy]
        )
        n_im0 = -np.asarray(
            [xraylib.Refractive_Index_Im("Si", e, density) for e in energy]
        )

        # Exactly like Xraylib (TODO: CS_Total -> CS_Photo_Total)
        delta = (
            density
            * 4.15179082788e-4
            * (Z + np.asarray([xraylib.Fi(Z, e) for e in energy]))
            / xraylib.AtomicWeight(Z)
            / energy ** 2
        )
        beta = (
            np.asarray([xraylib.CS_Total(Z, e) for e in energy])
            * density
            * 9.8663479e-9
            / energy
        )
        n_re1 = 1 - delta
        n_im1 = -beta

        np.testing.assert_allclose(n_re0, n_re1)
        np.testing.assert_allclose(n_im0, n_im1)

        # Im: Kissel
        n_im1b = (
            -np.asarray([xraylib.CS_Total_Kissel(Z, e) for e in energy])
            * density
            * 9.8663479e-9
            / energy
        )

        # Im: Kissel with pint
        n_im1d = (
            ureg.Quantity(c.mass_att_coeff(energy), "cm^2/g")
            * ureg.Quantity(c.density, "g/cm^3")
            * ureg.Quantity(energy, "keV").to("cm", "spectroscopy")
            / (4 * np.pi)
        )
        n_im1d = -n_im1d.to("dimensionless").magnitude

        r = n_im1b / n_im1d
        np.testing.assert_allclose(r, r[0])

        # Im: other formula
        n_im1c = (
            density
            * 4.15179082788e-4
            * (np.asarray([xraylib.Fii(Z, e) for e in energy]))
            / xraylib.AtomicWeight(Z)
            / energy ** 2
        )

        # Spectrocrunch
        n_re2 = c.refractive_index_real(energy)
        n_im2 = c.refractive_index_imag(energy)

        np.testing.assert_allclose(n_re2, n_re0)
        np.testing.assert_allclose(n_im2, n_im1c, rtol=1e-6)
def capXsect(element, energy):
    C = xl.CS_Total(symToNum(element), energy)
    return C
Beispiel #15
0
def tube_atten(E, Z, D):
    expon = -xrl.CS_Total(Z, E) * D * 1e-4 * xrl.ElementDensity(Z)
    ta = exp(expon)
    return ta
Beispiel #16
0
 def _CS_Total_Layer(layer, E):
     rv = 0.0
     for i in zip(layer.Z, layer.weight):
         (Z, weight) = i
         rv += weight * xrl.CS_Total(Z, E)
     return rv
Beispiel #17
0
photons_per_second = float(
    input('Incident photon flux (background subtracted) (ph/s): '))

compound = xrl.CompoundParser(input_str['compound'])

#convert the absorption edge string to energy
edge_element, edge_shell = input_str['absorption_edge'].split('-')

edge_energy = xrl.EdgeEnergy(xrl.SymbolToAtomicNumber(edge_element),
                             _SHELL_MACROS[edge_shell])

#calculate the mass attenuation coefficient below and above edge
murho = [0, 0]

for i in range(compound['nElements']):
    murho[0] = murho[0] + compound['massFractions'][i] * xrl.CS_Total(
        compound['Elements'][i], edge_energy - 0.001)
    murho[1] = murho[1] + compound['massFractions'][i] * xrl.CS_Total(
        compound['Elements'][i], edge_energy + 0.001)

#calculate filler attenuation using an "average" nitrogen filter
filler_mux = xrl.CS_Total(7, edge_energy) * 1.5 * 0.1

#Measurement specific values for background count rates, estimates are used
beta = 1.1
gamma = 0.03 * exp(filler_mux)


#optimization condition f = 0
def f(x, mu0, mu, beta=1, gamma=0, filler_mux=0):
    aux1 = sqrt(8 * beta * exp(-filler_mux)) * sqrt(
        exp(mu0 * x) + exp(mu * x) + gamma *