예제 #1
0
 def calculateSld(self, event):
     """
         Calculate the neutron scattering density length of a molecule
     """
     self.clear_outputs()
     try:
         #Check validity user inputs
         flag, msg = self.check_inputs()
         if self.base is not None and msg.lstrip().rstrip() != "":
             msg = "SLD Calculator: %s" % str(msg)
             wx.PostEvent(self.base, StatusEvent(status=msg))
         if not flag:
             return
         #get ready to compute
         self.sld_formula = formula(self.compound, density=self.density)
         (sld_real, sld_im, _), (_, absorp, incoh), \
                     length = neutron_scattering(compound=self.compound,
                                density=self.density,
                                wavelength=self.neutron_wavelength)
         if self.xray_source == "[A]":
             energy = xray_energy(self.xray_source_input)
             xray_real, xray_im = xray_sld_from_atoms(
                 self.sld_formula.atoms,
                 density=self.density,
                 energy=energy)
         elif self.xray_source == "[keV]":
             xray_real, xray_im = xray_sld_from_atoms(
                 self.sld_formula.atoms,
                 density=self.density,
                 energy=self.xray_source_input)
         elif self.xray_source == "Element":
             xray_real, xray_im = self.calculate_sld_helper(
                 element=self.xray_source_input,
                 density=self.density,
                 molecule_formula=self.sld_formula)
         # set neutron sld values
         val = format_number(sld_real * _SCALE)
         self.neutron_sld_real_ctl.SetValue(val)
         val = format_number(math.fabs(sld_im) * _SCALE)
         self.neutron_sld_im_ctl.SetValue(val)
         # Compute the Cu SLD
         self.xray_sld_real_ctl.SetValue(format_number(xray_real * _SCALE))
         val = format_number(math.fabs(xray_im) * _SCALE)
         self.xray_sld_im_ctl.SetValue(val)
         # set incoherence and absorption
         self.neutron_inc_ctl.SetValue(format_number(incoh))
         self.neutron_abs_ctl.SetValue(format_number(absorp))
         # Neutron length
         self.neutron_length_ctl.SetValue(format_number(length))
         # display wavelength
         #self.wavelength_ctl.SetValue(str(self.wavelength))
         #self.wavelength_ctl.SetValue(str(self.wavelength))
     except:
         if self.base is not None:
             msg = "SLD Calculator: %s" % (sys.exc_value)
             wx.PostEvent(self.base, StatusEvent(status=msg))
     if event is not None:
         event.Skip()
예제 #2
0
 def calculateSld(self, event):
     """
         Calculate the neutron scattering density length of a molecule
     """
     self.clear_outputs()
     try:
         #Check validity user inputs
         flag, msg = self.check_inputs()
         if self.base is not None and msg.lstrip().rstrip() != "":
             msg = "SLD Calculator: %s" % str(msg)
             wx.PostEvent(self.base, StatusEvent(status=msg))
         if not flag:
            return
         #get ready to compute
         self.sld_formula = formula(self.compound,
                                         density=self.density)
         (sld_real, sld_im, _), (_, absorp, incoh), \
                     length = neutron_scattering(compound=self.compound,
                                density=self.density,
                                wavelength=self.neutron_wavelength)
         if self.xray_source == "[A]":
             energy = xray_energy(self.xray_source_input)
             xray_real, xray_im = xray_sld_from_atoms(self.sld_formula.atoms,
                                                      density=self.density,
                                                      energy=energy)
         elif self.xray_source == "[keV]":
             xray_real, xray_im = xray_sld_from_atoms(self.sld_formula.atoms,
                                                      density=self.density,
                                                      energy=self.xray_source_input)
         elif self.xray_source == "Element":
             xray_real, xray_im = self.calculate_sld_helper(element=self.xray_source_input,
                                                            density=self.density,
                                                            molecule_formula=self.sld_formula)
         # set neutron sld values
         val = format_number(sld_real * _SCALE)
         self.neutron_sld_real_ctl.SetValue(val)
         val = format_number(math.fabs(sld_im) * _SCALE)
         self.neutron_sld_im_ctl.SetValue(val)
         # Compute the Cu SLD
         self.xray_sld_real_ctl.SetValue(format_number(xray_real * _SCALE))
         val = format_number(math.fabs(xray_im) * _SCALE)
         self.xray_sld_im_ctl.SetValue(val)
         # set incoherence and absorption
         self.neutron_inc_ctl.SetValue(format_number(incoh))
         self.neutron_abs_ctl.SetValue(format_number(absorp))
         # Neutron length
         self.neutron_length_ctl.SetValue(format_number(length))
         # display wavelength
         #self.wavelength_ctl.SetValue(str(self.wavelength))
         #self.wavelength_ctl.SetValue(str(self.wavelength))
     except:
         if self.base is not None:
             msg = "SLD Calculator: %s" % (sys.exc_value)
             wx.PostEvent(self.base, StatusEvent(status=msg))
     if event is not None:
         event.Skip()
