Source code for dabax.dabax_base

"""

dabax: python module for processing remote files containing dabax

"""
from typing import Tuple, List, Any

import numpy
import os
from urllib.request import urlretrieve, build_opener, HTTPSHandler, install_opener
from silx.io.specfile import SpecFile
import ssl

from dabax.common_tools import calculate_f0_from_f0coeff, f0_interpolate_coefficients
from dabax.common_tools import atomic_symbols, atomic_names, atomic_number
from dabax.common_tools import parse_formula

try:
    # create an "unverified" SSL context
    context = ssl.create_default_context()
    context.check_hostname = False
    context.verify_mode = ssl.CERT_NONE

    # build and install an opener that uses the unverified context for HTTPS
    install_opener(build_opener(HTTPSHandler(context=context)))
except:
    pass


[docs]class Functions: """Registry of DABAX data-file function types used to select parsing mode.""" f0 = "f0" f1f2 = "f1f2" CrossSec = "CrossSec" Crystals = "Crystals" AtomicWeights = "AtomicWeights" AtomicConstants = "AtomicConstants"
[docs] @staticmethod def get_mode(function): """Return the parsing mode (0=column, 1=entry) for the given function type.""" return 0 if function in [Functions.f0, Functions.AtomicConstants] else 1
[docs]class DabaxBase(object): """ Base class providing access to DABAX data files (local or remote). Handles downloading, caching, and parsing of SPEC-format DABAX files for f0, f1f2, cross-sections, crystal structures, and atomic data. """ def __init__(self, dabax_repository=None, verbose=False, file_f0="f0_InterTables.dat", file_f1f2="f1f2_Windt.dat", file_CrossSec = "CrossSec_EPDL97.dat", file_Crystals="Crystals.dat", file_AtomicWeights="AtomicWeights.dat", file_AtomicConstants="AtomicConstants.dat", ): """ Parameters ---------- dabax_repository : str, optional URL or local path to the DABAX file repository. Defaults to the official GitHub raw URL. verbose : bool, optional Print file access messages. file_f0 : str, optional Name of the f0 data file. file_f1f2 : str, optional Name of the f1/f2 data file. file_CrossSec : str, optional Name of the cross-section data file. file_Crystals : str, optional Name of the crystal structures data file. file_AtomicWeights : str, optional Name of the atomic weights data file. file_AtomicConstants : str, optional Name of the atomic constants data file. """ self._dabax_repository = dabax_repository if not dabax_repository is None else self.get_dabax_default_repository() self._verbose = verbose self._spec_file_registry = {} self._modes = {} self.set_file_f0(file_f0) self.set_file_f1f2(file_f1f2) self.set_file_CrossSec(file_CrossSec) self.set_file_Crystals(file_Crystals) self.set_file_AtomicWeights(file_AtomicWeights) self.set_file_AtomicConstants(file_AtomicConstants) def _register_file(self, filename, function): spec_file = SpecFile(self.get_dabax_file(filename)) entries = DabaxBase._get_entries(spec_file, Functions.get_mode(function)) self._spec_file_registry[filename] = [spec_file, entries] return spec_file, entries def _get_registered_spec_file(self, filename, function): data = self._spec_file_registry.get(filename, [None, None]) spec_file = data[0] entries = data[1] if not spec_file is None: return spec_file, entries else: return self._register_file(filename, function) @staticmethod def _get_index_of_entry(entries: Tuple, entry_name: str) -> int: try: return entries.index(entry_name) except: return -1 @staticmethod def _get_entries(spec_file : SpecFile, mode=0) -> Tuple: entries = [] for index in range(len(spec_file)): s1 = spec_file[index] name = s1.scan_header_dict["S"] if mode == 0: try: entries.append(name.split(' ')[1]) except: pass elif mode == 1: name = ' '.join(name.split()) try: entries.append(name.split(' ')[1]) except: pass return entries @staticmethod def _get_data_and_labels(spec_file: SpecFile, entries: Tuple, entry_name, verbose=False, filename=None): index_found = DabaxBase._get_index_of_entry(entries, entry_name) flag_found = index_found != -1 if not flag_found and verbose: print("Entry name %s not found in DABAX file: %s" % (entry_name, filename)) return None, None, -1 data = spec_file[index_found].data labels = spec_file[index_found].labels return data, labels, index_found @staticmethod def _get_interesting_entries(entries: Tuple, symbol: str) -> Tuple[List[Any], List[Any], List[Any]]: interesting_entries = [] charge_list = [] index_list = [] for i, entry in enumerate(entries): if entry.find(symbol) == 0: if entry == symbol: interesting_entries.append(entry) charge_list.append(0.0) index_list.append(i) else: entry2 = entry.replace(symbol, '') try: charge_item = int(entry2[::-1]) # convert to integer the reversed string charge_list.append(charge_item) interesting_entries.append(entry) index_list.append(i) except: pass return charge_list, index_list, interesting_entries @staticmethod def _get_coefficient_list(spec_file: SpecFile, index_list: Tuple[int]): return [spec_file[i].data[:, 0] for i in index_list]
[docs] def get_dabax_default_repository(self): """Return the default remote DABAX repository URL.""" return "https://raw.githubusercontent.com/oasys-kit/DabaxFiles/main/"
[docs] def set_dabax_repository(self, repo): """Set the DABAX repository URL or local path.""" self._dabax_repository = repo
[docs] def get_dabax_repository(self): """Return the current DABAX repository URL or local path.""" return self._dabax_repository
[docs] def set_verbose(self, value=True): """Enable or disable verbose output.""" self._verbose = value
[docs] def verbose(self): """Return the verbose flag.""" return self._verbose
[docs] def set_file_f0(self, filename): """Set and register the f0 data file.""" self._file_f0 = filename self._sf_f0, self._sf_f0_entries = self._register_file(self._file_f0, Functions.f0)
[docs] def get_file_f0(self): """Return the current f0 data file name.""" return self._file_f0
[docs] def set_file_f1f2(self, filename): """Set and register the f1/f2 data file.""" self._file_f1f2 = filename self._sf_f1f2, self._sf_f1f2_entries = self._register_file(self._file_f1f2, Functions.f1f2)
[docs] def get_file_f1f2(self): """Return the current f1/f2 data file name.""" return self._file_f1f2
[docs] def set_file_CrossSec(self, filename): """Set and register the cross-section data file.""" self._file_CrossSec = filename self._sf_CrossSec, self._sf_CrossSec_entries = self._register_file(self._file_CrossSec, Functions.CrossSec)
[docs] def get_file_CrossSec(self): """Return the current cross-section data file name.""" return self._file_CrossSec
[docs] def set_file_Crystals(self, filename): """Set and register the crystal structures data file.""" self._file_Crystals = filename self._sf_Crystals, self._sf_Crystals_entries = self._register_file(self._file_Crystals, Functions.Crystals)
[docs] def get_file_Crystals(self): """Return the current crystal structures data file name.""" return self._file_Crystals
[docs] def set_file_AtomicWeights(self, filename): """Set and register the atomic weights data file.""" self._file_AtomicWeights = filename self._sf_AtomicWeights, self._sf_AtomicWeights_entries = self._register_file(self._file_AtomicWeights, Functions.AtomicWeights)
[docs] def get_file_AtomicWeights(self) -> str: """Return the current atomic weights data file name.""" return self._file_AtomicWeights
[docs] def set_file_AtomicConstants(self, filename): """Set and register the atomic constants data file.""" self._file_AtomicConstants = filename self._sf_AtomicConstants, self._sf_AtomicConstants_entries = self._register_file(self._file_AtomicConstants, Functions.AtomicConstants)
[docs] def get_file_AtomicConstants(self): """Return the current atomic constants data file name.""" return self._file_AtomicConstants
[docs] def info(self): """Return a formatted string summarising the current DABAX configuration.""" txt = "################ DABAX info ###########\n" txt += "dabax repository: %s\n" % self.get_dabax_repository() txt += "dabax f0 file: %s\n" % self.get_file_f0() txt += "dabax f1f2 file: %s\n" % self.get_file_f1f2() txt += "dabax CrossSec file: %s\n" % self.get_file_CrossSec() txt += "dabax Crystals file: %s\n" % self.get_file_Crystals() txt += "########################################\n" return txt
[docs] def is_remote(self): """Return True if the repository is a remote URL.""" if "http" in self.dabax_repository: return True else: return False
######################### # common access tools #########################
[docs] def get_dabax_file(self, filename): """ Return the local path to a DABAX file, downloading it first if necessary. Parameters ---------- filename : str DABAX file name (e.g. ``"f0_InterTables.dat"``). Returns ------- str Absolute local filesystem path to the file. """ # # file exists in current directory # dabax_repository = self.get_dabax_repository() # Use a default writable directory filepath = os.path.join(get_dabax_directory(), os.path.basename(filename)) # extra safety if os.path.exists(filepath): if self.verbose(): print("Dabax file exists in local directory: %s " % filepath) return filepath # # download remote file # if dabax_repository[0:3] == "htt" or dabax_repository[0:3] == "ftp": try: filepath, http_msg = urlretrieve(dabax_repository + filename, filename=filepath, reporthook=None, data=None) if self.verbose(): print("Dabax file %s downloaded from %s" % (filepath, dabax_repository + filename)) wait_until_downloaded(filepath) return filepath except: try: # in case there are write permissions issues filepath, http_msg = urlretrieve(dabax_repository + filename, filename=None, # will create a temp file reporthook=None, data=None) if self.verbose(): print("Dabax file %s downloaded from %s" % (filepath, dabax_repository + filename)) wait_until_downloaded(filepath) return filepath except: raise Exception("Failed to download file %s from %s" % (filename, dabax_repository)) # # file exists in local repository # filepath = os.path.join(dabax_repository, filename) if os.path.exists(filepath): if self.verbose(): print("Dabax file exists in local directory: %s " % filepath) return filepath print("Error trying to access file: %s" % filepath) raise Exception(FileNotFoundError)
######################### # f0 #########################
[docs] def get_f0_coeffs_from_dabax_file(self, entry_name="Y3+"): """ Return the f0 parametric coefficients for a given element or ion. Parameters ---------- entry_name : str, optional Element symbol or ion (e.g. ``"Si"``, ``"Y3+"``). Default ``"Y3+"``. Returns ------- numpy.ndarray Array of f0 coefficients, or empty list if not found. """ filename = self.get_file_f0() spec_file, entries = self._get_registered_spec_file(filename, Functions.f0) data, _, _ = DabaxBase._get_data_and_labels(spec_file, entries, entry_name, verbose=self.verbose(), filename=filename) if not data is None: return data[:, 0] else: return []
[docs] def f0_with_fractional_charge(self, Z, charge=0.0): """ Return f0 coefficients for element Z at a given (possibly fractional) ionic charge. Parameters ---------- Z : int Atomic number. charge : float, optional Ionic charge. Interpolates between tabulated values when non-integer. Returns ------- numpy.ndarray f0 coefficient array. """ symbol = atomic_symbols()[Z] if charge == 0.0: return self.get_f0_coeffs_from_dabax_file(entry_name=symbol) else: spec_file, entries = self._get_registered_spec_file(self.get_file_f0(), Functions.f0) charge_list, index_list, _ = DabaxBase._get_interesting_entries(entries, symbol) return f0_interpolate_coefficients(charge, charge_list, DabaxBase._get_coefficient_list[spec_file, index_list])
# # # def _f0_with_fractional_charge_get_entries(self, Z, charge=0.0): symbol = atomic_symbols()[Z] if charge == 0.0: return None else: spec_file, entries = self._get_registered_spec_file(self.get_file_f0(), Functions.f0) charge_list, index_list, interesting_entries = DabaxBase._get_interesting_entries(entries, symbol) return interesting_entries, charge_list, DabaxBase._get_coefficient_list(spec_file, index_list) ###################### # f1f2 ######################
[docs] def f1f2_extract(self, entry_name="Y3+"): """ Extract raw f1/f2 tabulated data from the DABAX file. Parameters ---------- entry_name : str, optional Element symbol or ion. Default ``"Y3+"``. Returns ------- energy_in_eV : numpy.ndarray Photon energies in eV. f1 : numpy.ndarray Real part of the anomalous scattering factor. f2 : numpy.ndarray Imaginary part of the anomalous scattering factor. """ filename = self.get_file_f1f2() spec_file, entries = self._get_registered_spec_file(filename, Functions.f1f2) data, _, _ = DabaxBase._get_data_and_labels(spec_file, entries, entry_name, verbose=self.verbose(), filename=filename) # energy energy_in_eV = data[0,:].copy() if filename == 'f1f2_asf_Kissel.dat' or \ filename == 'f1f2_Chantler.dat': if self.verbose(): print('f1f2_extract: Changing Energy from keV to eV for DABAX file '+filename) energy_in_eV *= 1e3 # f1f2 if filename == 'f1f2_asf_Kissel.dat': f1 = data[4,:].copy() f2 = numpy.abs(data[1,:].copy()) else: f1 = data[1,:].copy() f2 = data[2,:].copy() return energy_in_eV, f1, f2
[docs] def f1f2_interpolate(self, entry_name, energy, method=2, # 0: lin-lin, 1=lin-log, 2=log-lin, 3:log-log ): """ Interpolate f1/f2 at given photon energy values. Parameters ---------- entry_name : str Element symbol or ion. energy : float or numpy.ndarray Photon energy in eV. method : int, optional Interpolation method: 0=lin-lin, 1=lin-log, 2=log-lin (default), 3=log-log. Returns ------- f1_interpolated : float or numpy.ndarray f2_interpolated : float or numpy.ndarray """ energy0, f1, f2 = self.f1f2_extract(entry_name) if method == 0: f1_interpolated = numpy.interp(energy, energy0, f1) f2_interpolated = numpy.interp(energy, energy0, f2) elif method == 1: f1_interpolated = 10 ** numpy.interp((energy), (energy0), numpy.log10(f1)) f2_interpolated = 10 ** numpy.interp((energy), (energy0), numpy.log10(f2)) elif method == 2: f1_interpolated = numpy.interp(numpy.log10(energy), numpy.log10(energy0), f1) f2_interpolated = numpy.interp(numpy.log10(energy), numpy.log10(energy0), f2) elif method == 3: f1_interpolated = 10 ** numpy.interp(numpy.log10(energy), numpy.log10(energy0), numpy.log10(f1)) f2_interpolated = 10 ** numpy.interp(numpy.log10(energy), numpy.log10(energy0), numpy.log10(f2)) else: raise ValueError(f"Method {method} not recognized") return f1_interpolated, f2_interpolated
###################### # crosssec ######################
[docs] def crosssec_extract(self, entry_name="Si", partial='TotalCrossSection[barn/atom]'): """ Extract raw cross-section tabulated data from the DABAX file. Parameters ---------- entry_name : str, optional Element symbol. Default ``"Si"``. partial : str, optional Column label for the desired cross-section type. Default ``'TotalCrossSection[barn/atom]'``. Returns ------- energy : numpy.ndarray Photon energies in eV. cs : numpy.ndarray Cross-section values. """ filename = self.get_file_CrossSec() spec_file, entries = self._get_registered_spec_file(filename, Functions.CrossSec) data, labels, index_found = DabaxBase._get_data_and_labels(spec_file, entries, entry_name, verbose=self.verbose(), filename=filename) energy_column_index = next((i for i, label in enumerate(labels) if 'PhotonEnergy' in label), -1) if energy_column_index == -1: raise Exception("Column with PhotonEnergy not found in scan index %d of %s" % (index_found, self.get_file_CrossSec())) cs_column_index = next((i for i, label in enumerate(labels) if partial in label), -1) if cs_column_index == -1: raise Exception("Column with %s not found in scan index %d of %s" % (partial, index_found, self.get_file_CrossSec())) energy = data[energy_column_index, :].copy() cs = data[cs_column_index, :].copy() # print("\n>>>>") if '[EV]' in labels[energy_column_index].upper(): pass elif '[KEV]' in labels[energy_column_index].upper(): energy *= 1e3 # print(">>> energy changed from keV to eV") elif '[MEV]' in labels[energy_column_index].upper(): energy *= 1e6 # print(">>> energy changed from MeV to eV") # print(">>>> %s (col %d)\n %s (col %d): " % (labels[energy_column_index], energy_column_index, labels[cs_column_index], cs_column_index)) return energy, cs
[docs] def crosssec_interpolate(self, entry_name, energy, method=2, # 0: lin-lin, 1=lin-log, 2=log-lin, 3:log-log partial='TotalCrossSection[barn/atom]', ): """ Interpolate cross-section at given photon energy values. Parameters ---------- entry_name : str Element symbol. energy : float or numpy.ndarray Photon energy in eV. method : int, optional Interpolation method: 0=lin-lin, 1=lin-log, 2=log-lin (default), 3=log-log. partial : str, optional Column label for the cross-section type. Returns ------- float or numpy.ndarray Interpolated cross-section value(s). """ out = self.crosssec_extract(entry_name, partial=partial) if out is None: raise Exception("Descriptor %s not in file %s" % (entry_name, self.get_file_CrossSec())) else: energy0, cs = out if method == 0: cs_interpolated = numpy.interp(energy, energy0, cs) elif method == 1: cs_interpolated = 10 ** numpy.interp((energy), (energy0), numpy.log10(cs)) elif method == 2: cs_interpolated = numpy.interp(numpy.log10(energy), numpy.log10(energy0), cs) elif method == 3: cs_interpolated = 10 ** numpy.interp(numpy.log10(energy), numpy.log10(energy0), numpy.log10(cs)) else: raise ValueError(f"Method {method} not recognized") return cs_interpolated
###################### # miscellaneous ######################
[docs] def atomic_weights(self, descriptor, filename="AtomicWeights.dat", ): """ Return atomic weights from DABAX. Parameters ---------- descriptor : str or list of str Element symbol (e.g. ``"Ge"``) or isotope string (e.g. ``"70Ge"``). If a plain symbol is given, the averaged atomic mass is returned. If an isotope prefix is given, the mass of that specific isotope is returned. filename : str, optional DABAX atomic weights file. Default ``"AtomicWeights.dat"``. Returns ------- float or list of float Atomic weight(s) in atomic mass units. """ spec_file, scan_names = self._get_registered_spec_file(filename, Functions.AtomicWeights) if isinstance(descriptor, str): descriptor = [descriptor] descriptor_is_string = 1 else: # is list descriptor_is_string = 0 out = [] for idescriptor in descriptor: flag_found = False index_found = [] for index, scan_name in enumerate(scan_names): if scan_name[-len(idescriptor):] == idescriptor: flag_found = True index_found.append(index) if not flag_found: raise (Exception("Entry name not found: %s" % idescriptor)) data = spec_file[index_found[0]].data if idescriptor[0].isdigit(): out.append(data[0, 0]) else: out.append(data[2, 0]) if descriptor_is_string: return out[0] else: return out
[docs] def atomic_constants(self, descriptor, filename="AtomicConstants.dat", return_item=0, return_label=None, ): """ Return atomic constants from DABAX. Parameters ---------- descriptor : str or list of str Element symbol or list of symbols (e.g. ``"Si"`` or ``["Si", "Fe"]``). filename : str, optional DABAX atomic constants file. Default ``"AtomicConstants.dat"``. return_item : int, optional Column index to return (0–11). Used when ``return_label`` is None. return_label : str, optional Name of the quantity to return. Takes priority over ``return_item``. Accepted values: ``'AtomicRadius'``, ``'CovalentRadius'``, ``'AtomicMass'``, ``'BoilingPoint'``, ``'MeltingPoint'``, ``'Density'``, ``'AtomicVolume'``, ``'CoherentScatteringLength'``, ``'IncoherentX-section'``, ``'Absorption@1.8A'``, ``'DebyeTemperature'``, ``'ThermalConductivity'``. Returns ------- float or list of float Value(s) of the requested atomic constant. Examples -------- >>> dx.atomic_constants('Si', return_label='AtomicMass') 28.0855 """ if isinstance(descriptor, str): descriptor = [descriptor] descriptor_is_string = 1 else: # is list descriptor_is_string = 0 return_index = -1 if return_label is None: return_index = return_item else: if return_label == 'AtomicRadius' : return_index = 0 if return_label == 'CovalentRadius' : return_index = 1 if return_label == 'AtomicMass' : return_index = 2 if return_label == 'BoilingPoint' : return_index = 3 if return_label == 'MeltingPoint' : return_index = 4 if return_label == 'Density' : return_index = 5 if return_label == 'AtomicVolume' : return_index = 6 if return_label == 'CoherentScatteringLength' : return_index = 7 if return_label == 'IncoherentX-section' : return_index = 8 if return_label == 'Absorption@1.8A' : return_index = 9 if return_label == 'DebyeTemperature' : return_index = 10 if return_label == 'ThermalConductivity' : return_index = 11 if return_index == -1: raise Exception("Bad item index") # access spec file spec_file, scan_names = self._get_registered_spec_file(filename, Functions.AtomicConstants) out = [] for idescriptor in descriptor: index = DabaxBase._get_index_of_entry(scan_names, idescriptor) flag_found = index != -1 index_found = index if flag_found: out.append(spec_file[index_found].data[return_index, 0]) else: raise Exception("Data not found for %s " % idescriptor) if descriptor_is_string: return out[0] else: return out
[docs] def element_density(self, descriptor, filename="AtomicConstants.dat"): """ Return the density of an element in g/cm³. Parameters ---------- descriptor : str or list of str Element symbol(s). filename : str, optional DABAX atomic constants file. Returns ------- float or list of float Density in g/cm³. """ return self.atomic_constants(descriptor, filename=filename, return_label="Density")
[docs] def compound_parser(self, descriptor): """ Parse a chemical formula and return composition data. Parameters ---------- descriptor : str Chemical formula string (e.g. ``"SiO2"``, ``"H2O"``). Returns ------- dict Dictionary with keys: ``nElements``, ``nAtomsAll``, ``Elements`` (list of Z), ``massFractions``, ``nAtoms``, ``molarMass``. """ zetas, fatomic = parse_formula(formula=descriptor, verbose=self.verbose()) elements = [] atomic_weight = [] massFractions = [] for i ,z in enumerate(zetas): symbol = atomic_symbols()[z] atw = self.atomic_weights(symbol) elements.append(z) atomic_weight.append(atw) massFractions.append(fatomic[i ] *atw) mweight = 0.0 for i in range(len(fatomic)): mweight += atomic_weight[i] * fatomic[i] for i in range(len(massFractions)): massFractions[i] /= mweight new_dict = { "nElements": len(elements), "nAtomsAll": float(numpy.array(fatomic).sum()), "Elements" :zetas, "massFractions": massFractions, "nAtoms" :fatomic, "molarMass": mweight, } return new_dict
import os import sys import time
[docs]def get_dabax_directory(): """ Return the platform-specific local directory used to cache DABAX files. Returns ------- str Path to the local DABAX cache directory (created if absent). """ home = os.path.expanduser("~") if sys.platform.startswith("win"): base = os.environ.get("LOCALAPPDATA", os.path.join(home, "AppData", "Local")) elif sys.platform == "darwin": base = os.path.join(home, "Library", "Application Support") else: base = os.environ.get("XDG_DATA_HOME", os.path.join(home, ".local", "share")) dabax_directory = os.path.join(base, "Dabax") os.makedirs(dabax_directory, exist_ok=True) return dabax_directory
[docs]def wait_until_downloaded(filepath, timeout=60): """ Block until a file appears on disk or a timeout is reached. Parameters ---------- filepath : str Path to the file to wait for. timeout : float, optional Maximum wait time in seconds. Default 60. Returns ------- bool True if the file appeared, False on timeout. """ start = time.time() while True: if os.path.exists(filepath): return True if time.time() - start > timeout: return False time.sleep(0.1)
if __name__ == '__main__': dx = DabaxBase(dabax_repository="https://gitlab.esrf.fr/srio/dabaxfiles/-/raw/main/") print(dx.info()) # # f0 # if False: # # test f0 data for B3+ # q = numpy.array([0,0.05,0.1,0.15,0.2,0.25,0.3,0.35,0.4,0.5,0.6,0.7,0.8,0.9,1,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9]) f0_B3plus = numpy.array([2,1.995,1.979,1.954,1.919,1.875,1.824,1.766,1.703,1.566,1.42,1.274,1.132,0.999,0.877,0.767,0.669,0.582,0.507,0.441,0.384,0.335,0.293,0.256]) # # plot # from srxraylib.plot.gol import plot plot(q, f0_B3plus, q, calculate_f0_from_f0coeff(dx.f0_with_fractional_charge(5, 3.0), q), q, calculate_f0_from_f0coeff(dx.f0_with_fractional_charge(5, 2.8), q), xtitle=r"q (sin $\theta$ / $\lambda$)", ytitle="f0 [electron units]", legend=["B3plus original", "B3plus from f0_with_fractional_charge(5,+3)", "B3plus from f0_with_fractional_charge(5,+2.8)"], marker=['+', None, None], title="") # # f0 another test # if False: # # test f0 data for B3+ # q = numpy.array( [0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9]) f0_B3plus = numpy.array( [2, 1.995, 1.979, 1.954, 1.919, 1.875, 1.824, 1.766, 1.703, 1.566, 1.42, 1.274, 1.132, 0.999, 0.877, 0.767, 0.669, 0.582, 0.507, 0.441, 0.384, 0.335, 0.293, 0.256]) # # plot # from srxraylib.plot.gol import plot plot(q, f0_B3plus, q, calculate_f0_from_f0coeff(dx.f0_with_fractional_charge(5, 3.0), q), q, calculate_f0_from_f0coeff(dx.f0_with_fractional_charge(5, 2.8), q), xtitle=r"q (sin $\theta$ / $\lambda$)", ytitle="f0 [electron units]", legend=["B3plus original", "B3plus from f0_with_fractional_charge(5,+3)", "B3plus from f0_with_fractional_charge(5,+2.8)"], marker=['+',None,None], title="", show=1) if False: # # misc # print("Ge, Si: ", dx.atomic_weights(["Ge","Si"])) print("70Ge: ", dx.atomic_weights("70Ge")) print(atomic_symbols()[14], atomic_names()[14]) print("Si atomic mass", dx.atomic_constants("Si", return_item=2)) print("Si,Ge atomic mass", dx.atomic_constants(["Si", "Ge"], return_item=2)) print("Si,Co atomic mass", dx.atomic_constants(["Si", "Co"], return_label='AtomicMass')) print("Z=27", atomic_symbols()[27]) print("Ge Z=%d" % atomic_number("Ge")) print("Density Si: ", dx.element_density("Si")) if False: energy, f1, f2 = dx.f1f2_extract("Si") energy_i = numpy.linspace(10,15000,200) f1_i, f2_i = dx.f1f2_interpolate("Si", energy=energy_i) print(">>>>", energy.shape, f1.shape, f2.shape) from srxraylib.plot.gol import plot plot(energy, f1, energy, f2, energy_i, f1_i, energy_i, f2_i, xlog=True, ylog=True, title="f1f2 Si", legend=['f1','f2','f1_i','f2_i'], marker=[None,None,'+','+'], linestyle=[None,None,'','']) if False: # used to create f0_xop_with_fractional_charge_data() in common_tools filename = dx.get_file_f0() file1 = dx.get_dabax_file(filename) if self.verbose(): print("Accessing file: %s" % filename) sf = SpecFile(file1) for Z in range(1,99): interesting_entries, charge_list, coefficient_list = dx._f0_with_fractional_charge_get_entries(Z, charge=1) for i,iel in enumerate(coefficient_list): coefficient_list[i] = iel.tolist() print(" a.append({'Z':",Z,",'charge_list':",charge_list,",'coefficient_list':",coefficient_list,"})" ) if False: from common_tools import f0_xop_with_fractional_charge print("f0 coeffs for Z=14 charge=1.5 DABAX/common_tools: ", dx.f0_with_fractional_charge(14, charge=1.5), f0_xop_with_fractional_charge(14, charge=1.5),) if False: energy, cs = dx.crosssec_extract("Si") energy_i = numpy.linspace(10,15000,200) cs_i = dx.crosssec_interpolate("Si", energy=energy_i) print(">>>>", energy.shape, cs.shape) from srxraylib.plot.gol import plot plot(energy, cs, energy_i, cs_i, xlog=True, ylog=True, title="crosssec Si", legend=['cs','cs_i'], marker=[None,'+'], linestyle=[None,'']) print(">>>> cs of Si at 10 kev %g barn/atom ", dx.crosssec_interpolate("Si", energy=50000.0))