def from_string(text, xray_database: TransitionDatabase):
        """
        Returns a wavelength parsed from a text in units of Angstrom
        :param text:
        :param xray_database:
        :return:
        """
        if any([emisson_line in text
                for emisson_line in EMISSON_LINES.keys()]):
            for emisson_line in EMISSON_LINES.keys():
                if not emisson_line in text:
                    continue

                element = text.replace(emisson_line, '').strip()
                transitions = xray_database.get_all_transitions(
                    element, EMISSON_LINES[emisson_line])
                if len(transitions) != 1:
                    raise WavelengthError(
                        f"Unknown transition line for '{text}'")
                # transition db returns in eV, xray-wavelength expects keV
                return xray_wavelength(
                    transitions[EMISSON_LINES[emisson_line]]['experimental'] *
                    1e-3)

        try:
            if 'AA' in text or 'Ang' in text:
                wavelength = float(text.replace('AA', '').replace('Ang', ''))
            elif 'eV' in text:
                wavelength = SI.extract_number(text, 'eV')
            else:
                # Now we assume there is no unit, which means it should be Angstrom
                wavelength = float(text)

        except ValueError:
            raise WavelengthError(
                f"Input '{text}' could not be identified as an wavelength")

        if wavelength <= 0:
            raise WavelengthError("Wavelength has to be positive")

        return wavelength
def attenuation_length(compound,
                       density=None,
                       natural_density=None,
                       energy=None,
                       wavelength=None):
    """
    Calculates the attenuation length for a compound
                Transmisison if then exp(-thickness/attenuation_length)

    :Parameters:
        *compound* : Formula initializer
            Chemical formula.
        *density* : float | |g/cm^3|
            Mass density of the compound, or None for default.
        *natural_density* : float | |g/cm^3|
            Mass density of the compound at naturally occurring isotope abundance.
        *wavelength* : float or vector | |Ang|
            Wavelength of the X-ray.
        *energy* : float or vector | keV
            Energy of the X-ray, if *wavelength* is not specified.

    :Returns:
        *attenuation_length* : vector | |m|
            as function of (energy)

    :Notes:

    against http://henke.lbl.gov/optical_constants/
    """
    if energy is not None: wavelength = xray_wavelength(energy)
    assert wavelength is not None, "scattering calculation needs energy or wavelength"
    if (numpy.isscalar(wavelength)): wavelength = numpy.array([wavelength])
    n = index_of_refraction(compound=compound,
                            density=density,
                            natural_density=natural_density,
                            wavelength=wavelength)
    attenuation_length = (wavelength * 1e-10) / (4 * numpy.pi * numpy.imag(n))
    return numpy.abs(attenuation_length)
def xafs_sample_prep_get_abslen(request):
	"""
	Computes the relevant x-ray absorption data.

	POSTDATA:
	
		chem: Element chemical formula.
		ephot: Photon energy (incoming) in keV.
		dens: Compound density in g/cc
		bn: Boron Nitride dilution fraction (between 0-1)

	RETURNS:

		X-ray data as an HTTPresponse string.
	"""

	if request.method == "POST":
		
		res = "<table class='table table-bordered'>"

		try:
			#Get POSTDATA
			chem = str(request.POST['chem'])
			ephot = float(request.POST['ephot'])
			dens = float(request.POST['dens'])
			bn = float(request.POST['bn'])
		except:
			res = "Input format error! Please fix and retry."
			return HttpResponse(res)


		#Parse formula
		form = formula(chem)
		res += "<tr><td>Compound:</td><td>" + chem + "</td></tr>"

		#Compute molecular mass
		mass = 0.0

		for elem in form.atoms:
			mass += form.atoms[elem]*elem.mass 

		res += "<tr><td>Molecular Mass:</td><td>" + str(round(mass,2)) + " g/mol </td></tr>"

		#Compute total mu
		mu = 0.0
		r_e = 2.8179403E-13 #cm
		N_a = 6.02214E23
		for elem in form.atoms:
			frac = (form.atoms[elem]*elem.mass) / mass
			xr = xsf.Xray(elem)
			xsec = 2*r_e*xsf.xray_wavelength(ephot)*1E-8*xr.scattering_factors(energy=ephot)[1]*(N_a/elem.mass)
			mu += frac * xsec

		#Perform dilution with BN if needed
		if str(bn) != "" and 0 < bn < 1:
			bn_mass = B.mass + N.mass
			bn_dens = 2.29 #source: Sigma-Aldrich, BN powder ~1 micron, 98%
			frac_b = B.mass / bn_mass
			frac_n = N.mass / bn_mass

			dens = (1 - bn) * dens + bn * bn_dens

			xr_B = xsf.Xray(B)
			xsec_B = 2*r_e*xsf.xray_wavelength(ephot)*1E-8*xr_B.scattering_factors(energy=ephot)[1]*(N_a/B.mass)
			xr_N = xsf.Xray(N)
			xsec_N = 2*r_e*xsf.xray_wavelength(ephot)*1E-8*xr_N.scattering_factors(energy=ephot)[1]*(N_a/N.mass)

			mu_bn = frac_b * xsec_B + frac_n * xsec_N
			mu = (1 - bn) * mu + bn * mu_bn

			res += "<tr><td>BN Dilution Fraction:</td><td>" + str(bn) + "</td></tr>"

		mu *= dens

		res += "<tr><td>Linear Absorption Coefficient:</td><td>" + str(round(mu,2)) + " 1/cm </td></tr>"

		#Compute absorption length
		abs_length= round((1/mu) * 10000, 2) #microns
		res += "<tr><td>Total X-ray Absorption Length:</td><td>" + str(round(abs_length,2)) + " microns </td></tr>"

		#Compute approx. total mass assuming 0.65 cm radius for pellet (standard size for Pike brand pellet press)
		total_mass = round(dens * (0.65**2) * 3.14159 * (abs_length/10000) * 1000, 2)

		res += "<tr><td>Pellet Mass (13mm diameter):</td><td>" + str(round(total_mass,2)) + " mg</td></tr>"

		res += "</table>"

		return HttpResponse(res)
	else:
		return HttpResponse("POSTdata must be used!")
Esempio n. 4
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