예제 #3
0
def calculate_xray_sld(element, density, molecule_formula):
    """
    Get an element and compute the corresponding SLD for a given formula
    :param element:  elements a string of existing atom
    """
    element_formula = formula(str(element))
    if len(element_formula.atoms) != 1:
        return 
    element = element_formula.atoms.keys()[0] 
    energy = xray_energy(element.K_alpha)
    atom = molecule_formula.atoms
    return xray_sld_from_atoms(atom, density=density, energy=energy)
예제 #4
0
def calculate_xray_sld(element, density, molecule_formula):
    """
    Get an element and compute the corresponding SLD for a given formula
    :param element:  elements a string of existing atom
    """
    element_formula = formula(str(element))
    if len(element_formula.atoms) != 1:
        return
    element = next(iter(element_formula.atoms))  # only one element...
    energy = xray_energy(element.K_alpha)
    atom = molecule_formula.atoms
    return xray_sld_from_atoms(atom, density=density, energy=energy)
예제 #5
0
    def calculate_sld_helper(self, element, density, molecule_formula):
        """
        Get an element and compute the corresponding SLD for a given formula

        :param element:  elements a string of existing atom

        """
        element_formula = formula(str(element))
        if len(element_formula.atoms) != 1:
            return
        element = element_formula.atoms.keys()[0]
        energy = xray_energy(element.K_alpha)
        atom = molecule_formula.atoms
        return xray_sld_from_atoms(atom, density=density, energy=energy)
예제 #6
0
    def calculate_xray_sld(self, element):
        """
        Get an element and compute the corresponding SLD for a given formula

        :param element:  elements a string of existing atom

        """
        myformula = formula(str(element))
        if len(myformula.atoms) != 1:
            return
        element = myformula.atoms.keys()[0]
        energy = xray_energy(element.K_alpha)

        self.sld_formula = formula(str(self.compound), density=self.density)
        atom = self.sld_formula.atoms
        return xray_sld_from_atoms(atom, density=self.density, energy=energy)
예제 #7
0
    def calculate_xray_sld(self, element):
        """
        Get an element and compute the corresponding SLD for a given formula

        :param element:  elements a string of existing atom

        """
        myformula = formula(str(element))
        if len(myformula.atoms) != 1:
            return
        element = myformula.atoms.keys()[0]
        energy = xray_energy(element.K_alpha)

        self.sld_formula = formula(str(self.compound), density=self.density)
        atom = self.sld_formula.atoms
        return xray_sld_from_atoms(atom, density=self.density, energy=energy)
예제 #8
0
    def calculate_xray_sld(self, element):
        """
        Get an element and compute the corresponding SLD for a given formula

        :param element:  elements a string of existing atom

        """
        # TODO: use periodictable.elements object
        #    energy = xray_energy(periodictable.elements[element].K_alpha)
        # TODO: code is very similar to sld helper
        myformula = formula(str(element))
        if len(myformula.atoms) != 1:
            return
        element = list(myformula.atoms.keys())[0]
        energy = xray_energy(element.K_alpha)

        self.sld_formula = formula(str(self.compound), density=self.density)
        atom = self.sld_formula.atoms
        return xray_sld_from_atoms(atom, density=self.density, energy=energy)
