diff --git a/pyproject.toml b/pyproject.toml index 392b9d58..8b0a23a3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = [ "setuptools>=61.0.0",] +requires = [ "setuptools>=61.0.0", "setuptools-scm"] build-backend = "setuptools.build_meta" [project] @@ -11,13 +11,23 @@ requires-python = ">=3.9" classifiers = [ "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.9",] dependencies = [ "nomad-lab>=1.2.1.dev,<1.2.2", - "pytest", "structlog==22.3.0", "xrayutilities>=1.7.4", + "pynxtools@git+https://github.com/FAIRmat-NFDI/pynxtools.git@XRD_reader_integretion", ] +[project.optional-dependencies] +dev = ["pytest", + "pip-tools"] + [project.license] file = "LICENSE" [tool.setuptools.packages.find] -where = [ "src",] +where = ["src", + "submodules/pynxtools"] +include = ['pynxtools'] +namespaces = false +exclude = ["tests*"] + +[tool.setuptools_scm] diff --git a/setup.py b/setup.py index 7f1a1763..60684932 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ from setuptools import setup -if __name__ == "__main__": - setup() +setup() diff --git a/src/nomad_measurements/xrd/parser.py b/src/nomad_measurements/xrd/parser.py index 635b119e..fb67a8e0 100644 --- a/src/nomad_measurements/xrd/parser.py +++ b/src/nomad_measurements/xrd/parser.py @@ -55,4 +55,4 @@ def parse(self, mainfile: str, archive: EntryArchive, logger) -> None: entry.data_file = data_file file_name = f'{data_file[:-6]}.archive.json' archive.data = XRDDataFile(measurement=create_archive(entry,archive,file_name)) - archive.metadata.entry_name = data_file[:-6] + ' data file' \ No newline at end of file + archive.metadata.entry_name = data_file[:-6] + ' data file' diff --git a/src/nomad_measurements/xrd/schema.py b/src/nomad_measurements/xrd/schema.py index fdfd4182..7b34af91 100644 --- a/src/nomad_measurements/xrd/schema.py +++ b/src/nomad_measurements/xrd/schema.py @@ -17,6 +17,7 @@ # import numpy as np +from pynxtools.dataconverter.readers.xrd.reader import get_template_from_xrd_reader from nomad.datamodel.metainfo.basesections import ( Measurement, MeasurementResult, @@ -61,64 +62,13 @@ ) from nomad_measurements.xrd.xrd_parser import parse_and_convert_file - +from pynxtools.dataconverter.readers.xrd.reader import X +from nomad_measurements.xrd.xrd_helper import (calculate_two_theta_or_scattering_vector, + estimate_kalpha_wavelengths) + m_package = Package(name='nomad-measurements') -def calculate_two_theta_or_scattering_vector(q=None, two_theta=None, wavelength=None): - """ - Calculate the two-theta array from the scattering vector (q) or vice-versa, - given the wavelength of the X-ray source. - - Args: - q (array-like, optional): Array of scattering vectors, in angstroms^-1. - two_theta (array-like, optional): Array of two-theta angles, in degrees. - wavelength (float): Wavelength of the X-ray source, in angstroms. - - Returns: - numpy.ndarray: Array of two-theta angles, in degrees. - """ - if q is not None: - return 2 * np.arcsin(q * wavelength / (4 * np.pi)) - elif two_theta is not None: - return (4 * np.pi / wavelength) * np.sin(np.deg2rad(two_theta) / 2) - else: - raise ValueError("Either q or two_theta must be provided.") - - -def estimate_kalpha_wavelengths(source_material): - """ - Estimate the K-alpha1 and K-alpha2 wavelengths of an X-ray source given the material - of the source. - - Args: - source_material (str): Material of the X-ray source, such as 'Cu', 'Fe', 'Mo', - 'Ag', 'In', 'Ga', etc. - - Returns: - Tuple[float, float]: Estimated K-alpha1 and K-alpha2 wavelengths of the X-ray - source, in angstroms. - """ - # Dictionary of K-alpha1 and K-alpha2 wavelengths for various X-ray source materials, - # in angstroms - kalpha_wavelengths = { - 'Cr': (2.2910, 2.2936), - 'Fe': (1.9359, 1.9397), - 'Cu': (1.5406, 1.5444), - 'Mo': (0.7093, 0.7136), - 'Ag': (0.5594, 0.5638), - 'In': (0.6535, 0.6577), - 'Ga': (1.2378, 1.2443) - } - - try: - kalpha1_wavelength, kalpha2_wavelength = kalpha_wavelengths[source_material] - except KeyError: - raise ValueError("Unknown X-ray source material.") - - return kalpha1_wavelength, kalpha2_wavelength - - class XRayTubeSource(ArchiveSection): ''' X-ray tube source used in conventional diffractometers. @@ -322,33 +272,51 @@ def normalize(self, archive, logger: BoundLogger) -> None: result = XRDResult() settings = XRDSettings() + # TODO use re module to detect the concept by a pattern, as in NeXus the inheritated group + # instance could be different name. with archive.m_context.raw_file(self.data_file) as file: - xrd_dict = parse_and_convert_file(file.name) - result.intensity = xrd_dict.get('detector', None) - result.two_theta = xrd_dict['2Theta'] * ureg('degree') if '2Theta' in xrd_dict and xrd_dict['2Theta'] is not None else None - result.omega = xrd_dict['Omega'] * ureg('degree') if 'Omega' in xrd_dict and xrd_dict['Omega'] is not None else None - result.chi = xrd_dict['Chi'] * ureg('degree') if 'Chi' in xrd_dict and xrd_dict['Chi'] is not None else None + xrd_template = get_template_from_xrd_reader(nxdl_name='NXxrd_pan', file_paths=file.name) + # Comes from detector + intensity = "/ENTRY[entry]/DATA[q_plot]/intensity" + result.intensity = xrd_template[intensity] if intensity in xrd_template else None + two_theta = "/ENTRY[entry]/2theta_plot/two_theta" + result.two_theta = xrd_template[two_theta] * ureg('degree') if two_theta in xrd_template else None + omega = "/ENTRY[entry]/2theta_plot/omega" + result.omega = xrd_template[omega] * ureg('degree') if omega in xrd_template else None + chi = "/ENTRY[entry]/2theta_plot/chi" + result.chi = xrd_template[chi] * ureg('degree') if chi in xrd_template else None if settings.source is None: settings.source = XRayTubeSource() - metadata_dict = xrd_dict.get('metadata', {}) - source_dict = metadata_dict.get('source', {}) - settings.source.xray_tube_material = source_dict.get('anode_material', None) - settings.source.kalpha_one = source_dict.get('kAlpha1', None) - settings.source.kalpha_two = source_dict.get('kAlpha2', None) - settings.source.ratio_kalphatwo_kalphaone = source_dict.get('ratioKAlpha2KAlpha1', None) - settings.source.kbeta = source_dict.get('kBeta', None) - settings.source.xray_tube_voltage = source_dict.get('voltage', None) - settings.source.xray_tube_current = source_dict.get('current', None) - result.scan_axis = metadata_dict.get('scan_axis', None) - result.integration_time = xrd_dict['countTime'] * ureg('second') if xrd_dict['countTime'] is not None else None + # metadata_dict = xrd_template.get('metadata', {}) + # source_dict = metadata_dict.get('source', {}) + xray_tb_mat = "/ENTRY[entry]/INSTRUMENT[instrument]/SOURCE[source]/xray_tube_material" + settings.source.xray_tube_material = xrd_template[xray_tb_mat] if xray_tb_mat in xrd_template else None + alpha_one = "/ENTRY[entry]/INSTRUMENT[instrument]/SOURCE[source]/k_alpha_one" + settings.source.kalpha_one = xrd_template[alpha_one] if alpha_one in xrd_template else None + alpha_two = "/ENTRY[entry]/INSTRUMENT[instrument]/SOURCE[source]/k_alpha_two" + settings.source.kalpha_two = xrd_template[alpha_two] if alpha_two in xrd_template else None + one_to_ratio = "/ENTRY[entry]/INSTRUMENT[instrument]/SOURCE[source]/ratio_k_alphatwo_k_alphaone" + settings.source.ratio_kalphatwo_kalphaone = xrd_template[one_to_ratio] if one_to_ratio in xrd_template else None + kbeta = "/ENTRY[entry]/INSTRUMENT[instrument]/SOURCE[source]/kbeta" + settings.source.kbeta = xrd_template[kbeta] if kbeta in xrd_template else None + voltage = "/ENTRY[entry]/INSTRUMENT[instrument]/SOURCE[source]/xray_tube_voltage" + settings.source.xray_tube_voltage = xrd_template[voltage] if voltage in xrd_template else None + current = "/ENTRY[entry]/INSTRUMENT[instrument]/SOURCE[source]/xray_tube_current" + settings.source.xray_tube_current = xrd_template[current] if current in xrd_template else None + scan_axis = "/ENTRY[entry]/INSTRUMENT[instrument]/DETECTOR[detector]/scan_axis" + result.scan_axis = xrd_template[scan_axis] if scan_axis in xrd_template else None + count_time = "/ENTRY[entry]/COLLECTION[collection]/count_time" + result.integration_time = xrd_template[count_time] if count_time in xrd_template else None samples=CompositeSystemReference() - samples.lab_id=xrd_dict['metadata']["sample_id"] + sample_id = "/ENTRY[entry]/SAMPLE[sample]/sample_id" + samples.lab_id = xrd_template[sample_id] if sample_id in xrd_template else None samples.normalize(archive, logger) self.samples=[samples] if settings.source.xray_tube_material is not None: xray_tube_material = settings.source.xray_tube_material settings.source.kalpha_one, settings.source.kalpha_two = estimate_kalpha_wavelengths(source_material=xray_tube_material) + try: if settings.source.kalpha_one is not None: result.source_peak_wavelength = settings.source.kalpha_one @@ -367,6 +335,7 @@ def normalize(self, archive, logger: BoundLogger) -> None: two_theta=result.two_theta, wavelength=result.source_peak_wavelength) except Exception: logger.warning("Unable to convert from two_theta to q_vector vice-versa") + self.xrd_settings = settings self.results = [result] diff --git a/src/nomad_measurements/xrd/xrd_helper.py b/src/nomad_measurements/xrd/xrd_helper.py new file mode 100644 index 00000000..ffe743e7 --- /dev/null +++ b/src/nomad_measurements/xrd/xrd_helper.py @@ -0,0 +1,59 @@ +""" +Gethering of functions and classes that are needed to calculate +some properties, features and to map data into nomad. +""" +import numpy as np + + +def calculate_two_theta_or_scattering_vector(q=None, two_theta=None, wavelength=None): + """ + Calculate the two-theta array from the scattering vector (q) or vice-versa, + given the wavelength of the X-ray source. + + Args: + q (array-like, optional): Array of scattering vectors, in angstroms^-1. + two_theta (array-like, optional): Array of two-theta angles, in degrees. + wavelength (float): Wavelength of the X-ray source, in angstroms. + + Returns: + numpy.ndarray: Array of two-theta angles, in degrees. + """ + if q is not None: + return 2 * np.arcsin(q * wavelength / (4 * np.pi)) + elif two_theta is not None: + return (4 * np.pi / wavelength) * np.sin(np.deg2rad(two_theta) / 2) + else: + raise ValueError("Either q or two_theta must be provided.") + + +def estimate_kalpha_wavelengths(source_material): + """ + Estimate the K-alpha1 and K-alpha2 wavelengths of an X-ray source given the material + of the source. + + Args: + source_material (str): Material of the X-ray source, such as 'Cu', 'Fe', 'Mo', + 'Ag', 'In', 'Ga', etc. + + Returns: + Tuple[float, float]: Estimated K-alpha1 and K-alpha2 wavelengths of the X-ray + source, in angstroms. + """ + # Dictionary of K-alpha1 and K-alpha2 wavelengths for various X-ray source materials, + # in angstroms + kalpha_wavelengths = { + 'Cr': (2.2910, 2.2936), + 'Fe': (1.9359, 1.9397), + 'Cu': (1.5406, 1.5444), + 'Mo': (0.7093, 0.7136), + 'Ag': (0.5594, 0.5638), + 'In': (0.6535, 0.6577), + 'Ga': (1.2378, 1.2443) + } + + try: + kalpha1_wavelength, kalpha2_wavelength = kalpha_wavelengths[source_material] + except KeyError as exc: + raise ValueError("Unknown X-ray source material.") from exc + + return kalpha1_wavelength, kalpha2_wavelength diff --git a/submodules/pynxtools b/submodules/pynxtools index d49f5af0..469b95f7 160000 --- a/submodules/pynxtools +++ b/submodules/pynxtools @@ -1 +1 @@ -Subproject commit d49f5af06335a5f4d3f1dc9b9d637145c46f4d74 +Subproject commit 469b95f73d4511a5d1f78091b3e1cf636534215c