예제 #9
0
tstart_cpu = time.clock()   # start the CPU timer


E = 12			# Energy in keV

M = 'Be'		# Material 
R = 50			# CRL radius of curvature 
N = 40			# number of refractive lens 


M = getattr(pt, '%s'%M)							# I dont know how, but 'eval' - not good idea!)
name = getattr(pt.elements, '%s'%M).name		# name of element
density = M.density								# density
mass = M.mass									# mass of element

lyamda = ptx.xray_energy(E)
n = ptx.index_of_refraction(M, energy=E)		# index of refraction
delta = 1-n.real								# Delta
beta = -n.imag									# Beta
u = 4*np.pi*beta/(lyamda*1e-10)					# Linear attenuation coefficient
Lpi = 1e-10*lyamda/(2*delta)


F = (R*1e-6)/(2*N*delta)							# CRL focus distance (thin lens)
e1 = (2*np.log(2)/np.pi)**.5					# V.Kohn coefficient
Aeff = e1*(F*lyamda*1e-10*delta/beta)**.5		# CRL effective aperture (V.Kohn)
Aeff_1m = e1*(1*lyamda*1e-10*delta/beta)**.5	# CRL effective aperture @ 1m focus distance

print ('Material	%s (%s)'%(M, name))
print ('Density		%s g/cm^3'%density)
예제 #10
0
def cgi_call():
    form = cgi.FieldStorage()
    #print >>sys.stderr, form
    #print >>sys.stderr, "sample",form.getfirst('sample')
    #print >>sys.stderr, "mass",form.getfirst('mass')
    
    # Parse inputs
    errors = {};
    calculate = form.getfirst('calculate','all')
    if calculate not in ('scattering','activation','all'):
        errors['calculate'] = "calculate should be one of 'scattering', 'activation' or 'all'"
    try: chem = formula(form.getfirst('sample'))
    except: errors['sample'] = error()
    try: fluence = float(form.getfirst('flux',100000))
    except: errors['flux'] = error()
    try: fast_ratio = float(form.getfirst('fast','0'))
    except: errors['fast'] = error()
    try: Cd_ratio = float(form.getfirst('Cd','0'))
    except: errors['Cd'] = error()
    try: exposure = parse_hours(form.getfirst('exposure','1'))
    except: errors['exposure'] = error()
    try: 
        mass_str = form.getfirst('mass','1')
        if mass_str.endswith('kg'):
           mass = 1000*float(mass_str[:-2])
        elif mass_str.endswith('mg'):
           mass = 0.001*float(mass_str[:-2])
        elif mass_str.endswith('ug'):
           mass = 1e-6*float(mass_str[:-2])
        elif mass_str.endswith('g'):
           mass = float(mass_str[:-1])
        else:
           mass = float(mass_str)
    except: errors['mass'] = error()
    try: density_type,density_value = parse_density(form.getfirst('density','0'))
    except: errors['density'] = error()
    try: 
        #print >>sys.stderr,form.getlist('rest[]')
        rest_times = [parse_rest(v) for v in form.getlist('rest[]')]
        if not rest_times: rest_times = [0,1,24,360]
    except: errors['rest'] = error()
    try: decay_level = float(form.getfirst('decay','0.001'))
    except: errors['decay'] = error()
    try: thickness = float(form.getfirst('thickness', '1'))
    except: errors['thickness'] = error()
    try:
        wavelength_str = form.getfirst('wavelength','1').strip()
        if wavelength_str.endswith('meV'):
             wavelength = nsf.neutron_wavelength(float(wavelength_str[:-3]))
        elif wavelength_str.endswith('m/s'):
             wavelength = nsf.neutron_wavelength_from_velocity(float(wavelength_str[:-3]))
        elif wavelength_str.endswith('Ang'):
             wavelength = float(wavelength_str[:-3])
        else:
             wavelength = float(wavelength_str)
        #print >>sys.stderr,wavelength_str
    except: errors['wavelength'] = error()
    try:
        xray_source = form.getfirst('xray','Cu Ka').strip()
        if xray_source.endswith('Ka'):
            xray_wavelength = elements.symbol(xray_source[:-2].strip()).K_alpha
        elif xray_source.endswith('keV'):
            xray_wavelength = xsf.xray_wavelength(float(xray_source[:-3]))
        elif xray_source.endswith('Ang'):
            xray_wavelength = float(xray_source[:-3])
        elif xray_source[0].isalpha():
            xray_wavelength = elements.symbol(xray_source).K_alpha
        else:
            xray_wavelength = float(xray_source)
        #print >>sys.stderr,"xray",xray_source,xray_wavelength
    except: errors['xray'] = error()
    try:
        abundance_source = form.getfirst('abundance','IAEA')
        if abundance_source == "NIST":
            abundance = activation.NIST2001_isotopic_abundance
        elif abundance_source == "IAEA":
            abundance = activation.IAEA1987_isotopic_abundance
        else:
            raise ValueError("abundance should be NIST or IAEA")
    except: errors['abundance'] = error()
        

    if errors: return {'success':False, 'error':'invalid request', 'detail':errors}

    # Fill in defaults
    #print >>sys.stderr,density_type,density_value,chem.density
    if density_type == 'default' or density_value == 0:
        # default to a density of 1
        if chem.density is None: chem.density = 1
    elif density_type == 'volume':
        chem.density = chem.molecular_mass/density_value
    elif density_type == 'natural':
        # if density is given, assume it is for natural abundance
        chem.natural_density = density_value
    elif density_type == 'isotope':
        chem.density = density_value
    else:
        raise ValueError("unknown density type %r"%density_type)

    result = {'success': True}
    result['sample'] = {
            'formula': str(chem),
            'mass': mass,
            'density': chem.density,
            'thickness': thickness,
            'natural_density': chem.natural_density,
        }
        
    # Run calculations
    if calculate in ('activation', 'all'):
      try:
        env = activation.ActivationEnvironment(fluence=fluence,fast_ratio=fast_ratio, Cd_ratio=Cd_ratio)
        sample = activation.Sample(chem, mass=mass)
        sample.calculate_activation(env,exposure=exposure,rest_times=rest_times,abundance=abundance)
        decay_time = sample.decay_time(decay_level)
        total = [0]*len(sample.rest_times)
        rows = []
        for el,activity_el in activation.sorted_activity(sample.activity.items()):
            total = [t+a for t,a in zip(total,activity_el)]
            rows.append({'isotope':el.isotope,'reaction':el.reaction,'product':el.daughter,
                         'halflife':el.Thalf_str,'comments':el.comments,'levels':activity_el})
        result['activation'] = {
            'flux': fluence,
            'fast': fast_ratio,
            'Cd': Cd_ratio,
            'exposure': exposure,
            'rest': rest_times,
            'activity': rows, 
            'total': total,
            'decay_level': decay_level,
            'decay_time': decay_time,
        }
        #print >>sys.stderr,result
      except:
        result['activation'] = {"error": error()}
        
    #nsf_sears.replace_neutron_data()
    if calculate in ('scattering', 'all'):
      try: 
        sld,xs,penetration = neutron_scattering(chem, wavelength=wavelength)
        result['scattering'] = {
            'neutron': {
                'wavelength': wavelength,
                'energy': nsf.neutron_energy(wavelength),
                'velocity': nsf.VELOCITY_FACTOR/wavelength,
            },
            'xs': {'coh': xs[0], 'abs': xs[1], 'incoh': xs[2]},
            'sld': {'real': sld[0], 'imag': sld[1], 'incoh': sld[2]},
            'penetration': penetration,
            'transmission': 100*exp(-thickness/penetration),
        }
        
      except:
        missing = [str(el) for el in chem.atoms if not el.neutron.has_sld()]
        if any(missing):
            msg = "missing neutron cross sections for "+", ".join(missing)
        else:
            msg = error()
        result['scattering'] = {'error': msg }


      try: 
        xsld = xray_sld(chem, wavelength=xray_wavelength) 
        result['xray_scattering'] = {
            'xray': {
                'wavelength': xray_wavelength,
                'energy': xsf.xray_energy(xray_wavelength),
            },
            'sld': {'real': xsld[0], 'imag': xsld[1]},
        }
      except: 
        result['xray_scattering'] = {'error': error()}

    return result
예제 #11
0
def test_xsf():

    # Check some K_alpha and K_beta1 values
    assert Cu.K_alpha == 1.5418
    assert Cu.K_beta1 == 1.3922

    # Check scalar scattering factor lookup
    f1,f2 = Ni.xray.scattering_factors(energy=xray_energy(Cu.K_alpha))
    assert abs(f1-25.0229)<0.0001
    assert abs(f2-0.5249)<0.0001

    # Check array scattering factor lookup
    f1,f2 = Ni.xray.scattering_factors(wavelength=Cu.K_alpha)
    m1,m2 = Ni.xray.scattering_factors(wavelength=Mo.K_alpha)
    B1,B2 = Ni.xray.scattering_factors(wavelength=[Cu.K_alpha,Mo.K_alpha])
    assert (B1==[f1,m1]).all() and (B2==[f2,m2]).all()

    # Check that we can lookup sld by wavelength and energy
    Fe_rho,Fe_mu = Fe.xray.sld(wavelength=Cu.K_alpha)
    assert abs(Fe_rho-59.45) < 0.01
    Si_rho,Si_mu = Si.xray.sld(energy=8.050)
    assert abs(Si_rho-20.0701) < 0.0001
    assert abs(Si_mu-0.4572) < 0.0001

    # Check that wavelength is the default
    Fe_rho_default,Fe_mu_default = Fe.xray.sld(wavelength=Cu.K_alpha)
    assert Fe_rho == Fe_rho_default and Fe_mu == Fe_mu_default

    # Check array form of sld lookup
    f1,f2 = Si.xray.sld(wavelength=Cu.K_alpha)
    m1,m2 = Si.xray.sld(wavelength=Mo.K_alpha)
    B1,B2 = Si.xray.sld(wavelength=[Cu.K_alpha,Mo.K_alpha])
    assert (B1==[f1,m1]).all() and (B2==[f2,m2]).all()

    # Check energy conversion is consistent
    f1,f2 = Si.xray.sld(energy=xray_energy(Cu.K_alpha))
    m1,m2 = Si.xray.sld(energy=xray_energy(Mo.K_alpha))
    assert (B1==[f1,m1]).all() and (B2==[f2,m2]).all()
    B1,B2 = Si.xray.sld(energy=xray_energy([Cu.K_alpha,Mo.K_alpha]))
    assert (B1==[f1,m1]).all() and (B2==[f2,m2]).all()

    #print Cu.xray.sftable
    #plot_xsf(Cu)
    #emission_table()
    #sld_table(table,Cu.K_alpha)

    """
    # Table of scattering length densities for various molecules
    for molecule,density in [('SiO2',2.2),('B4C',2.52)]:
        atoms = formula(molecule).atoms
        rho,mu = xray_sld(atoms,density,wavelength=Cu.K_alpha)
        print "sld for %s(%g g/cm**3)  rho=%.4g mu=%.4g"\
            %(molecule,density,rho,mu)
    """

    # Cross check against mo
    rho,mu = xray_sld({Si:1},density=Si.density,wavelength=1.54)
    rhoSi,muSi = Si.xray.sld(wavelength=1.54)
    assert abs(rho - rhoSi) < 1e-14
    assert abs(mu - muSi) < 1e-14

    # Check that xray_sld works as expected
    atoms = formula('SiO2').atoms
    rho,mu = xray_sld(atoms,density=2.2,energy=xray_energy(Cu.K_alpha))
    assert abs(rho-18.87)<0.1
    atoms = formula('B4C').atoms
    rho,mu = xray_sld(atoms,density=2.52,energy=xray_energy(Cu.K_alpha))
    assert abs(rho-20.17)<0.1

    F = formula('', density=0)
    rho,mu = xray_sld('', density=0, wavelength=Cu.K_alpha)
    assert rho==mu==0

    # Check natural density calculations
    D2O_density = (2*D.mass + O.mass)/(2*H.mass + O.mass)
    rho,mu = xray_sld('D2O',natural_density=1,wavelength=1.54)
    rho2,mu2 = xray_sld('D2O',density=D2O_density,wavelength=1.54)
    assert abs(rho-rho2)<1e-14 and abs(mu-mu2)<1e-14


    # Check f0 calculation for scalar, vector, array and empty
    Q1,Q2 = 4*pi/Cu.K_alpha, 4*pi/Mo.K_alpha
    f0 = Ni.xray.f0(Q=Q1)
    assert abs(f0-10.11303) < 0.00001
    assert isnan(Ni.xray.f0(Q=7*4*pi))

    f0 = Ni.xray.f0(Q=Q1)
    m0 = Ni.xray.f0(Q=Q2)
    B0 = Ni.xray.f0(Q=[Q1,Q2])
    assert (B0==[f0,m0]).all()


    f0 = Ni.xray.f0(Q=[])
    assert len(f0) == 0

    f0 = Ni.xray.f0(Q=[[1,2],[3,4]])
    assert abs(f0[0,0] - Ni.xray.f0(1)) < 1e-14
    assert abs(f0[0,1] - Ni.xray.f0(2)) < 1e-14
    assert abs(f0[1,0] - Ni.xray.f0(3)) < 1e-14
    assert abs(f0[1,1] - Ni.xray.f0(4)) < 1e-14

    # Check f0 calculation for ion
    Ni_2p_f0 = Ni.ion[2].xray.f0(Q=Q1)
    assert abs(Ni_2p_f0-10.09535) < 0.00001
    Ni58_2p_f0 = Ni[58].ion[2].xray.f0(Q=Q1)
    assert Ni_2p_f0 == Ni58_2p_f0

    # The following test is implementation specific, and is not guaranteed
    # to succeed if the extension interface changes.
    assert '_xray' not in Ni[58].__dict__
예제 #12
0
def test_xsf():

    # Check some K_alpha and K_beta1 values
    assert Cu.K_alpha == 1.5418
    assert Cu.K_beta1 == 1.3922

    # Check scalar scattering factor lookup
    f1, f2 = Ni.xray.scattering_factors(energy=xray_energy(Cu.K_alpha))
    assert abs(f1 - 25.0229) < 0.0001
    assert abs(f2 - 0.5249) < 0.0001

    # Check array scattering factor lookup
    f1, f2 = Ni.xray.scattering_factors(wavelength=Cu.K_alpha)
    m1, m2 = Ni.xray.scattering_factors(wavelength=Mo.K_alpha)
    B1, B2 = Ni.xray.scattering_factors(wavelength=[Cu.K_alpha, Mo.K_alpha])
    assert (B1 == [f1, m1]).all() and (B2 == [f2, m2]).all()

    # Check that we can lookup sld by wavelength and energy
    Fe_rho, Fe_mu = Fe.xray.sld(wavelength=Cu.K_alpha)
    assert abs(Fe_rho - 59.45) < 0.01
    Si_rho, Si_mu = Si.xray.sld(energy=8.050)
    assert abs(Si_rho - 20.0701) < 0.0001
    assert abs(Si_mu - 0.4572) < 0.0001

    # Check that wavelength is the default
    Fe_rho_default, Fe_mu_default = Fe.xray.sld(wavelength=Cu.K_alpha)
    assert Fe_rho == Fe_rho_default and Fe_mu == Fe_mu_default

    # Check array form of sld lookup
    f1, f2 = Si.xray.sld(wavelength=Cu.K_alpha)
    m1, m2 = Si.xray.sld(wavelength=Mo.K_alpha)
    B1, B2 = Si.xray.sld(wavelength=[Cu.K_alpha, Mo.K_alpha])
    assert (B1 == [f1, m1]).all() and (B2 == [f2, m2]).all()

    # Check energy conversion is consistent
    f1, f2 = Si.xray.sld(energy=xray_energy(Cu.K_alpha))
    m1, m2 = Si.xray.sld(energy=xray_energy(Mo.K_alpha))
    assert (B1 == [f1, m1]).all() and (B2 == [f2, m2]).all()
    B1, B2 = Si.xray.sld(energy=xray_energy([Cu.K_alpha, Mo.K_alpha]))
    assert (B1 == [f1, m1]).all() and (B2 == [f2, m2]).all()

    #print Cu.xray.sftable
    #plot_xsf(Cu)
    #emission_table()
    #sld_table(table,Cu.K_alpha)
    """
    # Table of scattering length densities for various molecules
    for molecule,density in [('SiO2',2.2),('B4C',2.52)]:
        atoms = formula(molecule).atoms
        rho,mu = xray_sld(atoms,density,wavelength=Cu.K_alpha)
        print "sld for %s(%g g/cm**3)  rho=%.4g mu=%.4g"\
            %(molecule,density,rho,mu)
    """

    # Cross check against mo
    rho, mu = xray_sld({Si: 1}, density=Si.density, wavelength=1.54)
    rhoSi, muSi = Si.xray.sld(wavelength=1.54)
    assert abs(rho - rhoSi) < 1e-14
    assert abs(mu - muSi) < 1e-14

    # Check that xray_sld works as expected
    atoms = formula('SiO2').atoms
    rho, mu = xray_sld(atoms, density=2.2, energy=xray_energy(Cu.K_alpha))
    assert abs(rho - 18.87) < 0.1
    atoms = formula('B4C').atoms
    rho, mu = xray_sld(atoms, density=2.52, energy=xray_energy(Cu.K_alpha))
    assert abs(rho - 20.17) < 0.1

    F = formula('', density=0)
    rho, mu = xray_sld('', density=0, wavelength=Cu.K_alpha)
    assert rho == mu == 0

    # Check natural density calculations
    D2O_density = (2 * D.mass + O.mass) / (2 * H.mass + O.mass)
    rho, mu = xray_sld('D2O', natural_density=1, wavelength=1.54)
    rho2, mu2 = xray_sld('D2O', density=D2O_density, wavelength=1.54)
    assert abs(rho - rho2) < 1e-14 and abs(mu - mu2) < 1e-14

    # Check f0 calculation for scalar, vector, array and empty
    Q1, Q2 = 4 * pi / Cu.K_alpha, 4 * pi / Mo.K_alpha
    f0 = Ni.xray.f0(Q=Q1)
    assert abs(f0 - 10.11303) < 0.00001
    assert isnan(Ni.xray.f0(Q=7 * 4 * pi))

    f0 = Ni.xray.f0(Q=Q1)
    m0 = Ni.xray.f0(Q=Q2)
    B0 = Ni.xray.f0(Q=[Q1, Q2])
    assert (B0 == [f0, m0]).all()

    f0 = Ni.xray.f0(Q=[])
    assert len(f0) == 0

    f0 = Ni.xray.f0(Q=[[1, 2], [3, 4]])
    assert f0[0, 0] == Ni.xray.f0(1)
    assert f0[0, 1] == Ni.xray.f0(2)
    assert f0[1, 0] == Ni.xray.f0(3)
    assert f0[1, 1] == Ni.xray.f0(4)

    # Check f0 calculation for ion
    Ni_2p_f0 = Ni.ion[2].xray.f0(Q=Q1)
    assert abs(Ni_2p_f0 - 10.09535) < 0.00001
    Ni58_2p_f0 = Ni[58].ion[2].xray.f0(Q=Q1)
    assert Ni_2p_f0 == Ni58_2p_f0

    # The following test is implementation specific, and is not guaranteed
    # to succeed if the extension interface changes.
    assert '_xray' not in Ni[58].__dict__