From e281e8cacefb850b54bb9e1245e51d898798094a Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Tue, 20 Feb 2024 10:18:34 +0100 Subject: [PATCH 01/41] add writing of CPS data to vms reader --- pynxtools_xps/vms/vamas.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index 4957f913..e5ef1f6b 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -187,7 +187,8 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): detector_data_key = f'{path_map["detector"]}/{detector_data_key_child}/counts' energy = np.array(spectrum["data"]["x"]) - intensity = np.array(spectrum["data"]["y"]) + intensity_raw = np.array(spectrum["data"]["y"]) + intensity_cps = np.array(spectrum["data"]["y_cps"]) if entry not in self._xps_dict["data"]: self._xps_dict["data"][entry] = xr.Dataset() @@ -203,7 +204,7 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): averaged_scans = np.mean(all_scan_data, axis=0) if averaged_scans.size == 1: # on first scan in cycle - averaged_scans = intensity + averaged_scans = intensity_cps try: self._xps_dict["data"][entry][scan_key.split("_")[0]] = xr.DataArray( @@ -213,13 +214,12 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): except ValueError: pass - # Write scan data to 'data'. self._xps_dict["data"][entry][scan_key] = xr.DataArray( - data=intensity, coords={"energy": energy} + data=intensity_cps, coords={"energy": energy} ) # Write raw intensities to 'detector'. - self._xps_dict[detector_data_key] = intensity + self._xps_dict[detector_data_key] = intensity_raw class VamasParser(ABC): @@ -603,9 +603,16 @@ def build_list(self): for var in range(int(block.no_variables)): if var == 0: key = "y" + + data["y"] = getattr(block, "y") + + if block.variable_label_1 == "Intensity": + y_cps = [np.round(y / block.dwell_time, 2) for y in block.y] + data["y_cps"] = y_cps + else: key = "y" + str(var) - data[key] = getattr(block, key) + data[key] = getattr(block, key) spec_dict = { "time_stamp": date_time, From a23f8febd810f9ba87ca45dddefb6e9b044da4cd Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:38:48 +0100 Subject: [PATCH 02/41] make vms comments a list --- pynxtools_xps/vms/vamas.py | 12 ++++++------ pynxtools_xps/vms/vamas_data_model.py | 8 +++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index e5ef1f6b..ec3fab5f 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -435,9 +435,9 @@ def _parse_header(self): for attr in self.attrs["common_header"]: setattr(self.header, attr, self.data.pop(0).strip()) no_comment_lines = int(self.header.no_comment_lines) - comments = "" + comments = [] for _ in range(no_comment_lines): - comments += self.data.pop(0) + comments += [self.data.pop(0)] self.header.comment_lines = comments self.header.exp_mode = self.data.pop(0).strip() if self.header.exp_mode == "NORM": @@ -657,7 +657,7 @@ def _parse_norm_block(self): block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) block.no_comment_lines = int(self.data.pop(0).strip()) for _ in range(block.no_comment_lines): - block.comment_lines += self.data.pop(0) + block.comment_lines += [self.data.pop(0)] block.technique = self.data.pop(0).strip() for _ in range(int(self.header.nr_exp_var)): block.exp_var_value = self.data.pop(0).strip() @@ -739,7 +739,7 @@ def _parse_map_block(self): block.no_comment_lines = int(self.data.pop(0).strip()) for _ in range(block.no_comment_lines): self.data.pop(0) - block.comment_lines += self.data.pop(0) + block.comment_lines += [self.data.pop(0)] block.technique = self.data.pop(0).strip() block.x_coord = self.data.pop(0).strip() block.y_coord = self.data.pop(0).strip() @@ -863,7 +863,7 @@ def _parse_norm_block(self): block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) block.no_comment_lines = int(self.data.pop(0).strip()) for _ in range(block.no_comment_lines): - block.comment_lines += self.data.pop(0) + block.comment_lines += [self.data.pop(0)] block.technique = self.data.pop(0).strip() for _ in range(int(self.header.nr_exp_var)): block.exp_var_value = self.data.pop(0).strip() @@ -945,7 +945,7 @@ def _parse_map_block(self): block.no_comment_lines = int(self.data.pop(0).strip()) for _ in range(block.no_comment_lines): self.data.pop(0) - block.comment_lines += self.data.pop(0) + block.comment_lines += [self.data.pop(0)] block.technique = self.data.pop(0).strip() block.x_coord = self.data.pop(0).strip() block.y_coord = self.data.pop(0).strip() diff --git a/pynxtools_xps/vms/vamas_data_model.py b/pynxtools_xps/vms/vamas_data_model.py index 878445d5..a94b811e 100644 --- a/pynxtools_xps/vms/vamas_data_model.py +++ b/pynxtools_xps/vms/vamas_data_model.py @@ -19,7 +19,7 @@ # # pylint: disable=too-many-instance-attributes -from dataclasses import dataclass +from dataclasses import dataclass, field @dataclass @@ -34,7 +34,9 @@ class VamasHeader: operator_id: str = "Not Specified" experiment_id: str = "Not Specified" no_comment_lines: str = "2" - comment_lines: str = "Casa Info Follows CasaXPS Version 2.3.22PR1.0\n0" + comment_lines: list = field( + default_factory=["Casa Info Follows CasaXPS Version 2.3.22PR1.0\n0"] + ) exp_mode: str = "NORM" scan_mode: str = "REGULAR" nr_regions: str = "0" @@ -64,7 +66,7 @@ class VamasBlock: no_comment_lines: str = "" # This list should contain one element per for each # line in the comment block - comment_lines: str = "" + comment_lines: list = field(default_factory=list) technique: str = "" exp_var_value: str = "" source_label: str = "" From 82c3cd2040a95f9e133755e3cc727b423ccf2e8b Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:39:51 +0100 Subject: [PATCH 03/41] change default value of casa comments --- pynxtools_xps/vms/vamas_data_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pynxtools_xps/vms/vamas_data_model.py b/pynxtools_xps/vms/vamas_data_model.py index a94b811e..35797b70 100644 --- a/pynxtools_xps/vms/vamas_data_model.py +++ b/pynxtools_xps/vms/vamas_data_model.py @@ -35,8 +35,8 @@ class VamasHeader: experiment_id: str = "Not Specified" no_comment_lines: str = "2" comment_lines: list = field( - default_factory=["Casa Info Follows CasaXPS Version 2.3.22PR1.0\n0"] - ) + default_factory=list + ) # ["Casa Info Follows CasaXPS Version 2.3.22PR1.0\n0"] exp_mode: str = "NORM" scan_mode: str = "REGULAR" nr_regions: str = "0" From c7834b7bf1d646c537d8d4899b5f39c628e21a8e Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:50:16 +0100 Subject: [PATCH 04/41] change notation in mapper output --- pynxtools_xps/sle/sle_specs.py | 4 ++-- pynxtools_xps/txt/txt_scienta.py | 4 ++-- pynxtools_xps/txt/txt_vamas_export.py | 4 ++-- pynxtools_xps/xy/xy_specs.py | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pynxtools_xps/sle/sle_specs.py b/pynxtools_xps/sle/sle_specs.py index a80dc638..d6a6b6bb 100644 --- a/pynxtools_xps/sle/sle_specs.py +++ b/pynxtools_xps/sle/sle_specs.py @@ -198,8 +198,8 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): """ # pylint: disable=too-many-locals,duplicate-code - group_parent = f'{self._root_path}/RegionGroup_{spectrum["group_name"]}' - region_parent = f'{group_parent}/regions/RegionData_{spectrum["spectrum_type"]}' + group_parent = f'{self._root_path}/Group_{spectrum["group_name"]}' + region_parent = f'{group_parent}/regions/Region_{spectrum["spectrum_type"]}' instrument_parent = f"{region_parent}/instrument" analyser_parent = f"{instrument_parent}/analyser" diff --git a/pynxtools_xps/txt/txt_scienta.py b/pynxtools_xps/txt/txt_scienta.py index 4b456986..09307cbe 100644 --- a/pynxtools_xps/txt/txt_scienta.py +++ b/pynxtools_xps/txt/txt_scienta.py @@ -130,8 +130,8 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): """ # pylint: disable=too-many-locals,duplicate-code - group_parent = f'{self._root_path}/RegionGroup_{spectrum["spectrum_type"]}' - region_parent = f'{group_parent}/regions/RegionData_{spectrum["region_name"]}' + group_parent = f'{self._root_path}/Region_{spectrum["spectrum_type"]}' + region_parent = f'{group_parent}/regions/Region_{spectrum["region_name"]}' file_parent = f"{region_parent}/file_info" instrument_parent = f"{region_parent}/instrument" analyser_parent = f"{instrument_parent}/analyser" diff --git a/pynxtools_xps/txt/txt_vamas_export.py b/pynxtools_xps/txt/txt_vamas_export.py index 4923e266..87a2c3b5 100644 --- a/pynxtools_xps/txt/txt_vamas_export.py +++ b/pynxtools_xps/txt/txt_vamas_export.py @@ -130,8 +130,8 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): """ # pylint: disable=too-many-locals,duplicate-code - group_parent = f'{self._root_path}/RegionGroup_{spectrum["group_name"]}' - region_parent = f'{group_parent}/regions/RegionData_{spectrum["spectrum_type"]}' + group_parent = f'{self._root_path}/Group_{spectrum["group_name"]}' + region_parent = f'{group_parent}/regions/Region_{spectrum["spectrum_type"]}' file_parent = f"{region_parent}/file_info" instrument_parent = f"{region_parent}/instrument" analyser_parent = f"{instrument_parent}/analyser" diff --git a/pynxtools_xps/xy/xy_specs.py b/pynxtools_xps/xy/xy_specs.py index 47f12c70..e327860d 100644 --- a/pynxtools_xps/xy/xy_specs.py +++ b/pynxtools_xps/xy/xy_specs.py @@ -138,8 +138,8 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): """ # pylint: disable=too-many-locals,duplicate-code - group_parent = f'{self._root_path}/RegionGroup_{spectrum["group_name"]}' - region_parent = f'{group_parent}/regions/RegionData_{spectrum["region_name"]}' + group_parent = f'{self._root_path}/Group_{spectrum["group_name"]}' + region_parent = f'{group_parent}/regions/Region_{spectrum["region_name"]}' file_parent = f"{region_parent}/file_info" instrument_parent = f"{region_parent}/instrument" analyser_parent = f"{instrument_parent}/analyser" From 2cb268bb2fe452b9624427aca7eb51ddfecbf702 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:51:52 +0100 Subject: [PATCH 05/41] use XPS dataclass template --- pynxtools_xps/reader_utils.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/pynxtools_xps/reader_utils.py b/pynxtools_xps/reader_utils.py index 2b342695..86cec378 100644 --- a/pynxtools_xps/reader_utils.py +++ b/pynxtools_xps/reader_utils.py @@ -21,6 +21,29 @@ from scipy.interpolate import interp1d import numpy as np +from dataclasses import dataclass + + +@dataclass +class XpsDataclass: + """Generic class to hold a data model and a type validation method.""" + + def validate_types(self): + ret = True + for field_name, field_def in self.__dataclass_fields__.items(): + actual_type = type(getattr(self, field_name)) + if actual_type != field_def.type: + print(f"\t{field_name}: '{actual_type}' instead of '{field_def.type}'") + ret = False + return ret + + def __post_init__(self): + if not self.validate_types(): + raise ValueError("Wrong types") + + def dict(self): + return self.__dict__.copy() + class XPSMapper(ABC): """Abstract base class from mapping from a parser to NXmpes template""" @@ -77,6 +100,11 @@ def construct_data(self): """ +def to_snake_case(string_with_whitespace): + """Convert a string to snake_case.""" + return "_".join(word.lower() for word in string_with_whitespace.split()) + + def safe_arange_with_edges(start, stop, step): """ In order to avoid float point errors in the division by step. @@ -102,7 +130,7 @@ def safe_arange_with_edges(start, stop, step): def check_uniform_step_width(lst): """ - Check to see if a non-uniform step width is used in an lst + Check to see if a non-uniform step width is used in an list. Parameters ---------- From f64127bde5c210c9b8074375198369499f7ac9b7 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:38:19 +0100 Subject: [PATCH 06/41] add data model for CasaXPS peak fitting --- pynxtools_xps/vms/casa_data_model.py | 299 +++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 pynxtools_xps/vms/casa_data_model.py diff --git a/pynxtools_xps/vms/casa_data_model.py b/pynxtools_xps/vms/casa_data_model.py new file mode 100644 index 00000000..fd1e37e9 --- /dev/null +++ b/pynxtools_xps/vms/casa_data_model.py @@ -0,0 +1,299 @@ +""" +Data model for CasaXPS. +""" +# Copyright The NOMAD Authors. +# +# This file is part of NOMAD. See https://nomad-lab.eu for further info. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# pylint: disable=too-many-instance-attributes + +import re +from typing import List, Dict, Any +from dataclasses import dataclass, field + +from pynxtools_xps.reader_utils import XpsDataclass + + +class CasaProcess: + """Processing and fitting information from CasaXPS.""" + + def __init__(self): + self.n_alignments: int = 0 + self.n_unknown_processes: int = 0 + self.n_regions: int = 0 + self.n_components: int = 0 + + self.alignments: List[Any] = [] + self.unknown_processes: List[Any] = [] + self.regions: List[Any] = [] + self.components: List[Any] = [] + + def process_comments(self, comment_list: List[str]): + line_map = { + "Calib": self.process_alignment, + "CASA region": self.process_region, + "CASA comp": self.process_component, + } + + for line in comment_list: + for token, func in line_map.items(): + if line.startswith(token): + func(line) + + casa_data = { + "alignments": self.alignments, + "regions": self.regions, + "components": self.components, + } + + self.count_occurences() + + return casa_data + + def count_occurences(self): + """Count occurence of different process items.""" + self.n_alignments = len(self.alignments) + self.n_unknown_process = len(self.unknown_processes) + self.n_regions = len(self.regions) + self.n_components = len(self.components) + + def process_alignment(self, align_str: str): + """ + Process one alignment. + + Parameters + ---------- + align_str : str + String with alignment definition in a VMS file. + Typical example: + 'Calib M = 6.8 A = 0 BE ADD' + + + Returns + ------- + None. + + """ + split_line = self._split_line(align_str) + + align = CasaAlignment() + + measured_index = split_line.index("M") + aligned_index = split_line.index("A") + align.measured_energy = float(split_line[measured_index + 2]) + align.aligned_energy = float(split_line[aligned_index + 2]) + + align.energy_type = map_energy_type(split_line[7]) + align.operation = split_line[8] + + if align.operation == "ADD": + align.energy_offset = align.measured_energy - align.aligned_energy + align.operation = "addition" + + align.validate_types() + + self.alignments += [align] + + def process_region(self, region_str: str): + """ + Process one fit region. + + Parameters + ---------- + region_str : str + String with region definition in a VMS file. + Typical example: + 'CASA region (*O1s*) (*Shirley*) 718.88221 726.6 9.74 2 0 9 1450.5943 -450 0 0 (*Mo 3d*) 95.9219 0 9.74' + + Returns + ------- + None. + + """ + split_line = self._split_line(region_str) + + region = CasaRegion() + region.name = split_line[2] + region.bg_type = split_line[3] + region.start = float(split_line[4]) + region.end = float(split_line[5]) + region.rsf = float(split_line[6]) + region.av_width = float(split_line[7]) + region.start_offset = float(split_line[8]) + region.end_offset = float(split_line[9]) + region.cross_section = split_line[10:14] + region.tag = split_line[14] + region.unknown_0 = float(split_line[15]) + region.unknown_1 = float(split_line[16]) + region.rsf_effective = float(split_line[17]) + + region.validate_types() + + self.regions += [region] + + def process_component(self, component_str: str): + """ + Process one fit component if it is defined in the + + Parameters + ---------- + component_str : str + String with component definition in a VMS file. + Typical example: + 'CASA comp (*O1s, lattice*) (*GL(50)*) Area 308996.39 1e-020 15401311 -1 1 MFWHM 1.5315216 0.32 2 -1 1 Position 723.30224 719.3797 726.3 -1 1 RSF 0.063 MASS 15.9994 INDEX -1 (*O 1s*) CONST (**) UNCORRECTEDRSF 2.85' + + + Returns + ------- + None. + + """ + split_line = self._split_line(component_str) + + component = CasaComponent() + component.name = split_line[2] + component.lineshape = split_line[3] + + area_index = split_line.index("Area") + component.area = float(split_line[area_index + 1]) + component.area_min = float(split_line[area_index + 2]) + component.area_max = float(split_line[area_index + 3]) + component.area_ref_comp_id = int(split_line[area_index + 4]) + component.area_ref_comp_factor = float(split_line[area_index + 4]) + + width_index = split_line.index("MFWHM") + component.width = float(split_line[width_index + 1]) + component.width_min = float(split_line[width_index + 2]) + component.width_max = float(split_line[width_index + 3]) + component.width_ref_comp_id = int(split_line[width_index + 4]) + component.width_ref_comp_factor = float(split_line[width_index + 5]) + + position_index = split_line.index("Position") + component.position = float(split_line[position_index + 1]) + component.position_min = float(split_line[position_index + 2]) + component.position_max = float(split_line[position_index + 3]) + component.position_ref_comp_id = int(split_line[position_index + 4]) + component.position_ref_comp_factor = float(split_line[position_index + 5]) + + rsf_index = split_line.index("RSF") + component.rsf = float(split_line[rsf_index + 1]) + mass_index = split_line.index("MASS") + component.mass = float(split_line[mass_index + 1]) + comp_index = split_line.index("INDEX") + component.index = int(split_line[comp_index + 1]) + component.tag = str(split_line[comp_index + 2]) + const_index = split_line.index("CONST") + component.const = str(split_line[const_index + 1]) + uncorrected_rsf_index = split_line.index("UNCORRECTEDRSF") + component.uncorrected_rsf = float(split_line[uncorrected_rsf_index + 1]) + + component.validate_types() + self.components += [component] + + def _split_line(self, line): + """Split line in Casa processing.""" + regex_pattern = r"\s+|\(\*(?:(?!\*\)).)*?\*\)|\S+" + result = [match for match in re.findall(regex_pattern, line) if match.strip()] + return [re.sub(r"[\(*?\*)]", "", text) for text in result] + + +def map_energy_type(energy_str): + """Map energy names to NXDL-compliant concepts.""" + replacements = { + "BE": "binding", + "KE": "kinetic", + "binding energy": "binding", + "binding": "kinetic", + "Binding": "binding", + "Kinetic": "kinetic", + } + return replacements.get(energy_str) + + +@dataclass +class CasaAlignment(XpsDataclass): + """An object to store one CasaXPS alignment.""" + + energy_type: str = "binding" + energy_offset: float = 0.0 + energy_offset_units: str = "eV" + measured_energy: float = 0.0 + measured_energy_units: str = "eV" + aligned_energy: float = 0.0 + measured_energy_units: str = "eV" + operation: str = "eV" + + +@dataclass +class CasaRegion(XpsDataclass): + """An object to store one CasaXPS peak fit region.""" + + name: str = "" + rsf: float = 0.0 + start: float = 0.0 + start_units: str = "eV" + end: float = 0.0 + end_units: str = "eV" + bg_type: str = "" + av_width: float = 0.0 + av_width_units: str = "eV" + start_offset: float = 0.0 + start_offset_units: str = "CPS" + end_offset: float = 0.0 + end_offset_units: str = "CPS" + cross_section: list = field(default_factory=list) + tag: str = "" + unknown_0: float = 0.0 + unknown_1: float = 0.0 + rsf_effective: float = 0.0 + + +@dataclass +class CasaComponent(XpsDataclass): + """An object to store one CasaXPS peak fit component.""" + + name: str = "" + index: int = -1 + lineshape: str = "" + + area: float = 0.0 + area_min: float = 0.0 + area_max: float = 0.0 + area_ref_comp_id: int = -1 + area_ref_comp_factor: float = 0.0 + + width: float = 0.0 + width_units: str = "eV" + width_min: float = 0.0 + width_units: str = "eV" + width_max: float = 0.0 + width_units: str = "eV" + width_ref_comp_id: int = -1 + width_ref_comp_factor: float = 0.0 + + position: float = 0.0 + position_units: str = "eV" + position_min: float = 0.0 + position_min_units: str = "eV" + position_max: float = 0.0 + position_max_units: str = "eV" + position_ref_comp_id: int = -1 + position_ref_comp_factor: float = 0.0 + + rsf: float = 0.0 + uncorrected_rsf: float = 0.0 + mass: float = 0.0 + tag: str = "" + const: str = "" # CONST From 785c82a917bf647a4c15df188331af22fc771e5c Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:39:33 +0100 Subject: [PATCH 07/41] parsing of units and casa processing --- pynxtools_xps/vms/vamas.py | 174 ++++++++++++++++++++++++++++++++----- 1 file changed, 154 insertions(+), 20 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index ec3fab5f..00dd616d 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -28,12 +28,14 @@ import numpy as np from pynxtools_xps.vms.vamas_data_model import VamasHeader, VamasBlock +from pynxtools_xps.vms.casa_data_model import CasaProcess from pynxtools_xps.reader_utils import ( XPSMapper, construct_entry_name, construct_data_key, construct_detector_data_key, + to_snake_case, ) @@ -56,6 +58,26 @@ def __init__(self): "irregular": VamasParserIrregular, } + self.units = { + "instrument/sample_normal_polarangle_tilt": "degree ", + "instrument/sample_tilt_azimuth": "degree", + "instrument/sample_rotation_angle": "degree", + "source/source_analyzer_angle": "degree", + "source/excitation_energy": "eV", + "source/particle_charge": "C", + "analyser/analyzer_take_off_azimuth": "degree", + "analyser/analyzer_take_off_polar": "degree", + "analyser/analysis_width_x": "m", + "analyser/analysis_width_y": "m", + "analyser/target_bias": "V", + "analyser/time_correction": "s", + "analyser/work_function": "eV", + "energydispersion/pass_energy": "eV", + "detector/dwell_time": "s", + "data/start_energy": "eV", + "data/step_size": "eV", + } + super().__init__() def _select_parser(self): @@ -94,21 +116,28 @@ def construct_data(self): key_map = { "user": [], - "instrument": [], + "instrument": [ + "sample_normal_polarangle_tilt", + "sample_tilt_azimuth", + "sample_rotation_angle", + ], "source": [ "source_label", "source_analyzer_angle", ], - "beam": ["excitation_energy"], + "beam": ["excitation_energy", "particle_charge"], "analyser": [ "analyzer_take_off_azimuth", "analyzer_take_off_polar", "analysis_width_x", "analysis_width_y", "target_bias", + "time_correction", "work_function", ], - "collectioncolumn": [], + "collectioncolumn": [ + "magnification", + ], "energydispersion": [ "scan_mode", "pass_energy", @@ -118,8 +147,7 @@ def construct_data(self): "dwell_time", ], "manipulator": [], - "sample": [], - "calibration": [], + "sample": ["sample_name"], "data": [ "x_label", "x_units", @@ -133,11 +161,16 @@ def construct_data(self): ], "region": [ "analysis_method", - "spectrum_type", - "comments", + "element", + "group_id", + "group_name", + "region", + "scan_no", + "scans", "spectrum_id", + "spectrum_type", + "transition", "time_stamp", - "scans", ], } @@ -147,8 +180,8 @@ def construct_data(self): def _update_xps_dict_with_spectrum(self, spectrum, key_map): """Map one spectrum from raw data to NXmpes-ready dict.""" # pylint: disable=too-many-locals,duplicate-code - group_parent = f'{self._root_path}/RegionGroup_{spectrum["group_name"]}' - region_parent = f'{group_parent}/regions/RegionData_{spectrum["spectrum_type"]}' + group_parent = f'{self._root_path}/Group_{spectrum["group_name"]}' + region_parent = f'{group_parent}/regions/Region_{spectrum["spectrum_type"]}' instrument_parent = f"{region_parent}/instrument" analyser_parent = f"{instrument_parent}/analyser" @@ -162,23 +195,47 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): "energydispersion": f"{analyser_parent}/energydispersion", "detector": f"{analyser_parent}/detector", "manipulator": f"{instrument_parent}/manipulator", - "calibration": f"{instrument_parent}/calibration", "sample": f"{region_parent}/sample", "data": f"{region_parent}/data", + "energy_referencing": f"{region_parent}/calibrations/energy_referencing", + "peak_fitting": f"{region_parent}/peak_fitting", "region": f"{region_parent}", } + used_keys = [] + for grouping, spectrum_keys in key_map.items(): root = path_map[str(grouping)] for spectrum_key in spectrum_keys: - try: - units = re.search(r"\[([A-Za-z0-9_]+)\]", spectrum_key).group(1) - mpes_key = spectrum_key.rsplit(" ", 1)[0] + mpes_key = spectrum_key.rsplit(" ", 1)[0] + self._xps_dict[f"{root}/{mpes_key}"] = spectrum[spectrum_key] + + unit_key = f"{grouping}/{spectrum_key}" + units = self._get_units_for_key(unit_key) + if units: self._xps_dict[f"{root}/{mpes_key}/@units"] = units - self._xps_dict[f"{root}/{mpes_key}"] = spectrum[spectrum_key] - except AttributeError: - mpes_key = spectrum_key - self._xps_dict[f"{root}/{mpes_key}"] = spectrum[spectrum_key] + + # Write process data + process_key_map = { + "energy_referencing": ["alignments"], + "peak_fitting": ["regions", "components"], + } + + for grouping, spectrum_keys in process_key_map.items(): + root = path_map[str(grouping)] + for spectrum_key in spectrum_keys: + try: + processes = spectrum[spectrum_key] + for i, process in enumerate(processes): + process_key = ( + f"{root}/{spectrum_key}/{spectrum_key.rstrip('s')}{i}" + ) + for key, value in process.dict().items(): + key = key.replace("_units", "/@units") + self._xps_dict[f"{process_key}/{key}"] = value + used_keys += [spectrum_key] + except KeyError: + pass # Create keys for writing to data and detector entry = construct_entry_name(region_parent) @@ -217,10 +274,40 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): self._xps_dict["data"][entry][scan_key] = xr.DataArray( data=intensity_cps, coords={"energy": energy} ) + used_keys += ["data"] # Write raw intensities to 'detector'. self._xps_dict[detector_data_key] = intensity_raw + # Write additional keys to region parent. + for spectrum_key, value in spectrum.items(): + if spectrum_key not in used_keys: + self._xps_dict[f"{region_parent}/{spectrum_key}"] = value + + def _get_units_for_key(self, unit_key): + """ + Get correct units for a given key. + + Parameters + ---------- + unit_key : str + Key of type :, e.g. + detector/detector_voltage + + Returns + ------- + str + Unit for that unit_key. + + """ + try: + return re.search(r"\[([A-Za-z0-9_]+)\]", unit_key).group(1) + except AttributeError: + try: + return self.units[unit_key] + except KeyError: + return "" + class VamasParser(ABC): """A parser for reading vamas files.""" @@ -550,7 +637,6 @@ def build_list(self): settings = { "region": block.block_id, "sample_name": block.sample_id, - "comments": block.comment_lines, "analysis_method": block.technique, "source_label": block.source_label, "excitation_energy": block.source_energy, @@ -584,6 +670,9 @@ def build_list(self): "n_values": int(block.num_ord_values / block.no_variables), } + comment_dict = self.handle_block_comments(block.comment_lines) + settings.update(comment_dict) + # Convert the native time format to the datetime string # in the ISO 8601 format tzinfo = datetime.timezone( @@ -606,7 +695,7 @@ def build_list(self): data["y"] = getattr(block, "y") - if block.variable_label_1 == "Intensity": + if block.variable_label_1 in ["Intensity", "counts"]: y_cps = [np.round(y / block.dwell_time, 2) for y in block.y] data["y_cps"] = y_cps @@ -630,6 +719,44 @@ def build_list(self): return spectra + def handle_block_comments(self, comment_list): + """Handle comments (incl. Casa fitting for each block.""" + comments = {} + + if "Casa Info Follows" in comment_list[0]: + # Get all processing and fitting data from Casa comments. + casa = CasaProcess() + casa_data = casa.process_comments(comment_list) + + comments.update(casa_data) + + no_of_casa_lines = 1 + + for number in ( + "n_alignments", + "n_unknown_processes", + "n_regions", + "n_components", + ): + occurence = getattr(casa, number) + no_of_casa_lines += 1 + if occurence >= 1: + no_of_casa_lines += occurence + + non_casa_comments = comment_list[no_of_casa_lines:] + + else: + non_casa_comments = comment_list + + for line in non_casa_comments: + for sep in ("=", ":"): + try: + key, value = [part.strip(" ") for part in line.split("=", 1)] + comments[to_snake_case(key)] = value + except ValueError: + continue + return comments + class VamasParserRegular(VamasParser): """Parser for .vms files of type REGULAR""" @@ -1040,3 +1167,10 @@ def _add_data_values(self, block): data_array_slice = data_array[var::max_var] data_dict[name] = data_array_slice setattr(block, name, data_dict[name]) + + +if __name__ == "__main__": + file = r"C:\Users\pielsticker\Lukas\FAIRMat\user_cases\Schumann_XPS_Catalysis\C2 Activated Vamas Files\CleanData-alphaII VOPO4 C2 BC4316.vms" + parser = VamasParserRegular() + d = parser.parse_file(file) + d0 = d[0] From 49a590d80a46e5fda3d12fb59c3065114e012d8b Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:53:38 +0100 Subject: [PATCH 08/41] fix casa data model --- pynxtools_xps/vms/casa_data_model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pynxtools_xps/vms/casa_data_model.py b/pynxtools_xps/vms/casa_data_model.py index fd1e37e9..525b3ae8 100644 --- a/pynxtools_xps/vms/casa_data_model.py +++ b/pynxtools_xps/vms/casa_data_model.py @@ -232,7 +232,7 @@ class CasaAlignment(XpsDataclass): measured_energy: float = 0.0 measured_energy_units: str = "eV" aligned_energy: float = 0.0 - measured_energy_units: str = "eV" + aligned_energy_units: str = "eV" operation: str = "eV" @@ -277,9 +277,9 @@ class CasaComponent(XpsDataclass): width: float = 0.0 width_units: str = "eV" width_min: float = 0.0 - width_units: str = "eV" + width_min_units: str = "eV" width_max: float = 0.0 - width_units: str = "eV" + width_max_units: str = "eV" width_ref_comp_id: int = -1 width_ref_comp_factor: float = 0.0 From a16fcb1de4fa6509750ad8d4e21587f1944e0310 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Wed, 6 Mar 2024 17:06:09 +0100 Subject: [PATCH 09/41] add handling of Casa header --- pynxtools_xps/vms/vamas.py | 33 +++++++++++++++++++++++---- pynxtools_xps/vms/vamas_data_model.py | 6 +++-- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index 00dd616d..ff8d4817 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -624,6 +624,10 @@ def build_list(self): temp_group_name = "" spectra = [] + header_dict = {to_snake_case(k): v for (k, v) in self.header.dict().items()} + del header_dict["comment_lines"] + header_dict.update(self.handle_header_comments(self.header.comment_lines)) + for spectrum_id, block in enumerate(self.blocks): group_name = block.sample_id # This set of conditions detects if the group name has changed. @@ -669,9 +673,7 @@ def build_list(self): "sample_rotation_angle": block.sample_rotation, "n_values": int(block.num_ord_values / block.no_variables), } - - comment_dict = self.handle_block_comments(block.comment_lines) - settings.update(comment_dict) + settings.update(header_dict) # Convert the native time format to the datetime string # in the ISO 8601 format @@ -719,8 +721,31 @@ def build_list(self): return spectra + def handle_header_comments(self, comment_list): + """Handle comments (incl. Casa info) for the header.""" + comments = {} + + if "Casa Info Follows" in comment_list[0]: + comments["casa_version"] = ( + comment_list[0].split("Casa Info Follows CasaXPS Version")[1].strip() + ) + non_casa_comments = comment_list[1:] + else: + non_casa_comments = comment_list + + for line in non_casa_comments: + for sep in ("=", ":"): + try: + key, value = [part.strip(" ") for part in line.split(sep, 1)] + comments[to_snake_case(key)] = value + except ValueError: + if "SpecsLab Prodigy" in line: + comments["prodigy_version"] = line.split("Version")[1].strip() + + return comments + def handle_block_comments(self, comment_list): - """Handle comments (incl. Casa fitting for each block.""" + """Handle comments (incl. Casa fitting) for each block.""" comments = {} if "Casa Info Follows" in comment_list[0]: diff --git a/pynxtools_xps/vms/vamas_data_model.py b/pynxtools_xps/vms/vamas_data_model.py index 35797b70..7fb4d4e5 100644 --- a/pynxtools_xps/vms/vamas_data_model.py +++ b/pynxtools_xps/vms/vamas_data_model.py @@ -21,9 +21,11 @@ from dataclasses import dataclass, field +from pynxtools_xps.reader_utils import XpsDataclass + @dataclass -class VamasHeader: +class VamasHeader(XpsDataclass): """An object to store the Vamas header information.""" format_id: str = ( @@ -51,7 +53,7 @@ class VamasHeader: @dataclass -class VamasBlock: +class VamasBlock(XpsDataclass): """An object to store a block of spectrum data and meta-data.""" block_id: str = "" From 1ebfd687dd7494df36ab8d9c4dbd4bcd05a4407a Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Thu, 7 Mar 2024 10:02:49 +0100 Subject: [PATCH 10/41] add parsing of header comments --- pynxtools_xps/reader_utils.py | 18 ++++++- pynxtools_xps/vms/vamas.py | 72 +++++++++++++++++++++++---- pynxtools_xps/vms/vamas_data_model.py | 1 - 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/pynxtools_xps/reader_utils.py b/pynxtools_xps/reader_utils.py index 86cec378..48463b84 100644 --- a/pynxtools_xps/reader_utils.py +++ b/pynxtools_xps/reader_utils.py @@ -17,6 +17,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # +import re from abc import ABC, abstractmethod from scipy.interpolate import interp1d import numpy as np @@ -100,9 +101,22 @@ def construct_data(self): """ -def to_snake_case(string_with_whitespace): +def to_snake_case(str_value): """Convert a string to snake_case.""" - return "_".join(word.lower() for word in string_with_whitespace.split()) + if " " in str_value: + return "_".join(word.lower() for word in str_value.split()) + return convert_pascal_to_snake(str_value) + + +def convert_pascal_to_snake(str_value): + """Convert pascal case text to snake case.""" + pattern = re.compile(r"(? Date: Fri, 8 Mar 2024 16:12:21 +0100 Subject: [PATCH 11/41] enable parsing of irregular vms files --- pynxtools_xps/vms/vamas.py | 951 +++++++++++++++---------------------- 1 file changed, 387 insertions(+), 564 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index cd916cbf..b3c1409e 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -37,6 +37,7 @@ construct_data_key, construct_detector_data_key, to_snake_case, + get_minimal_step, ) @@ -50,14 +51,7 @@ class VamasMapper(XPSMapper): def __init__(self): self.file = None - self.parsers = [ - VamasParserRegular, - VamasParserIrregular, - ] - self.parser_map = { - "regular": VamasParserRegular, - "irregular": VamasParserIrregular, - } + self.parsers = [] self.units = { "instrument/sample_normal_polarangle_tilt": "degree ", @@ -92,21 +86,7 @@ def _select_parser(self): Vamas parser for reading this file structure. """ - vms_type = self._get_vms_type() - return self.parser_map[vms_type]() - - def _get_vms_type(self): - """Check if the vamas file is regular or irregular""" - contents = [] - with open(self.file, "rb") as vms_file: - for line in vms_file: - if line.endswith(b"\r\n"): - contents += [line.decode("utf-8", errors="ignore").strip()] - - for vms_type in self.parser_map: - if vms_type.upper() in contents: - return vms_type - return "" + return VamasParser() def construct_data(self): """Map VMS format to NXmpes-ready dict.""" @@ -310,7 +290,7 @@ def _get_units_for_key(self, unit_key): return "" -class VamasParser(ABC): +class VamasParser: """A parser for reading vamas files.""" def __init__(self): @@ -506,6 +486,7 @@ def parse_file(self, file): return self.build_list() def _read_lines(self, file): + """Read in vamas text file.""" with open(file, "rb") as vms_file: for line in vms_file: if line.endswith(b"\r\n"): @@ -546,34 +527,288 @@ def _add_exp_var(self): setattr(self.header, attr, self.data.pop(0).strip()) def _parse_blocks(self): + """Parse all (metadata) of Vamas blocks.""" for _ in range(int(self.header.no_blocks)): self._parse_one_block() def _parse_one_block(self): + """Parse one Vamas Block.""" if self.header.exp_mode == "NORM": self.blocks += [self._parse_norm_block()] elif self.header.exp_mode == "MAP": self.blocks += [self._parse_map_block()] - @abstractmethod def _parse_norm_block(self): """ Use this method when the NORM keyword is present. - This method has to be implemented in the inherited parsers. + Returns + ------- + block : vamas.Block object. + A block represents one spectrum with its metadata. """ - return VamasBlock() + # pylint: disable=too-many-statements + block = VamasBlock() + block.block_id = self.data.pop(0).strip() + block.sample_id = self.data.pop(0).strip() + block.year = int(self.data.pop(0).strip()) + block.month = int(self.data.pop(0).strip()) + block.day = int(self.data.pop(0).strip()) + block.hour = int(self.data.pop(0).strip()) + block.minute = int(self.data.pop(0).strip()) + block.second = int(self.data.pop(0).strip().split(".")[0]) + block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) + block.no_comment_lines = int(self.data.pop(0).strip()) + for _ in range(block.no_comment_lines): + block.comment_lines += [self.data.pop(0)] + block.technique = self.data.pop(0).strip() + for _ in range(int(self.header.nr_exp_var)): + block.exp_var_value = self.data.pop(0).strip() + block.source_label = self.data.pop(0).strip() + block.source_energy = float(self.data.pop(0).strip()) + block.unknown_1 = self.data.pop(0).strip() + block.unknown_2 = self.data.pop(0).strip() + block.unknown_3 = self.data.pop(0).strip() + block.source_analyzer_angle = self.data.pop(0).strip() + block.unknown_4 = self.data.pop(0).strip() + block.analyzer_mode = self.data.pop(0).strip() + block.resolution = float(self.data.pop(0).strip()) + block.magnification = self.data.pop(0).strip() + block.work_function = float(self.data.pop(0).strip()) + block.target_bias = float(self.data.pop(0).strip()) + block.analyzer_width_x = self.data.pop(0).strip() + block.analyzer_width_y = self.data.pop(0).strip() + block.analyzer_take_off_polar_angle = self.data.pop(0).strip() + block.analyzer_azimuth = self.data.pop(0).strip() + block.species_label = self.data.pop(0).strip() + block.transition_label = self.data.pop(0).strip() + block.particle_charge = self.data.pop(0).strip() + + if self.header.scan_mode == "REGULAR": + block.abscissa_label = self.data.pop(0).strip() + block.abscissa_units = self.data.pop(0).strip() + block.abscissa_start = float(self.data.pop(0).strip()) + block.abscissa_step = float(self.data.pop(0).strip()) + + block.no_variables = int(self.data.pop(0).strip()) + for var in range(block.no_variables): + name = "variable_label_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + name = "variable_units_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + + else: + block.no_variables = int(self.data.pop(0).strip()) - 1 + block.abscissa_label = self.data.pop(0).strip() + block.abscissa_units = self.data.pop(0).strip() + for var in range(block.no_variables): + name = "variable_label_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + name = "variable_units_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + + block.signal_mode = self.data.pop(0).strip() + block.dwell_time = float(self.data.pop(0).strip()) + block.no_scans = int(self.data.pop(0).strip()) + block.time_correction = self.data.pop(0).strip() + block.sample_angle_tilt = float(self.data.pop(0).strip()) + block.sample_tilt_azimuth = float(self.data.pop(0).strip()) + block.sample_rotation = float(self.data.pop(0).strip()) + block.no_additional_params = int(self.data.pop(0).strip()) + for param in range(block.no_additional_params): + name = "param_label_" + str(param + 1) + setattr(block, name, self.data.pop(0)) + name = "param_unit_" + str(param + 1) + setattr(block, name, self.data.pop(0)) + name = "param_value_" + str(param + 1) + setattr(block, name, self.data.pop(0)) + block.num_ord_values = int(self.data.pop(0).strip()) + if self.header.scan_mode == "IRREGULAR": + del self.data[:2] + for var in range(block.no_variables): + name = "min_ord_value_" + str(var + 1) + setattr(block, name, float(self.data.pop(0).strip())) + name = "max_ord_value_" + str(var + 1) + setattr(block, name, float(self.data.pop(0).strip())) - @abstractmethod - def _parse_map_block(self): + self._add_data_values(block) + return block + + def _parse_map_block(self, regular: bool = True): """ Use this method when the MAP keyword is present. - This method has to be implemented in the inherited parsers. + Returns + ------- + block : vamas.Block object. + A block represents one spectrum with its metadata. """ - return VamasBlock() + # pylint: disable=too-many-statements + block = VamasBlock() + block.block_id = self.data.pop(0).strip() + block.sample_id = self.data.pop(0).strip() + block.year = int(self.data.pop(0).strip()) + block.month = int(self.data.pop(0).strip()) + block.day = int(self.data.pop(0).strip()) + block.hour = int(self.data.pop(0).strip()) + block.minute = int(self.data.pop(0).strip()) + block.second = int(self.data.pop(0).strip()) + block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) + block.no_comment_lines = int(self.data.pop(0).strip()) + for _ in range(block.no_comment_lines): + self.data.pop(0) + block.comment_lines += [self.data.pop(0)] + block.technique = self.data.pop(0).strip() + block.x_coord = self.data.pop(0).strip() + block.y_coord = self.data.pop(0).strip() + block.exp_var_value = self.data.pop(0).strip() + block.source_label = self.data.pop(0).strip() + block.source_energy = float(self.data.pop(0).strip()) + block.unknown_1 = self.data.pop(0).strip() + block.unknown_2 = self.data.pop(0).strip() + block.unknown_3 = self.data.pop(0).strip() + block.fov_x = self.data.pop(0).strip() + block.fov_y = self.data.pop(0).strip() + block.source_analyzer_angle = self.data.pop(0).strip() + block.unknown_4 = self.data.pop(0).strip() + block.analyzer_mode = self.data.pop(0).strip() + block.resolution = float(self.data.pop(0).strip()) + block.magnification = self.data.pop(0).strip() + block.work_function = float(self.data.pop(0).strip()) + block.target_bias = float(self.data.pop(0).strip()) + block.analyzer_width_x = self.data.pop(0).strip() + block.analyzer_width_y = self.data.pop(0).strip() + block.analyzer_take_off_polar_angle = self.data.pop(0).strip() + block.analyzer_azimuth = self.data.pop(0).strip() + block.species_label = self.data.pop(0).strip() + block.transition_label = self.data.pop(0).strip() + block.particle_charge = self.data.pop(0).strip() + + if self.header.scan_mode == "REGULAR": + block.abscissa_label = self.data.pop(0).strip() + block.abscissa_units = self.data.pop(0).strip() + block.abscissa_start = float(self.data.pop(0).strip()) + block.abscissa_step = float(self.data.pop(0).strip()) + + block.no_variables = int(self.data.pop(0).strip()) + for var in range(block.no_variables): + name = "variable_label_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + name = "variable_units_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + + else: + block.no_variables = int(self.data.pop(0).strip()) - 1 + block.abscissa_label = self.data.pop(0).strip() + block.abscissa_units = self.data.pop(0).strip() + for var in range(block.no_variables): + name = "variable_label_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + name = "variable_units_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + + block.signal_mode = self.data.pop(0).strip() + block.dwell_time = float(self.data.pop(0).strip()) + block.no_scans = int(self.data.pop(0).strip()) + block.time_correction = self.data.pop(0).strip() + block.sample_angle_tilt = float(self.data.pop(0).strip()) + block.sample_tilt_azimuth = float(self.data.pop(0).strip()) + block.sample_rotation = float(self.data.pop(0).strip()) + block.no_additional_params = int(self.data.pop(0).strip()) + for param in range(block.no_additional_params): + name = "param_label_" + str(param + 1) + setattr(block, name, self.data.pop(0)) + name = "param_unit_" + str(param + 1) + setattr(block, name, self.data.pop(0)) + name = "param_value_" + str(param + 1) + setattr(block, name, self.data.pop(0)) + block.num_ord_values = int(self.data.pop(0).strip()) + if self.header.scan_mode == "IRREGULAR": + del self.data[:2] + for var in range(block.no_variables): + name = "min_ord_value_" + str(var + 1) + setattr(block, name, float(self.data.pop(0).strip())) + name = "max_ord_value_" + str(var + 1) + setattr(block, name, float(self.data.pop(0).strip())) + + self._add_data_values(block) + + return block + + def _add_data_values(self, block): + """Add data values to a Vamas data block.""" + if self.header.scan_mode == "REGULAR": + self._add_regular_data(block) + elif self.header.scan_mode == "IRREGULAR": + self._add_irregular_data(block) + + def _add_regular_data(self, block): + """Parse data with regularly spaced energy axis.""" + data_dict = {} + start = float(block.abscissa_start) + step = float(block.abscissa_step) + num = int(block.num_ord_values / block.no_variables) + energy = [round(start + i * step, 2) for i in range(num)] + + if block.abscissa_label == "binding energy": + energy.reverse() + + setattr(block, "x", energy) + + for var in range(block.no_variables): + if var == 0: + name = "y" + else: + name = "y" + str(var) + data_dict[name] = [] + + data_array = list(np.array(self.data[: block.num_ord_values], dtype=float)) + + self.data = self.data[block.num_ord_values :] + + for var in range(block.no_variables): + max_var = block.no_variables + if var == 0: + name = "y" + else: + name = "y" + str(var) + data_array_slice = data_array[var::max_var] + data_dict[name] = data_array_slice + setattr(block, name, data_dict[name]) + + def _add_irregular_data(self, block): + """Parse data with regularly spaced energy axis.""" + data_dict = {} + + block_data = list(np.array(self.data[: block.num_ord_values], dtype=float)) + + energy = block_data[:: block.no_variables + 1] + if block.abscissa_label == "binding energy": + energy.reverse() + block.x = energy + block.abscissa_start = min(energy) + block.abscissa_stop = max(energy) + block.abscissa_step = get_minimal_step(energy) + + for var in range(block.no_variables): + if var == 0: + name = "y" + else: + name = "y" + str(var) + data_dict[name] = [] + + for var in range(block.no_variables): + if var == 0: + name = "y" + else: + name = "y" + str(var) + data_array_slice = block_data[var + 1 :: block.no_variables + 1] + data_dict[name] = data_array_slice + setattr(block, name, data_dict[name]) + + self.data = self.data[block.num_ord_values + block.no_variables :] def _get_scan_numbers_for_spectra(self, spectra): """ @@ -610,146 +845,34 @@ def _get_scan_numbers_for_spectra(self, spectra): return flattened_spectra - def build_list(self): - """ - Construct a list of dictionaries from the Vamas objects + def handle_header_comments(self, comment_list): + """Handle comments (incl. Casa info) for the header.""" + comments = {} - Returns - ------- - List - Each list element is a dictionary with the data and - metadata of one spectrum. + special_keys = { + "Casa Info Follows": self._handle_casa_header, + "SpecsLab Prodigy": self._handle_prodigy_header, + # "SOFH": self._handle_phi_header, + } - """ - group_id = -1 - temp_group_name = "" - spectra = [] + for keyword, handle_func in special_keys.items(): + if any(keyword in line for line in comment_list): + index = [i for i, line in enumerate(comment_list) if keyword in line][0] - header_dict = {to_snake_case(k): v for (k, v) in self.header.dict().items()} - del header_dict["comment_lines"] - header_dict.update(self.handle_header_comments(self.header.comment_lines)) + if keyword == "Casa Info Follows": + special_comments = comment_list[index] + comment_list = comment_list[index + 1 :] - for spectrum_id, block in enumerate(self.blocks): - group_name = block.sample_id - # This set of conditions detects if the group name has changed. - # If it has, then it increments the group_idx. - if group_name != temp_group_name: - temp_group_name = group_name - group_id += 1 + if keyword == "SpecsLab Prodigy": + special_comments = comment_list[index] + comment_list = comment_list[index + 1 :] - spectrum_type = str(block.species_label + block.transition_label) - - settings = { - "region": block.block_id, - "sample_name": block.sample_id, - "analysis_method": block.technique, - "source_label": block.source_label, - "excitation_energy": block.source_energy, - "source_analyzer_angle": block.source_analyzer_angle, - "scan_mode": block.analyzer_mode, - "pass_energy": block.resolution, - "magnification": block.magnification, - "work_function": block.work_function, - "target_bias": block.target_bias, - "analysis_width_x": block.analyzer_width_x, - "analysis_width_y": block.analyzer_width_y, - "analyzer_take_off_polar": block.analyzer_take_off_polar_angle, - "analyzer_take_off_azimuth": block.analyzer_azimuth, - "element": block.species_label, - "transition": block.transition_label, - "particle_charge": block.particle_charge, - "x_label": block.abscissa_label, - "x_units": block.abscissa_units, - "start_energy": block.abscissa_start, - "step_size": block.abscissa_step, - "y_labels_1": block.variable_label_1, - "y_units_1": block.variable_units_1, - "y_labels_2": block.variable_label_2, - "y_units_2": block.variable_units_2, - "signal_mode": block.signal_mode, - "dwell_time": block.dwell_time, - "time_correction": block.time_correction, - "sample_normal_polarangle_tilt": block.sample_angle_tilt, - "sample_tilt_azimuth": block.sample_tilt_azimuth, - "sample_rotation_angle": block.sample_rotation, - "n_values": int(block.num_ord_values / block.no_variables), - } - settings.update(header_dict) - - # Convert the native time format to the datetime string - # in the ISO 8601 format - tzinfo = datetime.timezone( - datetime.timedelta(hours=block.no_hrs_in_advance_of_gmt) - ) - date_time = datetime.datetime( - block.year, - block.month, - block.day, - block.hour, - block.minute, - block.second, - tzinfo=tzinfo, - ) - - data = {"x": block.x} - for var in range(int(block.no_variables)): - if var == 0: - key = "y" - - data["y"] = getattr(block, "y") - - if block.variable_label_1 in ["Intensity", "counts"]: - y_cps = [np.round(y / block.dwell_time, 2) for y in block.y] - data["y_cps"] = y_cps - - else: - key = "y" + str(var) - data[key] = getattr(block, key) - - spec_dict = { - "time_stamp": date_time, - "group_name": group_name, - "group_id": group_id, - "spectrum_type": spectrum_type, - "spectrum_id": spectrum_id, - "scans": block.no_scans, - "data": data, - } - spec_dict.update(settings) - spectra += [spec_dict] - - spectra = self._get_scan_numbers_for_spectra(spectra) - - return spectra - - def handle_header_comments(self, comment_list): - """Handle comments (incl. Casa info) for the header.""" - comments = {} - - special_keys = { - "Casa Info Follows": self._handle_casa_header, - "SpecsLab Prodigy": self._handle_prodigy_header, - # "SOFH": self._handle_phi_header, - } - - for keyword, handle_func in special_keys.items(): - if any(keyword in line for line in comment_list): - index = [i for i, line in enumerate(comment_list) if keyword in line][0] - - if keyword == "Casa Info Follows": - special_comments = comment_list[index] - comment_list = comment_list[index + 1 :] - - if keyword == "SpecsLab Prodigy": - special_comments = comment_list[index] - comment_list = comment_list[index + 1 :] - - if keyword == "SOFH": - end_index = [ - i for i, line in enumerate(comment_list) if "EOFH" in line - ][0] - special_comments = comment_list[index : end_index + 1] - del comment_list[index : end_index + 1] + if keyword == "SOFH": + end_index = [ + i for i, line in enumerate(comment_list) if "EOFH" in line + ][0] + special_comments = comment_list[index : end_index + 1] + del comment_list[index : end_index + 1] comments.update(handle_func(special_comments)) @@ -834,420 +957,120 @@ def handle_block_comments(self, comment_list): continue return comments - -class VamasParserRegular(VamasParser): - """Parser for .vms files of type REGULAR""" - - def _parse_norm_block(self): + def build_list(self): """ - Use this method when the NORM keyword is present. + Construct a list of dictionaries from the Vamas objects Returns ------- - block : vamas.Block object. - A block represents one spectrum with its metadata. + List + Each list element is a dictionary with the data and + metadata of one spectrum. """ - # pylint: disable=too-many-statements - block = VamasBlock() - block.block_id = self.data.pop(0).strip() - block.sample_id = self.data.pop(0).strip() - block.year = int(self.data.pop(0).strip()) - block.month = int(self.data.pop(0).strip()) - block.day = int(self.data.pop(0).strip()) - block.hour = int(self.data.pop(0).strip()) - block.minute = int(self.data.pop(0).strip()) - block.second = int(self.data.pop(0).strip().split(".")[0]) - block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) - block.no_comment_lines = int(self.data.pop(0).strip()) - for _ in range(block.no_comment_lines): - block.comment_lines += [self.data.pop(0)] - block.technique = self.data.pop(0).strip() - for _ in range(int(self.header.nr_exp_var)): - block.exp_var_value = self.data.pop(0).strip() - block.source_label = self.data.pop(0).strip() - block.source_energy = float(self.data.pop(0).strip()) - block.unknown_1 = self.data.pop(0).strip() - block.unknown_2 = self.data.pop(0).strip() - block.unknown_3 = self.data.pop(0).strip() - block.source_analyzer_angle = self.data.pop(0).strip() - block.unknown_4 = self.data.pop(0).strip() - block.analyzer_mode = self.data.pop(0).strip() - block.resolution = float(self.data.pop(0).strip()) - block.magnification = self.data.pop(0).strip() - block.work_function = float(self.data.pop(0).strip()) - block.target_bias = float(self.data.pop(0).strip()) - block.analyzer_width_x = self.data.pop(0).strip() - block.analyzer_width_y = self.data.pop(0).strip() - block.analyzer_take_off_polar_angle = self.data.pop(0).strip() - block.analyzer_azimuth = self.data.pop(0).strip() - block.species_label = self.data.pop(0).strip() - block.transition_label = self.data.pop(0).strip() - block.particle_charge = self.data.pop(0).strip() - block.abscissa_label = self.data.pop(0).strip() - block.abscissa_units = self.data.pop(0).strip() - block.abscissa_start = float(self.data.pop(0).strip()) - block.abscissa_step = float(self.data.pop(0).strip()) - block.no_variables = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "variable_label_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - name = "variable_units_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - block.signal_mode = self.data.pop(0).strip() - block.dwell_time = float(self.data.pop(0).strip()) - block.no_scans = int(self.data.pop(0).strip()) - block.time_correction = self.data.pop(0).strip() - block.sample_angle_tilt = float(self.data.pop(0).strip()) - block.sample_tilt_azimuth = float(self.data.pop(0).strip()) - block.sample_rotation = float(self.data.pop(0).strip()) - block.no_additional_params = int(self.data.pop(0).strip()) - for param in range(block.no_additional_params): - name = "param_label_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_unit_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_value_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - block.num_ord_values = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "min_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) - name = "max_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) - - self._add_data_values(block) - return block + group_id = -1 + temp_group_name = "" + spectra = [] - def _parse_map_block(self): - """ - Use this method when the MAP keyword is present. + header_dict = {to_snake_case(k): v for (k, v) in self.header.dict().items()} + del header_dict["comment_lines"] + header_dict.update(self.handle_header_comments(self.header.comment_lines)) - Returns - ------- - block : vamas.Block object. - A block represents one spectrum with its metadata. + for spectrum_id, block in enumerate(self.blocks): + group_name = block.sample_id + # This set of conditions detects if the group name has changed. + # If it has, then it increments the group_idx. + if group_name != temp_group_name: + temp_group_name = group_name + group_id += 1 - """ - # pylint: disable=too-many-statements - block = VamasBlock() - block.block_id = self.data.pop(0).strip() - block.sample_id = self.data.pop(0).strip() - block.year = int(self.data.pop(0).strip()) - block.month = int(self.data.pop(0).strip()) - block.day = int(self.data.pop(0).strip()) - block.hour = int(self.data.pop(0).strip()) - block.minute = int(self.data.pop(0).strip()) - block.second = int(self.data.pop(0).strip()) - block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) - block.no_comment_lines = int(self.data.pop(0).strip()) - for _ in range(block.no_comment_lines): - self.data.pop(0) - block.comment_lines += [self.data.pop(0)] - block.technique = self.data.pop(0).strip() - block.x_coord = self.data.pop(0).strip() - block.y_coord = self.data.pop(0).strip() - block.exp_var_value = self.data.pop(0).strip() - block.source_label = self.data.pop(0).strip() - block.source_energy = float(self.data.pop(0).strip()) - block.unknown_1 = self.data.pop(0).strip() - block.unknown_2 = self.data.pop(0).strip() - block.unknown_3 = self.data.pop(0).strip() - block.fov_x = self.data.pop(0).strip() - block.fov_y = self.data.pop(0).strip() - block.source_analyzer_angle = self.data.pop(0).strip() - block.unknown_4 = self.data.pop(0).strip() - block.analyzer_mode = self.data.pop(0).strip() - block.resolution = float(self.data.pop(0).strip()) - block.magnification = self.data.pop(0).strip() - block.work_function = float(self.data.pop(0).strip()) - block.target_bias = float(self.data.pop(0).strip()) - block.analyzer_width_x = self.data.pop(0).strip() - block.analyzer_width_y = self.data.pop(0).strip() - block.analyzer_take_off_polar_angle = self.data.pop(0).strip() - block.analyzer_azimuth = self.data.pop(0).strip() - block.species_label = self.data.pop(0).strip() - block.transition_label = self.data.pop(0).strip() - block.particle_charge = self.data.pop(0).strip() - block.abscissa_label = self.data.pop(0).strip() - block.abscissa_units = self.data.pop(0).strip() - block.abscissa_start = float(self.data.pop(0).strip()) - block.abscissa_step = float(self.data.pop(0).strip()) - block.no_variables = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "variable_label_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - name = "variable_units_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - block.signal_mode = self.data.pop(0).strip() - block.dwell_time = float(self.data.pop(0).strip()) - block.no_scans = int(self.data.pop(0).strip()) - block.time_correction = self.data.pop(0).strip() - block.sample_angle_tilt = float(self.data.pop(0).strip()) - block.sample_tilt_azimuth = float(self.data.pop(0).strip()) - block.sample_rotation = float(self.data.pop(0).strip()) - block.no_additional_params = int(self.data.pop(0).strip()) - for param in range(block.no_additional_params): - name = "param_label_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_unit_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_value_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - block.num_ord_values = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "min_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) - name = "max_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) + spectrum_type = str(block.species_label + block.transition_label) - self._add_data_values(block) - - return block - - def _add_data_values(self, block): - """Add data values to a Vamas data block.""" - data_dict = {} - start = float(block.abscissa_start) - step = float(block.abscissa_step) - num = int(block.num_ord_values / block.no_variables) - energy = [round(start + i * step, 2) for i in range(num)] - - if block.abscissa_label == "binding energy": - energy.reverse() - - setattr(block, "x", energy) - - for var in range(block.no_variables): - if var == 0: - name = "y" - else: - name = "y" + str(var) - data_dict[name] = [] - - data_array = list(np.array(self.data[: block.num_ord_values], dtype=float)) - - self.data = self.data[block.num_ord_values :] - - for var in range(block.no_variables): - max_var = block.no_variables - if var == 0: - name = "y" - else: - name = "y" + str(var) - data_array_slice = data_array[var::max_var] - data_dict[name] = data_array_slice - setattr(block, name, data_dict[name]) - - -# THIS DOESN'T WORK SO FAR!! -class VamasParserIrregular(VamasParser): - """Parser for .vms files of type IRREGULAR""" - - def _parse_norm_block(self): - """ - Use this method when the NORM keyword is present. - - Returns - ------- - block : vamas.Block object. - A block represents one spectrum with its metadata. - - """ - # pylint: disable=too-many-statements - block = VamasBlock() - block.block_id = self.data.pop(0).strip() - block.sample_id = self.data.pop(0).strip() - block.year = int(self.data.pop(0).strip()) - block.month = int(self.data.pop(0).strip()) - block.day = int(self.data.pop(0).strip()) - block.hour = int(self.data.pop(0).strip()) - block.minute = int(self.data.pop(0).strip()) - block.second = int(self.data.pop(0).strip().split(".")[0]) - block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) - block.no_comment_lines = int(self.data.pop(0).strip()) - for _ in range(block.no_comment_lines): - block.comment_lines += [self.data.pop(0)] - block.technique = self.data.pop(0).strip() - for _ in range(int(self.header.nr_exp_var)): - block.exp_var_value = self.data.pop(0).strip() - block.source_label = self.data.pop(0).strip() - block.source_energy = float(self.data.pop(0).strip()) - block.unknown_1 = self.data.pop(0).strip() - block.unknown_2 = self.data.pop(0).strip() - block.unknown_3 = self.data.pop(0).strip() - block.source_analyzer_angle = self.data.pop(0).strip() - block.unknown_4 = self.data.pop(0).strip() - block.analyzer_mode = self.data.pop(0).strip() - block.resolution = float(self.data.pop(0).strip()) - block.magnification = self.data.pop(0).strip() - block.work_function = float(self.data.pop(0).strip()) - block.target_bias = float(self.data.pop(0).strip()) - block.analyzer_width_x = self.data.pop(0).strip() - block.analyzer_width_y = self.data.pop(0).strip() - block.analyzer_take_off_polar_angle = self.data.pop(0).strip() - block.analyzer_azimuth = self.data.pop(0).strip() - block.species_label = self.data.pop(0).strip() - block.transition_label = self.data.pop(0).strip() - block.particle_charge = self.data.pop(0).strip() - block.abscissa_label = self.data.pop(0).strip() - block.abscissa_units = self.data.pop(0).strip() - block.abscissa_start = float(self.data.pop(0).strip()) - block.abscissa_step = float(self.data.pop(0).strip()) - block.no_variables = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "variable_label_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - name = "variable_units_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - block.signal_mode = self.data.pop(0).strip() - block.dwell_time = float(self.data.pop(0).strip()) - block.no_scans = int(self.data.pop(0).strip()) - block.time_correction = self.data.pop(0).strip() - block.sample_angle_tilt = float(self.data.pop(0).strip()) - block.sample_tilt_azimuth = float(self.data.pop(0).strip()) - block.sample_rotation = float(self.data.pop(0).strip()) - block.no_additional_params = int(self.data.pop(0).strip()) - for param in range(block.no_additional_params): - name = "param_label_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_unit_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_value_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - block.num_ord_values = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "min_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) - name = "max_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) - - self._add_data_values(block) - return block - - def _parse_map_block(self): - """ - Use this method when the MAP keyword is present. - - Returns - ------- - block : vamas.Block object. - A block represents one spectrum with its metadata. - - """ - # pylint: disable=too-many-statements - block = VamasBlock() - block.block_id = self.data.pop(0).strip() - block.sample_id = self.data.pop(0).strip() - block.year = int(self.data.pop(0).strip()) - block.month = int(self.data.pop(0).strip()) - block.day = int(self.data.pop(0).strip()) - block.hour = int(self.data.pop(0).strip()) - block.minute = int(self.data.pop(0).strip()) - block.second = int(self.data.pop(0).strip()) - block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) - block.no_comment_lines = int(self.data.pop(0).strip()) - for _ in range(block.no_comment_lines): - self.data.pop(0) - block.comment_lines += [self.data.pop(0)] - block.technique = self.data.pop(0).strip() - block.x_coord = self.data.pop(0).strip() - block.y_coord = self.data.pop(0).strip() - block.exp_var_value = self.data.pop(0).strip() - block.source_label = self.data.pop(0).strip() - block.source_energy = float(self.data.pop(0).strip()) - block.unknown_1 = self.data.pop(0).strip() - block.unknown_2 = self.data.pop(0).strip() - block.unknown_3 = self.data.pop(0).strip() - block.fov_x = self.data.pop(0).strip() - block.fov_y = self.data.pop(0).strip() - block.source_analyzer_angle = self.data.pop(0).strip() - block.unknown_4 = self.data.pop(0).strip() - block.analyzer_mode = self.data.pop(0).strip() - block.resolution = float(self.data.pop(0).strip()) - block.magnification = self.data.pop(0).strip() - block.work_function = float(self.data.pop(0).strip()) - block.target_bias = float(self.data.pop(0).strip()) - block.analyzer_width_x = self.data.pop(0).strip() - block.analyzer_width_y = self.data.pop(0).strip() - block.analyzer_take_off_polar_angle = self.data.pop(0).strip() - block.analyzer_azimuth = self.data.pop(0).strip() - block.species_label = self.data.pop(0).strip() - block.transition_label = self.data.pop(0).strip() - block.particle_charge = self.data.pop(0).strip() - block.abscissa_label = self.data.pop(0).strip() - block.abscissa_units = self.data.pop(0).strip() - block.abscissa_start = float(self.data.pop(0).strip()) - block.abscissa_step = float(self.data.pop(0).strip()) - block.no_variables = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "variable_label_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - name = "variable_units_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - block.signal_mode = self.data.pop(0).strip() - block.dwell_time = float(self.data.pop(0).strip()) - block.no_scans = int(self.data.pop(0).strip()) - block.time_correction = self.data.pop(0).strip() - block.sample_angle_tilt = float(self.data.pop(0).strip()) - block.sample_tilt_azimuth = float(self.data.pop(0).strip()) - block.sample_rotation = float(self.data.pop(0).strip()) - block.no_additional_params = int(self.data.pop(0).strip()) - for param in range(block.no_additional_params): - name = "param_label_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_unit_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_value_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - block.num_ord_values = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "min_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) - name = "max_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) - - self._add_data_values(block) - - return block + settings = { + "region": block.block_id, + "sample_name": block.sample_id, + "analysis_method": block.technique, + "source_label": block.source_label, + "excitation_energy": block.source_energy, + "source_analyzer_angle": block.source_analyzer_angle, + "scan_mode": block.analyzer_mode, + "pass_energy": block.resolution, + "magnification": block.magnification, + "work_function": block.work_function, + "target_bias": block.target_bias, + "analysis_width_x": block.analyzer_width_x, + "analysis_width_y": block.analyzer_width_y, + "analyzer_take_off_polar": block.analyzer_take_off_polar_angle, + "analyzer_take_off_azimuth": block.analyzer_azimuth, + "element": block.species_label, + "transition": block.transition_label, + "particle_charge": block.particle_charge, + "x_label": block.abscissa_label, + "x_units": block.abscissa_units, + "start_energy": block.abscissa_start, + "step_size": block.abscissa_step, + "y_labels_1": block.variable_label_1, + "y_units_1": block.variable_units_1, + "y_labels_2": block.variable_label_2, + "y_units_2": block.variable_units_2, + "signal_mode": block.signal_mode, + "dwell_time": block.dwell_time, + "time_correction": block.time_correction, + "sample_normal_polarangle_tilt": block.sample_angle_tilt, + "sample_tilt_azimuth": block.sample_tilt_azimuth, + "sample_rotation_angle": block.sample_rotation, + "n_values": int(block.num_ord_values / block.no_variables), + } + settings.update(header_dict) - def _add_data_values(self, block): - """Add data values to a Vamas data block.""" - data_dict = {} - start = float(block.abscissa_start) - step = float(block.abscissa_step) - num = int(block.num_ord_values / block.no_variables) - energy = [round(start + i * step, 2) for i in range(num)] + comment_dict = self.handle_block_comments(block.comment_lines) + settings.update(comment_dict) - if block.abscissa_label == "binding energy": - energy.reverse() + # Convert the native time format to the datetime string + # in the ISO 8601 format + tzinfo = datetime.timezone( + datetime.timedelta(hours=block.no_hrs_in_advance_of_gmt) + ) + try: + date_time = datetime.datetime( + block.year, + block.month, + block.day, + block.hour, + block.minute, + block.second, + tzinfo=tzinfo, + ) + except ValueError: + date_time = datetime.datetime.min - setattr(block, "x", energy) + data = {"x": block.x} + for var in range(int(block.no_variables)): + if var == 0: + key = "y" - for var in range(block.no_variables): - if var == 0: - name = "y" - else: - name = "y" + str(var) - data_dict[name] = [] + data["y"] = getattr(block, "y") - data_array = list(np.array(self.data[: block.num_ord_values], dtype=float)) + if block.variable_label_1 in ["Intensity", "counts"]: + y_cps = [np.round(y / block.dwell_time, 2) for y in block.y] + data["y_cps"] = y_cps - self.data = self.data[block.num_ord_values :] + else: + key = "y" + str(var) + data[key] = getattr(block, key) - for var in range(block.no_variables): - max_var = block.no_variables - if var == 0: - name = "y" - else: - name = "y" + str(var) - data_array_slice = data_array[var::max_var] - data_dict[name] = data_array_slice - setattr(block, name, data_dict[name]) + spec_dict = { + "time_stamp": date_time, + "group_name": group_name, + "group_id": group_id, + "spectrum_type": spectrum_type, + "spectrum_id": spectrum_id, + "scans": block.no_scans, + "data": data, + } + spec_dict.update(settings) + spectra += [spec_dict] + spectra = self._get_scan_numbers_for_spectra(spectra) -if __name__ == "__main__": - file = r"C:\Users\pielsticker\Lukas\FAIRMat\user_cases\Schumann_XPS_Catalysis\C2 Activated Vamas Files\CleanData-alphaII VOPO4 C2 BC4316.vms" - parser = VamasParserRegular() - d = parser.parse_file(file) - d0 = d[0] + return spectra From 8d4e02964dba6e5fe1f775b8f12354db318c9458 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 8 Mar 2024 16:51:07 +0100 Subject: [PATCH 12/41] improve static typing --- pynxtools_xps/vms/vamas.py | 99 +++++++++++++++------------ pynxtools_xps/vms/vamas_data_model.py | 64 ++++++++--------- 2 files changed, 87 insertions(+), 76 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index b3c1409e..92b16da5 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -22,7 +22,9 @@ import re from copy import deepcopy import datetime -from abc import ABC, abstractmethod +from pathlib import Path +from typing import Any, Dict, List, Union + from itertools import groupby import xarray as xr import numpy as np @@ -50,10 +52,10 @@ class VamasMapper(XPSMapper): config_file = "config_vms.json" def __init__(self): - self.file = None - self.parsers = [] + self.file: Union[str, Path] = "" + self.parsers: List[Any] = [] - self.units = { + self.units: dict = { "instrument/sample_normal_polarangle_tilt": "degree ", "instrument/sample_tilt_azimuth": "degree", "instrument/sample_rotation_angle": "degree", @@ -93,7 +95,7 @@ def construct_data(self): # pylint: disable=duplicate-code spectra = deepcopy(self.raw_data) - self._xps_dict["data"]: dict = {} + self._xps_dict["data"]: Dict[str, Any] = {} key_map = { "user": [], @@ -158,7 +160,9 @@ def construct_data(self): for spectrum in spectra: self._update_xps_dict_with_spectrum(spectrum, key_map) - def _update_xps_dict_with_spectrum(self, spectrum, key_map): + def _update_xps_dict_with_spectrum( + self, spectrum: Dict[str, Any], key_map: Dict[str, str] + ): """Map one spectrum from raw data to NXmpes-ready dict.""" # pylint: disable=too-many-locals,duplicate-code group_parent = f'{self._root_path}/Group_{spectrum["group_name"]}' @@ -166,7 +170,7 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): instrument_parent = f"{region_parent}/instrument" analyser_parent = f"{instrument_parent}/analyser" - path_map = { + path_map: Dict[str, str] = { "user": f"{region_parent}/user", "instrument": f"{instrument_parent}", "source": f"{instrument_parent}/source", @@ -197,14 +201,14 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): self._xps_dict[f"{root}/{mpes_key}/@units"] = units # Write process data - process_key_map = { + process_key_map: Dict[str, List[str]] = { "energy_referencing": ["alignments"], "peak_fitting": ["regions", "components"], } - for grouping, spectrum_keys in process_key_map.items(): + for grouping, process_key_list in process_key_map.items(): root = path_map[str(grouping)] - for spectrum_key in spectrum_keys: + for spectrum_key in process_key_list: try: processes = spectrum[spectrum_key] for i, process in enumerate(processes): @@ -265,7 +269,7 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): if spectrum_key not in used_keys: self._xps_dict[f"{region_parent}/{spectrum_key}"] = value - def _get_units_for_key(self, unit_key): + def _get_units_for_key(self, unit_key: str): """ Get correct units for a given key. @@ -302,10 +306,10 @@ def __init__(self): vamas attribute keys, which are used, depending on how the vamas file is formatted. """ - self.data = [] + self.data: List[str] = [] self.header = VamasHeader() - self.blocks = [] + self.blocks: List[VamasBlock] = [] self.attrs = { "common_header": [ @@ -472,7 +476,7 @@ def __init__(self): ], } - def parse_file(self, file): + def parse_file(self, file: Union[str, Path]): """Parse the vamas file into a list of dictionaries. Parameters @@ -485,7 +489,7 @@ def parse_file(self, file): self._parse_blocks() return self.build_list() - def _read_lines(self, file): + def _read_lines(self, file: Union[str, Path]): """Read in vamas text file.""" with open(file, "rb") as vms_file: for line in vms_file: @@ -521,7 +525,10 @@ def _parse_header(self): if attr == "nr_exp_var": self._add_exp_var() + self.header.validate_types() + def _add_exp_var(self): + """Add experimental variable to header.""" for _ in range(int(self.header.nr_exp_var)): for attr in self.attrs["exp_var"]: setattr(self.header, attr, self.data.pop(0).strip()) @@ -570,20 +577,20 @@ def _parse_norm_block(self): block.unknown_1 = self.data.pop(0).strip() block.unknown_2 = self.data.pop(0).strip() block.unknown_3 = self.data.pop(0).strip() - block.source_analyzer_angle = self.data.pop(0).strip() + block.source_analyzer_angle = float(self.data.pop(0).strip()) block.unknown_4 = self.data.pop(0).strip() block.analyzer_mode = self.data.pop(0).strip() block.resolution = float(self.data.pop(0).strip()) block.magnification = self.data.pop(0).strip() block.work_function = float(self.data.pop(0).strip()) block.target_bias = float(self.data.pop(0).strip()) - block.analyzer_width_x = self.data.pop(0).strip() - block.analyzer_width_y = self.data.pop(0).strip() - block.analyzer_take_off_polar_angle = self.data.pop(0).strip() - block.analyzer_azimuth = self.data.pop(0).strip() + block.analyzer_width_x = float(self.data.pop(0).strip()) + block.analyzer_width_y = float(self.data.pop(0).strip()) + block.analyzer_take_off_polar_angle = float(self.data.pop(0).strip()) + block.analyzer_azimuth = float(self.data.pop(0).strip()) block.species_label = self.data.pop(0).strip() block.transition_label = self.data.pop(0).strip() - block.particle_charge = self.data.pop(0).strip() + block.particle_charge = int(self.data.pop(0).strip()) if self.header.scan_mode == "REGULAR": block.abscissa_label = self.data.pop(0).strip() @@ -633,9 +640,11 @@ def _parse_norm_block(self): setattr(block, name, float(self.data.pop(0).strip())) self._add_data_values(block) + + block.validate_types() return block - def _parse_map_block(self, regular: bool = True): + def _parse_map_block(self): """ Use this method when the MAP keyword is present. @@ -671,20 +680,20 @@ def _parse_map_block(self, regular: bool = True): block.unknown_3 = self.data.pop(0).strip() block.fov_x = self.data.pop(0).strip() block.fov_y = self.data.pop(0).strip() - block.source_analyzer_angle = self.data.pop(0).strip() + block.source_analyzer_angle = float(self.data.pop(0).strip()) block.unknown_4 = self.data.pop(0).strip() block.analyzer_mode = self.data.pop(0).strip() block.resolution = float(self.data.pop(0).strip()) block.magnification = self.data.pop(0).strip() block.work_function = float(self.data.pop(0).strip()) block.target_bias = float(self.data.pop(0).strip()) - block.analyzer_width_x = self.data.pop(0).strip() - block.analyzer_width_y = self.data.pop(0).strip() - block.analyzer_take_off_polar_angle = self.data.pop(0).strip() - block.analyzer_azimuth = self.data.pop(0).strip() + block.analyzer_width_x = float(self.data.pop(0).strip()) + block.analyzer_width_y = float(self.data.pop(0).strip()) + block.analyzer_take_off_polar_angle = float(self.data.pop(0).strip()) + block.analyzer_azimuth = float(self.data.pop(0).strip()) block.species_label = self.data.pop(0).strip() block.transition_label = self.data.pop(0).strip() - block.particle_charge = self.data.pop(0).strip() + block.particle_charge = int(self.data.pop(0).strip()) if self.header.scan_mode == "REGULAR": block.abscissa_label = self.data.pop(0).strip() @@ -737,16 +746,17 @@ def _parse_map_block(self, regular: bool = True): return block - def _add_data_values(self, block): + def _add_data_values(self, block: VamasBlock): """Add data values to a Vamas data block.""" if self.header.scan_mode == "REGULAR": self._add_regular_data(block) elif self.header.scan_mode == "IRREGULAR": self._add_irregular_data(block) - def _add_regular_data(self, block): + def _add_regular_data(self, block: VamasBlock): """Parse data with regularly spaced energy axis.""" - data_dict = {} + data_dict: Dict[str, List] = {} + start = float(block.abscissa_start) step = float(block.abscissa_step) num = int(block.num_ord_values / block.no_variables) @@ -778,19 +788,19 @@ def _add_regular_data(self, block): data_dict[name] = data_array_slice setattr(block, name, data_dict[name]) - def _add_irregular_data(self, block): + def _add_irregular_data(self, block: VamasBlock): """Parse data with regularly spaced energy axis.""" - data_dict = {} + data_dict: Dict[str, List] = {} block_data = list(np.array(self.data[: block.num_ord_values], dtype=float)) energy = block_data[:: block.no_variables + 1] if block.abscissa_label == "binding energy": energy.reverse() - block.x = energy - block.abscissa_start = min(energy) - block.abscissa_stop = max(energy) - block.abscissa_step = get_minimal_step(energy) + + setattr(block, "x", energy) + block.abscissa_start = float(min(energy)) + block.abscissa_step = float(get_minimal_step(energy)) for var in range(block.no_variables): if var == 0: @@ -810,10 +820,11 @@ def _add_irregular_data(self, block): self.data = self.data[block.num_ord_values + block.no_variables :] - def _get_scan_numbers_for_spectra(self, spectra): + def _get_scan_numbers_for_spectra(self, spectra: List[Dict]): """ - For a flat list of spectra, groupby group name and spectrum - type and iteratively give them scan numbers. + For a flat list of spectra dictionaries, group the spectra + by group name and spectrum type and iteratively give them + scan numbers. Parameters ---------- @@ -845,7 +856,7 @@ def _get_scan_numbers_for_spectra(self, spectra): return flattened_spectra - def handle_header_comments(self, comment_list): + def handle_header_comments(self, comment_list: List[str]): """Handle comments (incl. Casa info) for the header.""" comments = {} @@ -871,7 +882,7 @@ def handle_header_comments(self, comment_list): end_index = [ i for i, line in enumerate(comment_list) if "EOFH" in line ][0] - special_comments = comment_list[index : end_index + 1] + special_comments = comment_list[index : end_index + 1] # type: ignore[assignment] del comment_list[index : end_index + 1] comments.update(handle_func(special_comments)) @@ -900,7 +911,7 @@ def _handle_prodigy_header(self, comment_line: str): return {"prodigy_version": comment_line.split("Version")[1].strip()} # ============================================================================= - # def _handle_phi_header(self, comment_list): + # def _handle_phi_header(self, comment_list: List[str]): # """Get metadta from Phi system.""" # phi_parser = PhiParser() # phi_parser.parse_header_into_metadata(comment_list) @@ -919,7 +930,7 @@ def _handle_prodigy_header(self, comment_line: str): # return phi_comments # ============================================================================= - def handle_block_comments(self, comment_list): + def handle_block_comments(self, comment_list: List[str]): """Handle comments (incl. Casa fitting) for each block.""" comments = {} diff --git a/pynxtools_xps/vms/vamas_data_model.py b/pynxtools_xps/vms/vamas_data_model.py index e62a69ab..75d7adf3 100644 --- a/pynxtools_xps/vms/vamas_data_model.py +++ b/pynxtools_xps/vms/vamas_data_model.py @@ -57,72 +57,72 @@ class VamasBlock(XpsDataclass): block_id: str = "" sample_id: str = "" - year: str = "" - month: str = "" - day: str = "" - hour: str = "" - minute: str = "" - second: str = "" - no_hrs_in_advance_of_gmt: str = "0" - no_comment_lines: str = "" + year: int = 0 + month: int = 0 + day: int = 0 + hour: int = 0 + minute: int = 0 + second: int = 0 + no_hrs_in_advance_of_gmt: int = 0 + no_comment_lines: int = 0 # This list should contain one element per for each # line in the comment block comment_lines: list = field(default_factory=list) technique: str = "" exp_var_value: str = "" source_label: str = "" - source_energy: str = "" + source_energy: float = 0.0 unknown_1: str = "0" unknown_2: str = "0" unknown_3: str = "0" - source_analyzer_angle: str = "" + source_analyzer_angle: float = 0.0 unknown_4: str = "180" analyzer_mode: str = "" - resolution: str = "" + resolution: float = 0.0 magnification: str = "1" - work_function: str = "" - target_bias: str = "0" + work_function: float = 0.0 + target_bias: float = 0.0 # analyser slit length divided by the magnification # of the analyser transfer lens - analyzer_width_x: str = "0" - analyzer_width_y: str = "0" + analyzer_width_x: float = 0.0 + analyzer_width_y: float = 0.0 # degrees from upward z-direction, # defined by the sample stage - analyzer_take_off_polar_angle: str = "0" - analyzer_azimuth: str = "0" + analyzer_take_off_polar_angle: float = 0.0 + analyzer_azimuth: float = 0.0 species_label: str = "" transition_label: str = "" - particle_charge: str = "-1" + particle_charge: int = -1 abscissa_label: str = "kinetic energy" abscissa_units: str = "eV" - abscissa_start: str = "" - abscissa_step: str = "" - no_variables: str = "2" + abscissa_start: float = 0.0 + abscissa_step: float = 0.0 + no_variables: int = 2 variable_label_1: str = "counts" variable_units_1: str = "d" variable_label_2: str = "Transmission" variable_units_2: str = "d" signal_mode: str = "pulse counting" - dwell_time: str = "" - no_scans: str = "" + dwell_time: float = 0.0 + no_scans: int = 0 time_correction: str = "0" # degrees from upward z-direction, # defined by the sample stage - sample_angle_tilt: str = "0" + sample_angle_tilt: float = 0.0 # degrees clockwise from the y-direction towards the # operator, defined by the sample stage - sample_tilt_azimuth: str = "0" - sample_rotation: str = "0" - no_additional_params: str = "2" + sample_tilt_azimuth: float = 0.0 + sample_rotation: float = 0.0 + no_additional_params: int = 2 param_label_1: str = "ESCAPE DEPTH TYPE" param_unit_1: str = "d" param_value_1: str = "0" param_label_2: str = "MFP Exponent" param_unit_2: str = "d" param_value_2: str = "0" - num_ord_values: str = "" - min_ord_value_1: str = "" - max_ord_value_1: str = "" - min_ord_value_2: str = "" - max_ord_value_2: str = "" + num_ord_values: int = 0 + min_ord_value_1: float = 0.0 + max_ord_value_1: float = 0.0 + min_ord_value_2: float = 0.0 + max_ord_value_2: float = 0.0 data_string: str = "" From 3bc72a96b13ebce3649b8b17bf5b693daa2872e7 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 8 Mar 2024 17:02:19 +0100 Subject: [PATCH 13/41] small fix to irregular parsing --- pynxtools_xps/vms/vamas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index 92b16da5..e1902b44 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -818,7 +818,7 @@ def _add_irregular_data(self, block: VamasBlock): data_dict[name] = data_array_slice setattr(block, name, data_dict[name]) - self.data = self.data[block.num_ord_values + block.no_variables :] + self.data = self.data[block.num_ord_values :] # + block.no_variables :] def _get_scan_numbers_for_spectra(self, spectra: List[Dict]): """ From e1cbf32d0fd6fd212ad5ddb0b4f490dc66cd840f Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 8 Mar 2024 17:03:03 +0100 Subject: [PATCH 14/41] remove unneeded comments --- pynxtools_xps/vms/vamas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index e1902b44..46e5d29e 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -818,7 +818,7 @@ def _add_irregular_data(self, block: VamasBlock): data_dict[name] = data_array_slice setattr(block, name, data_dict[name]) - self.data = self.data[block.num_ord_values :] # + block.no_variables :] + self.data = self.data[block.num_ord_values :] def _get_scan_numbers_for_spectra(self, spectra: List[Dict]): """ From 9c3b7db7572c279667adf6e28dcee0ca1b2f642a Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Thu, 14 Mar 2024 18:11:57 +0100 Subject: [PATCH 15/41] fix static typing --- pynxtools_xps/reader_utils.py | 8 +++--- pynxtools_xps/vms/vamas.py | 5 ++-- tests/test_reader.py | 49 +++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/pynxtools_xps/reader_utils.py b/pynxtools_xps/reader_utils.py index 48463b84..f8208c52 100644 --- a/pynxtools_xps/reader_utils.py +++ b/pynxtools_xps/reader_utils.py @@ -19,6 +19,8 @@ # import re from abc import ABC, abstractmethod +from typing import Any, Dict, List, Union +from pathlib import Path from scipy.interpolate import interp1d import numpy as np @@ -50,9 +52,9 @@ class XPSMapper(ABC): """Abstract base class from mapping from a parser to NXmpes template""" def __init__(self): - self.file = None - self.raw_data: list = [] - self._xps_dict: dict = {} + self.file: Union[str, Path] = "" + self.raw_data: List[str] = [] + self._xps_dict: Dict[str, Any] = {} self._root_path = "/ENTRY[entry]" self.parser = None diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index 46e5d29e..9a86439e 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -52,7 +52,6 @@ class VamasMapper(XPSMapper): config_file = "config_vms.json" def __init__(self): - self.file: Union[str, Path] = "" self.parsers: List[Any] = [] self.units: dict = { @@ -190,7 +189,7 @@ def _update_xps_dict_with_spectrum( used_keys = [] for grouping, spectrum_keys in key_map.items(): - root = path_map[str(grouping)] + root = path_map[grouping] for spectrum_key in spectrum_keys: mpes_key = spectrum_key.rsplit(" ", 1)[0] self._xps_dict[f"{root}/{mpes_key}"] = spectrum[spectrum_key] @@ -207,7 +206,7 @@ def _update_xps_dict_with_spectrum( } for grouping, process_key_list in process_key_map.items(): - root = path_map[str(grouping)] + root = path_map[grouping] for spectrum_key in process_key_list: try: processes = spectrum[spectrum_key] diff --git a/tests/test_reader.py b/tests/test_reader.py index 1be0a18d..70326871 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -13,6 +13,20 @@ from pynxtools.nexus.nxdl_utils import get_nexus_definitions_path from pynxtools_xps.reader import XPSReader +# from pynxtools_xps.phi.spe_pro_phi import MapperPhi +from pynxtools_xps.sle.sle_specs import SleMapperSpecs + +# from pynxtools_xps.slh.slh_specs import SlhMapperSpecs +from pynxtools_xps.txt.txt_scienta import TxtMapperScienta + +# from pynxtools_xps.txt.txt_specs import TxtMapperSpecs +from pynxtools_xps.txt.txt_vamas_export import ( + TxtMapperVamasExport, +) +from pynxtools_xps.vms.vamas import VamasMapper +from pynxtools_xps.xy.xy_specs import XyMapperSpecs +from pynxtools_xps.xml.xml_specs import XmlMapperSpecs + def test_example_data(): """ @@ -45,3 +59,38 @@ def test_example_data(): assert isinstance(read_data, Template) assert validate_data_dict(template, read_data, root) + + +def test_vms_mapper(): + mapper = VamasMapper + data_dir = os.path.join(os.path.dirname(__file__), "data", "vms") + + files_and_keys = { + "EX889_S1110_MgFe2O4_spent_irregular": { + "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Survey/scan_mode": "REGULAR", + "data['2 S1110, UHV, RT, Epass = 20 eV__MgKLL_1']['cycle0']": 1351, + }, + "EX889_S1110_MgFe2O4_spent_irregular": { + "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Survey/scan_mode": "IRREGULAR", + "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Fe2p/instrument/analyser/energydispersion/scan_mode": "FixedAnalyserTransmission", + "data['2 S1110, UHV, RT, Epass = 20 eV__Fe3s-Si2p-Mg2s']['cycle0']": 761, + }, + } + + # (C["benz"], "20240122_SBenz_102_20240122_SBenz_SnO2_10nm.vms"), + # (r"C:\Users\pielsticker\Lukas\MPI-CEC\Projects\deepxps\RUB MDI\example_spectra_Florian\Co", "Co 2p 0008751 M1.vms"), + # (C["pielst"], C["EX889"], "vms", f"{C['EX889']}_regular.vms"), + ((C["pielst"], C["EX889"], "vms", f"{C['EX889']}_irregular.vms"),) + # (C["schu"], "CleanData-alphaII VOPO4 C2 BC4316.vms"), + # (C["pielst"], C["EX889"], "vms", "d_reg.vms"), + ((C["pielst"], C["EX889"], "vms", "d_irreg.vms"),) + + for vms_file in os.listdir(data_dir): + data = mapper.parse_file(file=file) + + +for k, v in d.items(): + if isinstance(v, str): + # print(k) + if "REG" in v: + print(k) From af4cfe21c5f2db3a3c049455493a17e2ec567143 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 15 Mar 2024 09:12:06 +0100 Subject: [PATCH 16/41] add vms test data --- pynxtools_xps/config/config_vms.json | 582 +++--- tests/data/vms/eln_data.yaml | 147 ++ tests/data/vms/regular.vms | 2798 ++++++++++++++++++++++++++ tests/test_reader.py | 81 +- 4 files changed, 3282 insertions(+), 326 deletions(-) create mode 100644 tests/data/vms/eln_data.yaml create mode 100644 tests/data/vms/regular.vms diff --git a/pynxtools_xps/config/config_vms.json b/pynxtools_xps/config/config_vms.json index fabe167d..822df788 100644 --- a/pynxtools_xps/config/config_vms.json +++ b/pynxtools_xps/config/config_vms.json @@ -1,289 +1,293 @@ -{ - "/@default":"entry", - "/ENTRY[entry]":{ - "@default":"data", - "definition":"@eln", - "definition/@version":"@eln", - "title":"@eln", - "start_time":"@xps_token:region/time_stamp", - "end_time":"@eln", - "experiment_institution":"@eln", - "experiment_facility":"@eln", - "experiment_laboratory":"@eln", - "entry_identifier":"@eln", - "duration":"None", - "duration/@units":"s", - "method":"@xps_token:region/analysis_method", - "program_name":"@eln" - }, - "/ENTRY[entry]/USER[user]":{ - "name":"@eln", - "affiliation":"@eln", - "address":"@eln", - "orcid":"@eln", - "email":"@eln" - }, - "/ENTRY[entry]/INSTRUMENT[instrument]":{ - "device_information":{ - "vendor":"@eln", - "identifier":"@eln", - "model":"@eln" - }, - "energy_resolution":{ - "physical_quantity":"energy", - "type":"derived", - "resolution":"@xps_token:data/step_size", - "resolution/@units":"eV" - }, - "source_TYPE[source_probe]":{ - "type":"@eln", - "name":"@xps_token:source/source_label", - "probe":"photon", - "device_information":{ - "vendor":"@eln", - "identifier":"@eln", - "model":"@eln" - }, - "associated_beam":"@link:/entry/instrument/beam_probe", - "source_analyzer_angle": "source_analyzer_angle", - "source_analyzer_angle/@units": "degree" - }, - "beam_TYPE[beam_probe]":{ - "distance":"@eln", - "distance/@units":"@eln", - "incident_energy":"@xps_token:beam/excitation_energy", - "incident_energy/@units":"eV", - "incident_energy_spread":"None", - "incident_energy_spread/@units":"None", - "incident_polarization":"None", - "incident_polarization/@units":"None", - "extent":"None", - "associated_source":"@link:/entry/instrument/source_probe" - }, - "ELECTRONANALYSER[electronanalyser]":{ - "@default": "detector0", - "name":"@xps_token:analyser/analyser_name", - "description":"@eln", - "work_function":"@xps_token:analyser/work_function", - "work_function/@units":"eV", - "fast_axes":"None", - "slow_axes":"energy", - "analyzer_take_off_azimuth": "@xps_token:analyser/analyzer_take_off_azimuth", - "analyzer_take_off_azimuth/@units": "degree", - "analyzer_take_off_polar/": "@xps_token:analyser/analyzer_take_off_polar", - "analyzer_take_off_polar/@units": "degree", - "analysis_width_x": "@xps_token:analyser/analysis_width_x", - "analysis_width_x/@units": "mm", - "analysis_width_y": "@xps_token:analyser/analysis_width_y", - "analysis_width_y/@units": "mm", - "target_bias": "@xps_token:analyser/target_bias", - "target_bias/@units": "V", - "device_information":{ - "vendor":"@eln", - "model":"@eln", - "identifier":"@eln" - }, - "energy_resolution":{ - "physical_quantity":"energy", - "type":"estimated", - "resolution":"@xps_token:data/step_size", - "resolution/@units":"eV" - }, - "transmission_function":{ - "@default":"relative_intensity", - "@signal":"relative_intensity", - "@axes":["kinetic_energy"], - "kinetic_energy":"@xps_token:transmission_function/kinetic_energy", - "kinetic_energy/@units":"@xps_token:transmission_function/kinetic_energy/@units", - "relative_intensity":"@xps_token:collectioncolumn/transmission_function/relative_intensity" - }, - "COLLECTIONCOLUMN[collectioncolumn]":{ - "scheme":"@eln", - "lens_mode":"@xps_token:collectioncolumn/lens_mode", - "projection":"None", - "angular_acceptance":"None", - "spatial_acceptance":"None", - "field_aperture":"None", - "contrast_aperture":"None", - "device_information":{ - "vendor":"@eln", - "model":"@eln", - "identifier":"@eln" - } - }, - "ENERGYDISPERSION[energydispersion]":{ - "scheme":"@eln", - "pass_energy":"@xps_token:energydispersion/pass_energy", - "pass_energy/@units":"@xps_token:energydispersion/pass_energy/@units", - "energy_scan_mode":"@xps_token:energydispersion/scan_mode", - "entrance_slit":"@eln", - "exit_slit":"@eln", - "device_information":{ - "vendor":"@eln", - "model":"@eln", - "identifier":"@eln" - }, - }, - "DETECTOR[detector]":{ - "@default":"raw_data", - "amplifier_type":"@eln", - "detector_type":"@eln", - "detector_voltage": "@xps_token:detector/detector_voltage", - "detector_voltage/@units": "V", - "count_time":"@xps_token:detector/dwell_time", - "count_time/@units":"s", - "acquisition_mode": "@xps_token:detector/signal_mode", - "device_information":{ - "vendor":"@eln", - "model":"@eln", - "identifier":"@eln" - }, - "raw_data":{ - "@signal":"raw", - "@default":"raw", - "raw":"@detector_data:cycles/Cycle_", - "raw/@units":"counts" - } - } - }, - "MANIPULATOR[manipulator]":{ - "device_information":{ - "vendor":"@eln", - "model":"@eln", - "identifier":"@eln" - }, - "temperature_sensor":{ - "name":"@eln", - "measurement":"@eln", - "type":"@eln", - "attached_to":"@eln", - "value":"@eln" - }, - "sample_heater":{ - "name":"@eln", - "physical_quantity":"@eln", - "type":"@eln", - "heater_power":"@eln", - "PID[pid]/setpoint":"@eln" - }, - "cryostat":{ - "name":"None", - "physical_quantity":"None", - "type":"None", - "PID[pid]/setpoint":"None" - }, - "drain_current_amperemeter":{ - "name":"@eln", - "measurement":"@eln", - "type":"@eln", - "value":"@eln" - }, - "sample_bias_voltmeter":{ - "name":"@eln", - "measurement":"@eln", - "type":"@eln", - "value":"@xps_token:sample/target_bias", - "value/@units": "V" - }, - "sample_bias_potentiostat":{ - "name":"@eln", - "physical_quantity":"@eln", - "type":"@eln", - "PID[pid]/setpoint":"@eln" - } - }, - "pressure_gauge":{ - "name":"@eln", - "measurement":"@eln", - "type":"@eln", - "value":"@eln", - "value_log/value":"@eln" - }, - "flood_gun":{ - "name":"@eln", - "physical_quantity":"@eln", - "type":"@eln", - "current":"@eln", - "current_log/value":"@eln" - } - }, - "/ENTRY[entry]/PROCESS[process]":{ - "energy_calibration":{ - "calibrated_axis":"@data:energy", - "calibrated_axis/@units":"eV", - }, - "energy_referencing":{ - "level":"None", - "reference_peak":"None", - "binding_energy":"None", - "offset":"None", - "calibrated_axis":"None" - }, - "transmission_correction":{ - "transmission_function":{ - "@axes":"None", - "@signal":"None", - "kinetic_energy":"None", - "kinetic_energy/@units":"None", - "relative_intensity":"None" - } - } - }, - "/ENTRY[entry]/SAMPLE[sample]":{ - "name":"@eln", - "sample_id":"@eln", - "atom_types":"@eln", - "physical_form":"@eln", - "situation":"@eln", - "SUBSTANCE[substance]":{ - "name":"@eln", - "molecular_mass":"@eln", - "cas_number":"@eln", - "molecular_formula_hill":"@eln" - }, - "sample_history":{ - "sample_preparation":{ - "start_time":"@eln", - "end_time":"@eln", - "description":"@eln", - "method":"@eln" - }, - "PHYSICAL_PROCESS[sample_loading]":{ - "start_time":"@eln", - "end_time":"@eln", - "description":"@eln", - "method":"@eln" - } - }, - "temperature":{ - "temperature_sensor": "@link:/entry/instrument/manipulator/temperature_sensor", - "sample_heater":"@link:/entry/instrument/manipulator/sample_heater", - "cryostat":"None" - }, - "gas_pressure":{ - "pressure_gauge":"@link:/entry/instrument/pressure_gauge" - }, - "bias":{ - "potentiostat":"@link:/entry/instrument/manipulator/sample_bias_potentiostat", - "voltmeter":"@link:/entry/instrument/manipulator/sample_bias_voltmeter" - }, - "drain_current":{ - "amperemeter":"@link:/entry/instrument/manipulator/drain_current_amperemeter" - }, - "flood_gun_current":{ - "flood_gun":"@link:/entry/instrument/flood_gun" - } - }, - "/ENTRY[entry]/data":{ - "@signal":"data", - "@default":"data", - "@axes":["energy"], - "data":"@data:cycle", - "data/@units":"@xps_token:data/y_units_1", - "energy": "@data:energy", - "energy/@type":"@xps_token:data/x_units_1", - "energy/@units":"eV", - "@energy_indices":"None", - "@energy_depends":"None" - } - } \ No newline at end of file +{ + "/@default":"entry", + "/ENTRY[entry]":{ + "@default":"data", + "definition":"@eln", + "definition/@version":"@eln", + "title":"@eln", + "start_time":"@xps_token:region/time_stamp", + "end_time":"@eln", + "experiment_institution":"@eln", + "experiment_facility":"@eln", + "experiment_laboratory":"@eln", + "entry_identifier":"@eln", + "duration":"None", + "duration/@units":"s", + "method":"@xps_token:region/analysis_method", + "program_name":"@eln" + }, + "/ENTRY[entry]/USER[user]":{ + "name":"@eln", + "affiliation":"@eln", + "address":"@eln", + "orcid":"@eln", + "email":"@eln" + }, + "/ENTRY[entry]/INSTRUMENT[instrument]":{ + "device_information":{ + "vendor":"@eln", + "identifier":"@eln", + "model":"@eln" + }, + "energy_resolution":{ + "physical_quantity":"energy", + "type":"derived", + "resolution":"@xps_token:data/step_size", + "resolution/@units":"eV" + }, + "source_TYPE[source_probe]":{ + "type":"@eln", + "name":"@xps_token:source/source_label", + "probe":"photon", + "device_information":{ + "vendor":"@eln", + "identifier":"@eln", + "model":"@eln" + }, + "associated_beam":"@link:/entry/instrument/beam_probe", + "source_analyzer_angle":"source_analyzer_angle", + "source_analyzer_angle/@units":"degree" + }, + "beam_TYPE[beam_probe]":{ + "distance":"@eln", + "distance/@units":"@eln", + "incident_energy":"@xps_token:beam/excitation_energy", + "incident_energy/@units":"eV", + "incident_energy_spread":"None", + "incident_energy_spread/@units":"None", + "incident_polarization":"None", + "incident_polarization/@units":"None", + "extent":"None", + "associated_source":"@link:/entry/instrument/source_probe" + }, + "ELECTRONANALYSER[electronanalyser]":{ + "@default":"detector0", + "name":"@xps_token:analyser/analyser_name", + "description":"@eln", + "work_function":"@xps_token:analyser/work_function", + "work_function/@units":"eV", + "fast_axes":"None", + "slow_axes":"energy", + "analyzer_take_off_azimuth":"@xps_token:analyser/analyzer_take_off_azimuth", + "analyzer_take_off_azimuth/@units":"degree", + "analyzer_take_off_polar":"@xps_token:analyser/analyzer_take_off_polar", + "analyzer_take_off_polar/@units":"degree", + "analysis_width_x":"@xps_token:analyser/analysis_width_x", + "analysis_width_x/@units":"mm", + "analysis_width_y":"@xps_token:analyser/analysis_width_y", + "analysis_width_y/@units":"mm", + "target_bias":"@xps_token:analyser/target_bias", + "target_bias/@units":"V", + "device_information":{ + "vendor":"@eln", + "model":"@eln", + "identifier":"@eln" + }, + "energy_resolution":{ + "physical_quantity":"energy", + "type":"estimated", + "resolution":"@xps_token:data/step_size", + "resolution/@units":"eV" + }, + "transmission_function":{ + "@default":"relative_intensity", + "@signal":"relative_intensity", + "@axes":[ + "kinetic_energy" + ], + "kinetic_energy":"@xps_token:transmission_function/kinetic_energy", + "kinetic_energy/@units":"@xps_token:transmission_function/kinetic_energy/@units", + "relative_intensity":"@xps_token:collectioncolumn/transmission_function/relative_intensity" + }, + "COLLECTIONCOLUMN[collectioncolumn]":{ + "scheme":"@eln", + "lens_mode":"@xps_token:collectioncolumn/lens_mode", + "projection":"None", + "angular_acceptance":"None", + "spatial_acceptance":"None", + "field_aperture":"None", + "contrast_aperture":"None", + "device_information":{ + "vendor":"@eln", + "model":"@eln", + "identifier":"@eln" + } + }, + "ENERGYDISPERSION[energydispersion]":{ + "scheme":"@eln", + "pass_energy":"@xps_token:energydispersion/pass_energy", + "pass_energy/@units":"@xps_token:energydispersion/pass_energy/@units", + "energy_scan_mode":"@xps_token:energydispersion/scan_mode", + "entrance_slit":"@eln", + "exit_slit":"@eln", + "device_information":{ + "vendor":"@eln", + "model":"@eln", + "identifier":"@eln" + } + }, + "DETECTOR[detector]":{ + "@default":"raw_data", + "amplifier_type":"@eln", + "detector_type":"@eln", + "detector_voltage":"@xps_token:detector/detector_voltage", + "detector_voltage/@units":"V", + "count_time":"@xps_token:detector/dwell_time", + "count_time/@units":"s", + "acquisition_mode":"@xps_token:detector/signal_mode", + "device_information":{ + "vendor":"@eln", + "model":"@eln", + "identifier":"@eln" + }, + "raw_data":{ + "@signal":"raw", + "@default":"raw", + "raw":"@detector_data:cycles/Cycle_", + "raw/@units":"counts" + } + } + }, + "MANIPULATOR[manipulator]":{ + "device_information":{ + "vendor":"@eln", + "model":"@eln", + "identifier":"@eln" + }, + "temperature_sensor":{ + "name":"@eln", + "measurement":"@eln", + "type":"@eln", + "attached_to":"@eln", + "value":"@eln" + }, + "sample_heater":{ + "name":"@eln", + "physical_quantity":"@eln", + "type":"@eln", + "heater_power":"@eln", + "PID[pid]/setpoint":"@eln" + }, + "cryostat":{ + "name":"None", + "physical_quantity":"None", + "type":"None", + "PID[pid]/setpoint":"None" + }, + "drain_current_amperemeter":{ + "name":"@eln", + "measurement":"@eln", + "type":"@eln", + "value":"@eln" + }, + "sample_bias_voltmeter":{ + "name":"@eln", + "measurement":"@eln", + "type":"@eln", + "value":"@xps_token:sample/target_bias", + "value/@units":"V" + }, + "sample_bias_potentiostat":{ + "name":"@eln", + "physical_quantity":"@eln", + "type":"@eln", + "PID[pid]/setpoint":"@eln" + } + }, + "pressure_gauge":{ + "name":"@eln", + "measurement":"@eln", + "type":"@eln", + "value":"@eln", + "value_log/value":"@eln" + }, + "flood_gun":{ + "name":"@eln", + "physical_quantity":"@eln", + "type":"@eln", + "current":"@eln", + "current_log/value":"@eln" + } + }, + "/ENTRY[entry]/PROCESS[process]":{ + "energy_calibration":{ + "calibrated_axis":"@data:energy", + "calibrated_axis/@units":"eV" + }, + "energy_referencing":{ + "level":"None", + "reference_peak":"None", + "binding_energy":"None", + "offset":"None", + "calibrated_axis":"None" + }, + "transmission_correction":{ + "transmission_function":{ + "@axes":"None", + "@signal":"None", + "kinetic_energy":"None", + "kinetic_energy/@units":"None", + "relative_intensity":"None" + } + } + }, + "/ENTRY[entry]/SAMPLE[sample]":{ + "name":"@eln", + "sample_id":"@eln", + "atom_types":"@eln", + "physical_form":"@eln", + "situation":"@eln", + "SUBSTANCE[substance]":{ + "name":"@eln", + "molecular_mass":"@eln", + "cas_number":"@eln", + "molecular_formula_hill":"@eln" + }, + "sample_history":{ + "sample_preparation":{ + "start_time":"@eln", + "end_time":"@eln", + "description":"@eln", + "method":"@eln" + }, + "PHYSICAL_PROCESS[sample_loading]":{ + "start_time":"@eln", + "end_time":"@eln", + "description":"@eln", + "method":"@eln" + } + }, + "temperature":{ + "temperature_sensor":"@link:/entry/instrument/manipulator/temperature_sensor", + "sample_heater":"@link:/entry/instrument/manipulator/sample_heater", + "cryostat":"None" + }, + "gas_pressure":{ + "pressure_gauge":"@link:/entry/instrument/pressure_gauge" + }, + "bias":{ + "potentiostat":"@link:/entry/instrument/manipulator/sample_bias_potentiostat", + "voltmeter":"@link:/entry/instrument/manipulator/sample_bias_voltmeter" + }, + "drain_current":{ + "amperemeter":"@link:/entry/instrument/manipulator/drain_current_amperemeter" + }, + "flood_gun_current":{ + "flood_gun":"@link:/entry/instrument/flood_gun" + } + }, + "/ENTRY[entry]/data":{ + "@signal":"data", + "@default":"data", + "@axes":[ + "energy" + ], + "data":"@data:cycle", + "data/@units":"@xps_token:data/y_units_1", + "energy":"@data:energy", + "energy/@type":"@xps_token:data/x_units_1", + "energy/@units":"eV", + "@energy_indices":"None", + "@energy_depends":"None" + } +} \ No newline at end of file diff --git a/tests/data/vms/eln_data.yaml b/tests/data/vms/eln_data.yaml new file mode 100644 index 00000000..54475cbb --- /dev/null +++ b/tests/data/vms/eln_data.yaml @@ -0,0 +1,147 @@ +definition: + value: NXmpes + version: 1.0 +title: XPS Experiment +start_time: 2022-04-08T11:47:02.0200Z +end_time: 2022-04-08T12:32:06.0200Z +experiment_institution: BESSY II +program_name: SpecsLab 2 +user: + name: Lukas Pielsticker + email: lukas.pielsticker@cec.mpg.de +instrument: + device_information: + vendor: SPECS GmbH + model: XPS setup + identifier: null + energy_resolution: + type: calibrated + resolution: + value: 0.2 + unit: eV + source_probe: + type: Synchrotron X-ray Source + probe: x-ray + device_information: + vendor: null + model: null + identifier: null + beam_probe: + distance: + value: 0.0 + unit: mm + analyser: + description: hemispherical + name: PHOIBOS 150 + device_information: + vendor: SPECS GmbH + model: PHOIBOS 150 + identifier: null + collectioncolumn: + scheme: angular dispersive + device_information: + vendor: null + model: null + identifier: null + energydispersion: + scheme: hemispherical + entrance_slit: unknown + energy_scan_mode: fixed_analyser_transmission + diameter: + unit: mm + value: 150 + device_information: + vendor: null + model: null + identifier: null + detector: + amplifier_type: channeltron + detector_type: Multi-anode + manipulator: + device_information: + vendor: SPECS GmbH + model: 5-axis manipulator + identifier: null + temperature_sensor: + name: type K thermocouple + measurement: temperature + attached_to: sample + type: type K thermocouple + value: + value: 298.0 + unit: K + sample_heater: + name: Coherent Compact Evolution IR Diode LASER (DILAS) + physical_quantity: temperature + type: IR diode laser + heater_power: + value: 0.0 + unit: W + pid: + setpoint: + value: 298.0 + unit: K + cryostat: + name: null + physical_quantity: null + type: null + pid: + setpoint: null + drain_current_amperemeter: + name: Amperemeter 1.0 + measurement: current + type: wire + value: + value: 0.0 + unit: A + sample_bias_voltmeter: + name: XPS sample voltmeter + measurement: voltage + attached_to: sample + type: oscilloscope + value: + value: 0.0 + unit: V + sample_bias_potentiostat: + name: XPS sample potentiostat + physical_quantity: voltage + type: potentiostat + pid: + setpoint: + value: 0.0 + unit: V + pressure_gauge: + name: Atmion + measurement: pressure + type: hot-filament ionization gauge + value: + value: 0.000000001 + unit: mbar + value_log: + value: + value: null + unit: null + flood_gun: + name: FG 22/35 + physical_quantity: current + type: low energy electron source + current: + value: 0.0 + unit: A + current_log: + value: + value: null + unit: null +sample: + description: A polymer material called PBTTT with chemical name poly[2,5-bis(3-dodecylthiophen-2-yl)thieno[3,2-b]thiophene]. + name: Test + substance: + molecular_formula_hill: (C42H62S4)n + situation: vacuum + sample_history: + sample_preparation: + start_time: 2022-04-08T11:02:38.0200Z + end_time: 2022-04-08T11:06:42.200Z + description: From third party + method: null + \ No newline at end of file diff --git a/tests/data/vms/regular.vms b/tests/data/vms/regular.vms new file mode 100644 index 00000000..dd9f742d --- /dev/null +++ b/tests/data/vms/regular.vms @@ -0,0 +1,2798 @@ +VAMAS Surface Chemical Analysis Standard Data Transfer Format 1988 May 4 +Not Specified +Not Specified +Not Specified +Not Specified +5 +Casa Info Follows CasaXPS Version 2.3.25PR1.0 +0 +Created by SpecsLab Prodigy, Version 4.100.1-r111001 +SourceAnalyserAngle: Not Specified +CasaRowLabel:1 as-loaded +NORM +REGULAR +0 +1 +Exp Variable +d +0 +0 +0 +0 +1 +Survey +1 as-loaded +2023 +8 +24 +14 +19 +47 +0 +14 +Casa Info Follows +0 +0 +0 +0 +File = D:/OwnCloud/Project data/FAIRmat/export test/sle/EX889_S1110_MgFe2O4_spent.sle +Group = 1 as-loaded +First of group = 1 +Spectrum ID = 20 +Analyzer lens = LargeArea:1.5kV +Analyzer slit = 4:7x20c\C:mesh +Scan mode = FixedAnalyzerTransmission +Kinetic energy start = 136.61 +C:\Users\pielsticker\Lukas\FAIRMat\user_cases\Pielsticker_XPS_MPI-CEC\EX889_S1110_MgFe2O4_spent\vms\EX889_S1110_MgFe2O4_spent_regular.vms +XPS +0 +Al +1486.61 +0 +0 +0 +54.5 +180 +FAT +100 +1 +4.1082 +0 +0 +0 +0 +0 +Survey + +-1 +kinetic energy +eV +136.61 +1 +2 +counts +d +Transmission +d +pulse counting +0.1 +1 +0 +0 +0 +0 +2 +ESCAPE DEPTH TYPE +d +1 +MFP Exponent +d +0 +2702 +18.1529 +10836.6 +23.5611 +78.8103 +1559.87 +78.8103 +1586.79 +78.5146 +1565.15 +78.2222 +1532.13 +77.933 +1579.34 +77.647 +1566.2 +77.3642 +1559.9 +77.0844 +1575.89 +76.8076 +1568.17 +76.5338 +1596.81 +76.2628 +1584.46 +75.9948 +1532.83 +75.7295 +1554.1 +75.467 +1535.59 +75.2073 +1553.13 +74.9501 +1583.11 +74.6956 +1562.84 +74.4437 +1564.34 +74.1943 +1564.92 +73.9474 +1550.85 +73.703 +1616.87 +73.4609 +1678.37 +73.2213 +1669.65 +72.9839 +1724.2 +72.7489 +1622.54 +72.5161 +1651.86 +72.2855 +1638.19 +72.0571 +1695.62 +71.8309 +1650.32 +71.6068 +1707.48 +71.3847 +1660.89 +71.1647 +1668.98 +70.9468 +1626.16 +70.7308 +1626.05 +70.5168 +1598.67 +70.3047 +1594.31 +70.0945 +1557.62 +69.8862 +1574.93 +69.6798 +1530.71 +69.4751 +1508.85 +69.2723 +1558.39 +69.0712 +1591.39 +68.8719 +1718.53 +68.6743 +1738.14 +68.4783 +2095.68 +68.2841 +2671.96 +68.0914 +2757.07 +67.9004 +2274.45 +67.711 +1750.86 +67.5232 +1565.47 +67.337 +1511.87 +67.1522 +1556.88 +66.969 +1534.57 +66.7873 +1530.3 +66.607 +1493.8 +66.4282 +1505.46 +66.2508 +1497.65 +66.0749 +1520.5 +65.9003 +1530.62 +65.7271 +1577.25 +65.5553 +1574.41 +65.3848 +1559.99 +65.2156 +1597.34 +65.0477 +1569.35 +64.8812 +1590.92 +64.7159 +1619.86 +64.5518 +1596.69 +64.389 +1548.91 +64.2274 +1647.49 +64.0671 +1595.61 +63.9079 +1650.16 +63.7499 +1593.16 +63.5931 +1611.57 +63.4374 +1661.15 +63.2829 +1606.1 +63.1295 +1612.16 +62.9772 +1620.29 +62.8259 +1639.24 +62.6758 +1650.37 +62.5268 +1636.44 +62.3788 +1638.33 +62.2318 +1565.45 +62.0859 +1670.93 +61.941 +1658.31 +61.7972 +1705.44 +61.6543 +1644.22 +61.5124 +1642.88 +61.3715 +1635.96 +61.2315 +1703.59 +61.0925 +1678.18 +60.9544 +1653.29 +60.8173 +1655.99 +60.6811 +1739.67 +60.5458 +1733.78 +60.4114 +1696.45 +60.2779 +1723.66 +60.1453 +1718.75 +60.0135 +1768.57 +59.8826 +1741.39 +59.7526 +1734.81 +59.6234 +1774.56 +59.495 +1759.46 +59.3675 +1680.27 +59.2408 +1757.98 +59.1149 +1778.29 +58.9898 +1801.33 +58.8655 +1829.88 +58.7419 +1871.03 +58.6192 +1925.4 +58.4972 +1879.21 +58.3759 +1847.32 +58.2554 +1813.84 +58.1357 +1838.2 +58.0167 +1878.25 +57.8984 +1888.03 +57.7808 +1884.11 +57.664 +1929.41 +57.5479 +1952.14 +57.4324 +1950.57 +57.3177 +1900.39 +57.2036 +1872.67 +57.0902 +1907.94 +56.9775 +1966.75 +56.8655 +1986.06 +56.7541 +1956.3 +56.6433 +1894.49 +56.5332 +1911.66 +56.4238 +1936.65 +56.315 +1950.51 +56.2068 +1966.01 +56.0992 +1917.42 +55.9922 +1944.08 +55.8859 +1876.57 +55.7801 +1952.94 +55.675 +1935.77 +55.5704 +1912.69 +55.4665 +1987.9 +55.3631 +1919.75 +55.2603 +1874.3 +55.158 +1930.37 +55.0564 +1889.53 +54.9553 +1891.26 +54.8547 +1968.67 +54.7547 +2031.15 +54.6552 +2012.75 +54.5563 +2001.53 +54.4579 +1967.13 +54.3601 +2038.89 +54.2627 +2003.47 +54.1659 +1939.11 +54.0696 +2030.01 +53.9738 +2107.98 +53.8786 +2057.44 +53.7838 +2059.59 +53.6895 +2047.33 +53.5957 +2025.78 +53.5024 +2059.42 +53.4096 +2101.8 +53.3173 +2082.68 +53.2255 +2091.96 +53.1341 +2114.61 +53.0432 +2021.11 +52.9528 +2087.39 +52.8628 +2118.41 +52.7733 +2092.11 +52.6842 +2069.75 +52.5956 +2141.01 +52.5074 +2098.73 +52.4197 +2112.32 +52.3324 +2128.38 +52.2455 +2174.64 +52.1591 +2207.51 +52.0731 +2157 +51.9875 +2145.98 +51.9024 +2140.12 +51.8176 +2148.66 +51.7333 +2193.11 +51.6494 +2158.89 +51.5659 +2154.73 +51.4828 +2360.73 +51.4001 +2290.34 +51.3178 +2251.53 +51.2358 +2209.06 +51.1543 +2186.3 +51.0732 +2243.28 +50.9924 +2302.04 +50.9121 +2275.91 +50.8321 +2316.28 +50.7525 +2278.56 +50.6732 +2287.64 +50.5944 +2313.54 +50.5159 +2324.13 +50.4377 +2340.14 +50.36 +2377.54 +50.2825 +2353.57 +50.2055 +2339.97 +50.1288 +2358.76 +50.0524 +2385.94 +49.9764 +2383.74 +49.9007 +2357.84 +49.8254 +2357.46 +49.7504 +2334.73 +49.6758 +2355.73 +49.6015 +2352.54 +49.5275 +2391.19 +49.4539 +2394.41 +49.3805 +2426.68 +49.3076 +2447.03 +49.2349 +2450.6 +49.1625 +2428.4 +49.0905 +2411.46 +49.0188 +2477.62 +48.9474 +2473.43 +48.8763 +2452.09 +48.8055 +2458.41 +48.735 +2510.02 +48.6649 +2466.94 +48.595 +2516.35 +48.5254 +2493.71 +48.4561 +2558.59 +48.3872 +2514.47 +48.3185 +2501.45 +48.2501 +2542.46 +48.182 +2544.79 +48.1142 +2564.02 +48.0466 +2613.64 +47.9794 +2573.06 +47.9124 +2611.51 +47.8458 +2599.39 +47.7793 +2614.03 +47.7132 +2645.83 +47.6474 +2569.28 +47.5818 +2594.86 +47.5165 +2638.49 +47.4514 +2615.08 +47.3866 +2618.4 +47.3221 +2688.75 +47.2579 +2704.86 +47.1939 +2645.78 +47.1301 +2674.26 +47.0667 +2668.06 +47.0035 +2687.27 +46.9405 +2711.88 +46.8778 +2749.15 +46.8153 +2683.49 +46.7531 +2716.97 +46.6911 +2723.18 +46.6294 +2788.5 +46.5679 +2761.46 +46.5067 +2774.06 +46.4457 +2757.48 +46.385 +2776.95 +46.3244 +2731.45 +46.2642 +2816.46 +46.2041 +2821.52 +46.1443 +2777.24 +46.0847 +2794.63 +46.0254 +2807.2 +45.9663 +2898.61 +45.9074 +2864.09 +45.8487 +2793.14 +45.7903 +2780.06 +45.732 +2913.25 +45.674 +2866.51 +45.6163 +2872.53 +45.5587 +2913.63 +45.5014 +2923.84 +45.4442 +2936.52 +45.3873 +2905.63 +45.3306 +2949.59 +45.2741 +2895.54 +45.2179 +2959.7 +45.1618 +2919.39 +45.1059 +2932.11 +45.0503 +2977.59 +44.9948 +2937.74 +44.9396 +2952.96 +44.8846 +2982.81 +44.8297 +3001.82 +44.7751 +2983.4 +44.7206 +2999.63 +44.6664 +3037.31 +44.6124 +3031.46 +44.5585 +3108.65 +44.5049 +3017.8 +44.4514 +3025.32 +44.3981 +3082.05 +44.3451 +3073.5 +44.2922 +3127.1 +44.2395 +3132.37 +44.187 +3085.73 +44.1346 +3107.65 +44.0825 +3025.26 +44.0306 +3143.23 +43.9788 +3101.6 +43.9272 +3218.56 +43.8758 +3186.14 +43.8246 +3190.59 +43.7735 +3214.04 +43.7226 +3188.25 +43.672 +3180.41 +43.6214 +3233.96 +43.5711 +3195.36 +43.5209 +3289.71 +43.4709 +3245.65 +43.4211 +3256.15 +43.3715 +3286.51 +43.322 +3273.36 +43.2727 +3234.52 +43.2235 +3254.16 +43.1745 +3307.83 +43.1257 +3288.27 +43.0771 +3282.41 +43.0286 +3214.57 +42.9803 +3387.93 +42.9321 +3394.45 +42.8841 +3346.38 +42.8363 +3399.57 +42.7886 +3432.17 +42.7411 +3371.22 +42.6937 +3382.29 +42.6465 +3519.85 +42.5995 +3465.57 +42.5526 +3481.13 +42.5059 +3400.96 +42.4593 +3485.9 +42.4129 +3500.51 +42.3666 +3434.69 +42.3205 +3445.45 +42.2745 +3531.13 +42.2287 +3607.43 +42.183 +3658.26 +42.1374 +3647.8 +42.0921 +3644.84 +42.0468 +3680.27 +42.0017 +3771.88 +41.9568 +3753.18 +41.912 +3648.12 +41.8673 +3667.52 +41.8228 +3636.53 +41.7784 +3629.03 +41.7342 +3631.38 +41.6901 +3666.16 +41.6462 +3791.26 +41.6024 +3763.01 +41.5587 +3777.31 +41.5151 +3759.79 +41.4717 +3811.61 +41.4285 +3882.98 +41.3853 +3948.47 +41.3423 +3862.6 +41.2995 +3914.22 +41.2567 +4009.02 +41.2141 +3920.11 +41.1717 +3957.47 +41.1293 +3865.42 +41.0871 +3785.27 +41.0451 +3872.52 +41.0031 +3753.65 +40.9613 +3844.6 +40.9196 +3855.37 +40.878 +3794.87 +40.8366 +3860.29 +40.7953 +3747.79 +40.7541 +3715.49 +40.713 +3745.65 +40.6721 +3869.44 +40.6313 +3950.49 +40.5906 +3970.95 +40.55 +4096.81 +40.5096 +4257.04 +40.4692 +4459.86 +40.429 +4692.13 +40.389 +4721.97 +40.349 +4464.4 +40.3091 +4262.12 +40.2694 +4142.39 +40.2298 +4056.91 +40.1903 +3928.01 +40.1509 +3882.82 +40.1116 +3866.38 +40.0725 +3725.36 +40.0334 +3765.33 +39.9945 +3709.83 +39.9557 +3562.89 +39.917 +3621.55 +39.8784 +3597.42 +39.84 +3596.66 +39.8016 +3638.07 +39.7633 +3611.19 +39.7252 +3579.1 +39.6872 +3642.96 +39.6492 +3589.74 +39.6114 +3597.4 +39.5737 +3554.48 +39.5361 +3547.16 +39.4986 +3642.72 +39.4612 +3669.33 +39.424 +3693.42 +39.3868 +3673.08 +39.3497 +3675.11 +39.3127 +3588.19 +39.2759 +3692.67 +39.2391 +3710.96 +39.2025 +3686.1 +39.1659 +3760.52 +39.1295 +3707.84 +39.0931 +3779.49 +39.0569 +3761.04 +39.0207 +3718.59 +38.9847 +3684.06 +38.9487 +3748.66 +38.9129 +3819.79 +38.8771 +3825.54 +38.8415 +3782.95 +38.8059 +3816.27 +38.7705 +3817.34 +38.7351 +3767.79 +38.6999 +3835.76 +38.6647 +3831.35 +38.6296 +3846.04 +38.5946 +3861.49 +38.5598 +3881.65 +38.525 +3865.56 +38.4903 +3857.45 +38.4557 +3875.75 +38.4212 +3906.68 +38.3868 +3929.36 +38.3525 +3908.24 +38.3182 +3843.91 +38.2841 +3909.05 +38.25 +3815.29 +38.2161 +3854.63 +38.1822 +3872.94 +38.1485 +3955 +38.1148 +3942.5 +38.0812 +3929.13 +38.0477 +3966 +38.0142 +3988.06 +37.9809 +3945.92 +37.9477 +4036.63 +37.9145 +3940.43 +37.8814 +3911.4 +37.8485 +3944.21 +37.8156 +3989.48 +37.7828 +4059.45 +37.75 +4114.2 +37.7174 +4131.45 +37.6848 +4037.94 +37.6524 +4051.83 +37.62 +4080.58 +37.5877 +4003.13 +37.5554 +4093.51 +37.5233 +4172.74 +37.4912 +4121.38 +37.4593 +4036.65 +37.4274 +3995.45 +37.3956 +4060.18 +37.3638 +4155.04 +37.3322 +4117.42 +37.3006 +3990.85 +37.2691 +4000.41 +37.2377 +4041.35 +37.2064 +3870.38 +37.1751 +3778.99 +37.1439 +3710.41 +37.1129 +3790.6 +37.0818 +3844.2 +37.0509 +3821.32 +37.02 +3804.37 +36.9892 +3802.21 +36.9585 +3733.64 +36.9279 +3718.82 +36.8973 +3703.71 +36.8669 +3758.16 +36.8365 +3743.39 +36.8061 +3721.92 +36.7759 +3717.49 +36.7457 +3663.76 +36.7156 +3730.41 +36.6856 +3820.22 +36.6556 +3776.22 +36.6257 +3777.44 +36.5959 +3766.95 +36.5662 +3769.71 +36.5365 +3805.45 +36.5069 +3806.64 +36.4774 +3822.4 +36.4479 +3784 +36.4185 +3864.01 +36.3892 +3802.12 +36.36 +3793.02 +36.3308 +3855.97 +36.3017 +3865.08 +36.2727 +3969.75 +36.2437 +3965.21 +36.2148 +3951.6 +36.186 +3968.58 +36.1573 +3993.61 +36.1286 +4001.33 +36.1 +3935.5 +36.0714 +3982.89 +36.0429 +4040.27 +36.0145 +4023.74 +35.9862 +3911.81 +35.9579 +3921.6 +35.9297 +4022.79 +35.9015 +4088.37 +35.8734 +4041.13 +35.8454 +4017.61 +35.8175 +3927.19 +35.7896 +3872.86 +35.7618 +3876.24 +35.734 +3812.48 +35.7063 +3810.52 +35.6787 +3705.95 +35.6511 +3661.32 +35.6236 +3563.39 +35.5962 +3501.12 +35.5688 +3467.18 +35.5415 +3409.4 +35.5143 +3410.86 +35.4871 +3342.05 +35.46 +3342.44 +35.4329 +3341.08 +35.4059 +3308.88 +35.379 +3244.79 +35.3521 +3270.97 +35.3253 +3304.26 +35.2986 +3316.09 +35.2719 +3247.5 +35.2452 +3269.42 +35.2187 +3335.66 +35.1922 +3276.58 +35.1657 +3298.95 +35.1393 +3351.99 +35.113 +3333.76 +35.0867 +3295.96 +35.0605 +3347.12 +35.0343 +3363.57 +35.0082 +3424.67 +34.9822 +3353.64 +34.9562 +3320.7 +34.9303 +3385 +34.9044 +3422.18 +34.8786 +3415.06 +34.8529 +3381.96 +34.8272 +3405.82 +34.8016 +3447.33 +34.776 +3404.91 +34.7505 +3389.96 +34.725 +3427.81 +34.6996 +3279.72 +34.6742 +3349.87 +34.6489 +3389.01 +34.6237 +3394.67 +34.5985 +3423.51 +34.5733 +3515.64 +34.5483 +3503.51 +34.5232 +3584.13 +34.4983 +3570.18 +34.4734 +3657.07 +34.4485 +3607.56 +34.4237 +3644.13 +34.3989 +3743.45 +34.3742 +3722.89 +34.3496 +3700.64 +34.325 +3658.06 +34.3004 +3599.17 +34.2759 +3538.86 +34.2515 +3517.02 +34.2271 +3505.76 +34.2028 +3389.38 +34.1785 +3292.63 +34.1543 +3269.42 +34.1301 +3380.76 +34.106 +3448.83 +34.0819 +3449.41 +34.0578 +3389.06 +34.0339 +3328.38 +34.0099 +3366.07 +33.9861 +3362.16 +33.9622 +3332.35 +33.9385 +3379.05 +33.9147 +3261.45 +33.8911 +3287.45 +33.8674 +3255.47 +33.8439 +3239.89 +33.8203 +3332.75 +33.7969 +3287.03 +33.7734 +3298.2 +33.7501 +3351.26 +33.7267 +3310.05 +33.7034 +3313.18 +33.6802 +3333.43 +33.657 +3265.39 +33.6339 +3398.28 +33.6108 +3300.22 +33.5877 +3418.91 +33.5647 +3393.61 +33.5418 +3345.42 +33.5189 +3357.74 +33.496 +3421.71 +33.4732 +3410.48 +33.4505 +3475.22 +33.4277 +3432.94 +33.4051 +3576.56 +33.3824 +3492.78 +33.3599 +3476.75 +33.3373 +3460.59 +33.3148 +3328.99 +33.2924 +3421.32 +33.27 +3443.4 +33.2477 +3475.87 +33.2254 +3553.21 +33.2031 +3625.36 +33.1809 +3604.94 +33.1587 +3701.67 +33.1366 +3622.6 +33.1145 +3669.36 +33.0925 +3662.8 +33.0705 +3642.56 +33.0485 +3688.15 +33.0266 +3775.45 +33.0047 +3909.49 +32.9829 +3959.46 +32.9611 +3873.13 +32.9394 +3800.47 +32.9177 +3677.36 +32.8961 +3440.29 +32.8744 +3423.94 +32.8529 +3347.7 +32.8314 +3315.05 +32.8099 +3327.11 +32.7884 +3404.95 +32.7671 +3455.04 +32.7457 +3664.53 +32.7244 +3947.69 +32.7031 +4143.85 +32.6819 +4015.34 +32.6607 +3807.48 +32.6396 +3397.91 +32.6184 +2803.3 +32.5974 +2492.37 +32.5764 +2267.74 +32.5554 +2229.81 +32.5344 +2121.65 +32.5135 +2123.23 +32.4927 +2189.71 +32.4718 +2191.1 +32.4511 +2179.19 +32.4303 +2114.88 +32.4096 +2190.7 +32.389 +2163.01 +32.3683 +2183.28 +32.3478 +2183.21 +32.3272 +2132.11 +32.3067 +2129.18 +32.2862 +2176.11 +32.2658 +2171.07 +32.2454 +2184.97 +32.2251 +2195.54 +32.2048 +2242.19 +32.1845 +2261.83 +32.1642 +2259.85 +32.144 +2255.38 +32.1239 +2201.71 +32.1038 +2255.39 +32.0837 +2220.13 +32.0636 +2185.38 +32.0436 +2241.34 +32.0237 +2204.58 +32.0037 +2247.31 +31.9838 +2239.56 +31.964 +2261.49 +31.9441 +2293.48 +31.9244 +2272.88 +31.9046 +2271.62 +31.8849 +2221.53 +31.8652 +2314.43 +31.8456 +2296.97 +31.826 +2310.69 +31.8064 +2297.91 +31.7869 +2295.44 +31.7674 +2327.22 +31.7479 +2286.99 +31.7285 +2265.61 +31.7091 +2323.71 +31.6898 +2349.41 +31.6704 +2248.72 +31.6512 +2300.8 +31.6319 +2259.05 +31.6127 +2280.49 +31.5935 +2374.34 +31.5744 +2327.19 +31.5553 +2390.85 +31.5362 +2401.69 +31.5172 +2380.2 +31.4982 +2407.42 +31.4792 +2375.09 +31.4603 +2372.97 +31.4414 +2335.34 +31.4225 +2367.35 +31.4037 +2381.62 +31.3849 +2358.67 +31.3661 +2325.5 +31.3474 +2378.51 +31.3287 +2401.77 +31.31 +2370.24 +31.2914 +2400.64 +31.2728 +2374.29 +31.2542 +2413.11 +31.2357 +2442.07 +31.2172 +2407.36 +31.1987 +2343.49 +31.1803 +2390.29 +31.1619 +2473.12 +31.1435 +2488.82 +31.1252 +2447.61 +31.1069 +2426.35 +31.0886 +2390.07 +31.0704 +2463.45 +31.0522 +2425.24 +31.034 +2534.41 +31.0158 +2470.01 +30.9977 +2473.89 +30.9796 +2483.39 +30.9616 +2447.27 +30.9436 +2503.71 +30.9256 +2487.21 +30.9076 +2541.03 +30.8897 +2554.33 +30.8718 +2548.3 +30.854 +2534.2 +30.8361 +2564.23 +30.8183 +2545.56 +30.8006 +2580.64 +30.7828 +2526.96 +30.7651 +2629.89 +30.7475 +2598.42 +30.7298 +2625.53 +30.7122 +2579.85 +30.6946 +2547.42 +30.6771 +2567.12 +30.6595 +2610.77 +30.642 +2616.9 +30.6246 +2603.38 +30.6071 +2596.31 +30.5897 +2573.56 +30.5724 +2601.8 +30.555 +2620.68 +30.5377 +2643.64 +30.5204 +2634.59 +30.5031 +2648.58 +30.4859 +2614.14 +30.4687 +2664.53 +30.4515 +2640.11 +30.4344 +2649.47 +30.4173 +2620.34 +30.4002 +2684.13 +30.3832 +2770.86 +30.3661 +2740.17 +30.3491 +2745.64 +30.3322 +2749.15 +30.3152 +2684.76 +30.2983 +2698.35 +30.2814 +2692.1 +30.2646 +2635.78 +30.2477 +2679.65 +30.2309 +2757.59 +30.2142 +2746.82 +30.1974 +2736.37 +30.1807 +2729.77 +30.164 +2756.35 +30.1474 +2777.97 +30.1307 +2767.78 +30.1141 +2814.13 +30.0975 +2813.38 +30.081 +2833.51 +30.0645 +2844.65 +30.048 +2800.18 +30.0315 +2834.07 +30.0151 +2891.2 +29.9986 +2911.29 +29.9823 +2863.73 +29.9659 +2783.29 +29.9496 +2802.54 +29.9333 +2872.58 +29.917 +2831.56 +29.9007 +2876.02 +29.8845 +2888.34 +29.8683 +2905.62 +29.8521 +3010.81 +29.836 +3061.91 +29.8198 +3180 +29.8037 +3308.58 +29.7877 +3159.4 +29.7716 +3170.76 +29.7556 +3126.36 +29.7396 +2998.97 +29.7236 +2915.15 +29.7077 +2924.83 +29.6918 +2712.68 +29.6759 +2759.56 +29.66 +2633.58 +29.6442 +2601.11 +29.6284 +2610.47 +29.6126 +2525.95 +29.5968 +2484.36 +29.5811 +2425.34 +29.5654 +2445.18 +29.5497 +2453.3 +29.534 +2343.66 +29.5184 +2457.7 +29.5028 +2582.03 +29.4872 +2883.02 +29.4716 +3509.9 +29.4561 +4917.17 +29.4406 +6871.43 +29.4251 +7909.72 +29.4096 +6336.91 +29.3942 +3641.81 +29.3787 +2447.76 +29.3633 +2145.26 +29.348 +2134.14 +29.3326 +2055.05 +29.3173 +2058.58 +29.302 +2143.99 +29.2867 +2129.66 +29.2715 +2146.41 +29.2563 +2124.34 +29.2411 +2195.89 +29.2259 +2165.19 +29.2107 +2125.13 +29.1956 +2176.27 +29.1805 +2186.61 +29.1654 +2138.4 +29.1503 +2106.22 +29.1353 +2185.07 +29.1203 +2170.58 +29.1053 +2160.84 +29.0903 +2193.81 +29.0754 +2145.58 +29.0605 +2129.8 +29.0456 +2221.15 +29.0307 +2246.21 +29.0158 +2209.38 +29.001 +2172.29 +28.9862 +2184.4 +28.9714 +2211.31 +28.9567 +2228.21 +28.9419 +2234.02 +28.9272 +2191.16 +28.9125 +2284.67 +28.8978 +2207.96 +28.8832 +2174.92 +28.8686 +2212.3 +28.8539 +2264.83 +28.8394 +2219.42 +28.8248 +2229.66 +28.8103 +2283.51 +28.7957 +2251.49 +28.7812 +2200.94 +28.7668 +2225.15 +28.7523 +2240.97 +28.7379 +2263.1 +28.7235 +2211.32 +28.7091 +2237.01 +28.6947 +2239.5 +28.6804 +2321.54 +28.6661 +2294.53 +28.6518 +2334.39 +28.6375 +2236.99 +28.6232 +2247.89 +28.609 +2274.6 +28.5948 +2273.66 +28.5806 +2248.54 +28.5664 +2301.37 +28.5523 +2370.62 +28.5381 +2308.63 +28.524 +2301.72 +28.5099 +2320.94 +28.4959 +2345.17 +28.4818 +2416.66 +28.4678 +2291.54 +28.4538 +2351.89 +28.4398 +2355.33 +28.4258 +2302.74 +28.4119 +2370.56 +28.398 +2356.11 +28.3841 +2285.34 +28.3702 +2333.3 +28.3563 +2370.23 +28.3425 +2382.09 +28.3286 +2414.98 +28.3148 +2448.46 +28.3011 +2440.6 +28.2873 +2381.75 +28.2736 +2341.95 +28.2598 +2385.54 +28.2461 +2418.42 +28.2324 +2446.05 +28.2188 +2404.69 +28.2051 +2480.4 +28.1915 +2423.9 +28.1779 +2499.41 +28.1643 +2448.74 +28.1508 +2428.41 +28.1372 +2444.88 +28.1237 +2436.94 +28.1102 +2433.34 +28.0967 +2474.11 +28.0832 +2424.33 +28.0698 +2410.84 +28.0564 +2378.05 +28.043 +2440.8 +28.0296 +2527.22 +28.0162 +2437.48 +28.0029 +2547.98 +27.9895 +2494.82 +27.9762 +2486.38 +27.9629 +2495.37 +27.9496 +2486.01 +27.9364 +2482.99 +27.9232 +2581.53 +27.9099 +2531.71 +27.8967 +2586.96 +27.8836 +2637.49 +27.8704 +2567.19 +27.8572 +2659.83 +27.8441 +2542.42 +27.831 +2638.99 +27.8179 +2547.54 +27.8049 +2541.78 +27.7918 +2580.54 +27.7788 +2539.73 +27.7658 +2549.89 +27.7528 +2560.56 +27.7398 +2619.43 +27.7268 +2628.95 +27.7139 +2722.46 +27.701 +2694.34 +27.6881 +2740.48 +27.6752 +2735.13 +27.6623 +2730.04 +27.6495 +2702.71 +27.6366 +2723.14 +27.6238 +2731.44 +27.611 +2743.45 +27.5982 +2773.12 +27.5855 +2739.82 +27.5727 +2787.3 +27.56 +2735.81 +27.5473 +2776.34 +27.5346 +2681.97 +27.5219 +2691.87 +27.5093 +2761.59 +27.4966 +2766.58 +27.484 +2777.7 +27.4714 +2800.24 +27.4588 +2824.1 +27.4462 +2792.84 +27.4337 +2858.7 +27.4212 +2958.37 +27.4086 +3122.91 +27.3961 +3302.71 +27.3836 +3266.85 +27.3712 +3145.78 +27.3587 +2973.16 +27.3463 +2903.35 +27.3339 +2883.99 +27.3215 +2913.09 +27.3091 +2939.03 +27.2967 +2841.41 +27.2844 +2899.11 +27.2721 +2941.94 +27.2597 +3009.92 +27.2474 +2996.62 +27.2352 +2932.21 +27.2229 +2855.78 +27.2106 +2830.32 +27.1984 +2810.04 +27.1862 +2828.48 +27.174 +2829.19 +27.1618 +2838.48 +27.1497 +2881.15 +27.1375 +2884.97 +27.1254 +2841.51 +27.1132 +2794.38 +27.1011 +2801.53 +27.0891 +2859.32 +27.077 +2848.6 +27.0649 +2890.32 +27.0529 +2866.95 +27.0409 +2988.53 +27.0289 +3065.19 +27.0169 +3353.8 +27.0049 +4062.05 +26.993 +4616.31 +26.981 +4853.89 +26.9691 +4490.87 +26.9572 +3765.91 +26.9453 +3300.31 +26.9334 +2970.04 +26.9215 +2794.55 +26.9097 +2702.77 +26.8979 +2787.06 +26.8861 +2773.82 +26.8743 +2764.71 +26.8625 +2776.82 +26.8507 +2849.4 +26.8389 +3048.86 +26.8272 +3285.1 +26.8155 +3501.76 +26.8038 +3329.89 +26.7921 +3049.89 +26.7804 +2986.11 +26.7688 +2968.11 +26.7571 +3107.31 +26.7455 +3108.4 +26.7339 +3129.88 +26.7223 +3197.95 +26.7107 +3252.79 +26.6991 +3153.13 +26.6875 +2969.74 +26.676 +2903.61 +26.6645 +2806.79 +26.653 +2630.74 +26.6415 +2525.55 +26.63 +2447.53 +26.6185 +2495.73 +26.6071 +2439.26 +26.5956 +2320.56 +26.5842 +2270.39 +26.5728 +2189 +26.5614 +2146.4 +26.55 +2145.97 +26.5387 +2481.3 +26.5273 +2923.49 +26.516 +3336.18 +26.5047 +3497.1 +26.4934 +3877.89 +26.4821 +5639.11 +26.4708 +8506.63 +26.4595 +10836.6 +26.4483 +9606.1 +26.4371 +5735.98 +26.4258 +2957.68 +26.4146 +1822.83 +26.4034 +1316.72 +26.3923 +1085.79 +26.3811 +970.5 +26.37 +926.149 +26.3588 +885.194 +26.3477 +862.1 +26.3366 +799.702 +26.3255 +807.653 +26.3144 +790.556 +26.3034 +801.822 +26.2923 +841.277 +26.2813 +853.177 +26.2703 +910.874 +26.2593 +1042.11 +26.2483 +1244.53 +26.2373 +1580.05 +26.2263 +1477.39 +26.2154 +1095.16 +26.2044 +884.679 +26.1935 +814.372 +26.1826 +791.712 +26.1717 +743.845 +26.1608 +753.034 +26.1499 +735.01 +26.1391 +700.411 +26.1282 +716.832 +26.1174 +716.658 +26.1066 +715.484 +26.0958 +721.596 +26.085 +747.636 +26.0742 +710.279 +26.0635 +697.313 +26.0527 +700.184 +26.042 +719.588 +26.0312 +759.877 +26.0205 +760.659 +26.0098 +774.439 +25.9991 +720.757 +25.9885 +752.16 +25.9778 +740.95 +25.9672 +744.767 +25.9565 +728.899 +25.9459 +707.586 +25.9353 +697.976 +25.9247 +688.251 +25.9142 +713.734 +25.9036 +687.787 +25.893 +650.849 +25.8825 +705.612 +25.872 +722.99 +25.8614 +719.757 +25.8509 +689.692 +25.8405 +668.031 +25.83 +690.496 +25.8195 +782.009 +25.8091 +785.314 +25.7986 +885.212 +25.7882 +922.177 +25.7778 +903.521 +25.7674 +880.802 +25.757 +779.619 +25.7466 +751.04 +25.7363 +707.866 +25.7259 +704.754 +25.7156 +645.032 +25.7052 +691.109 +25.6949 +716.191 +25.6846 +693.909 +25.6743 +664.448 +25.6641 +693.913 +25.6538 +701.625 +25.6436 +655.499 +25.6333 +654.445 +25.6231 +674.567 +25.6129 +662.513 +25.6027 +685.018 +25.5925 +653.953 +25.5823 +653.373 +25.5721 +658.506 +25.562 +682.785 +25.5518 +662.773 +25.5417 +638.873 +25.5316 +668.538 +25.5215 +687.657 +25.5114 +666.419 +25.5013 +638.456 +25.4912 +658.783 +25.4812 +692.175 +25.4711 +678.845 +25.4611 +667.156 +25.4511 +681.897 +25.4411 +659.374 +25.4311 +646.886 +25.4211 +675.337 +25.4111 +690.599 +25.4012 +677.649 +25.3912 +650.113 +25.3813 +647.628 +25.3713 +645.977 +25.3614 +656.456 +25.3515 +695.995 +25.3416 +709.987 +25.3317 +693.565 +25.3219 +677.359 +25.312 +669.894 +25.3022 +699.649 +25.2923 +666.535 +25.2825 +675.945 +25.2727 +665.449 +25.2629 +693.887 +25.2531 +717.518 +25.2433 +740.69 +25.2336 +712.263 +25.2238 +708.491 +25.2141 +704.775 +25.2043 +697.856 +25.1946 +701.851 +25.1849 +698.153 +25.1752 +706.236 +25.1655 +660.917 +25.1558 +643.383 +25.1462 +668.174 +25.1365 +673.139 +25.1269 +706.439 +25.1172 +743.437 +25.1076 +735.602 +25.098 +700.626 +25.0884 +680.974 +25.0788 +703.162 +25.0692 +708.584 +25.0597 +699.602 +25.0501 +727.802 +25.0406 +734.313 +25.031 +714.841 +25.0215 +691.855 +25.012 +724.871 +25.0025 +706.572 +24.993 +731.703 +24.9835 +734.806 +24.974 +752.743 +24.9646 +731.565 +24.9551 +734.231 +24.9457 +712.593 +24.9363 +717.394 +24.9269 +741.59 +24.9175 +745.817 +24.9081 +809.792 +24.8987 +798.709 +24.8893 +840.966 +24.8799 +759.28 +24.8706 +689.775 +24.8613 +691.945 +24.8519 +727.217 +24.8426 +755.684 +24.8333 +739.961 +24.824 +766.44 +24.8147 +725.648 +24.8054 +723.688 +24.7962 +735.84 +24.7869 +719.638 +24.7777 +708.913 +24.7684 +725.817 +24.7592 +695.256 +24.75 +702.168 +24.7408 +694.662 +24.7316 +738.886 +24.7224 +736.227 +24.7132 +743.942 +24.7041 +721.455 +24.6949 +745.532 +24.6858 +750.344 +24.6766 +738.152 +24.6675 +764.307 +24.6584 +784.343 +24.6493 +732.664 +24.6402 +708.189 +24.6311 +748.01 +24.622 +771.726 +24.613 +743.654 +24.6039 +802.587 +24.5949 +732.273 +24.5858 +753.307 +24.5768 +777.759 +24.5678 +794.737 +24.5588 +727.213 +24.5498 +734.891 +24.5408 +746.685 +24.5318 +810.113 +24.5229 +798.367 +24.5139 +781.758 +24.505 +745.457 +24.496 +796.885 +24.4871 +772.662 +24.4782 +752.297 +24.4693 +778.957 +24.4604 +804.677 +24.4515 +791.335 +24.4426 +838.846 +24.4338 +855.892 +24.4249 +834.514 +24.4161 +825.182 +24.4072 +792.076 +24.3984 +765.702 +24.3896 +731.4 +24.3808 +793.143 +24.372 +807.13 +24.3632 +847.999 +24.3544 +834.696 +24.3456 +829.928 +24.3369 +957.441 +24.3281 +1228.39 +24.3194 +1611.42 +24.3106 +1710.01 +24.3019 +1220.34 +24.2932 +775.257 +24.2845 +657.65 +24.2758 +589.275 +24.2671 +555.574 +24.2584 +540.144 +24.2497 +535.202 +24.2411 +561.554 +24.2324 +592.902 +24.2238 +567.368 +24.2152 +558.715 +24.2065 +593.777 +24.1979 +602.623 +24.1893 +585.821 +24.1807 +569.15 +24.1721 +614.427 +24.1636 +569.133 +24.155 +541.748 +24.1464 +527.352 +24.1379 +540.28 +24.1294 +536.909 +24.1208 +531.737 +24.1123 +489.602 +24.1038 +505.324 +24.0953 +510.439 +24.0868 +469.33 +24.0783 +476.742 +24.0698 +510.94 +24.0614 +515.15 +24.0529 +615.671 +24.0445 +759.427 +24.036 +802.359 +24.0276 +872.665 +24.0192 +799.813 +24.0107 +655.019 +24.0023 +552.074 +23.9939 +666.262 +23.9856 +948.54 +23.9772 +925.154 +23.9688 +488.365 +23.9604 +220.489 +23.9521 +174.542 +23.9437 +162.444 +23.9354 +162 +23.9271 +152.931 +23.9188 +143.328 +23.9105 +144.569 +23.9022 +148.845 +23.8939 +141.025 +23.8856 +122.192 +23.8773 +126.124 +23.869 +126.815 +23.8608 +107.827 +23.8525 +114.164 +23.8443 +116.653 +23.8361 +119.557 +23.8278 +137.364 +23.8196 +149.581 +23.8114 +130.929 +23.8032 +164.528 +23.795 +180.656 +23.7868 +207.756 +23.7787 +239.018 +23.7705 +282.917 +23.7624 +314.528 +23.7542 +337.866 +23.7461 +337.469 +23.7379 +243.387 +23.7298 +165.442 +23.7217 +116.962 +23.7136 +105.264 +23.7055 +82.2528 +23.6974 +75.9785 +23.6893 +76.2064 +23.6813 +83.4402 +23.6732 +83.9909 +23.6651 +88.9014 +23.6571 +120.144 +23.649 +132.782 +23.641 +163.834 +23.633 +191.291 +23.625 +171.302 +23.617 +182.152 +23.609 +175.119 +23.601 +132.172 +23.593 +118.131 +23.585 +74.9546 +23.5771 +52.0199 +23.5691 +18.1529 +23.5611 +end of experiment diff --git a/tests/test_reader.py b/tests/test_reader.py index 70326871..73180692 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -41,7 +41,7 @@ def test_example_data(): reader_dirs = sorted(glob(os.path.join(data_dir, "*"))) - for reader_dir in reader_dirs: + for reader_dir in reader_dirs[:1]: input_files = sorted(glob(os.path.join(reader_dir, "*"))) for supported_nxdl in reader.supported_nxdls: @@ -58,39 +58,46 @@ def test_example_data(): ) assert isinstance(read_data, Template) - assert validate_data_dict(template, read_data, root) - - -def test_vms_mapper(): - mapper = VamasMapper - data_dir = os.path.join(os.path.dirname(__file__), "data", "vms") - - files_and_keys = { - "EX889_S1110_MgFe2O4_spent_irregular": { - "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Survey/scan_mode": "REGULAR", - "data['2 S1110, UHV, RT, Epass = 20 eV__MgKLL_1']['cycle0']": 1351, - }, - "EX889_S1110_MgFe2O4_spent_irregular": { - "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Survey/scan_mode": "IRREGULAR", - "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Fe2p/instrument/analyser/energydispersion/scan_mode": "FixedAnalyserTransmission", - "data['2 S1110, UHV, RT, Epass = 20 eV__Fe3s-Si2p-Mg2s']['cycle0']": 761, - }, - } - - # (C["benz"], "20240122_SBenz_102_20240122_SBenz_SnO2_10nm.vms"), - # (r"C:\Users\pielsticker\Lukas\MPI-CEC\Projects\deepxps\RUB MDI\example_spectra_Florian\Co", "Co 2p 0008751 M1.vms"), - # (C["pielst"], C["EX889"], "vms", f"{C['EX889']}_regular.vms"), - ((C["pielst"], C["EX889"], "vms", f"{C['EX889']}_irregular.vms"),) - # (C["schu"], "CleanData-alphaII VOPO4 C2 BC4316.vms"), - # (C["pielst"], C["EX889"], "vms", "d_reg.vms"), - ((C["pielst"], C["EX889"], "vms", "d_irreg.vms"),) - - for vms_file in os.listdir(data_dir): - data = mapper.parse_file(file=file) - - -for k, v in d.items(): - if isinstance(v, str): - # print(k) - if "REG" in v: - print(k) + # validate_data_dict(template, read_data, root) + # assert validate_data_dict(template, read_data, root) + + return read_data.get_accumulated_dict() + + +data = test_example_data() + +# ============================================================================= +# def test_vms_mapper(): +# mapper = VamasMapper +# data_dir = os.path.join(os.path.dirname(__file__), "data", "vms") +# +# files_and_keys = { +# "regular": { +# "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Survey/scan_mode": "REGULAR", +# "data['2 S1110, UHV, RT, Epass = 20 eV__MgKLL_1']['cycle0']": 1351, +# }, +# "irregular": { +# "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Survey/scan_mode": "IRREGULAR", +# "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Fe2p/instrument/analyser/energydispersion/scan_mode": "FixedAnalyserTransmission", +# "data['2 S1110, UHV, RT, Epass = 20 eV__Fe3s-Si2p-Mg2s']['cycle0']": 761, +# }, +# } +# +# # (C["benz"], "20240122_SBenz_102_20240122_SBenz_SnO2_10nm.vms"), +# # (r"C:\Users\pielsticker\Lukas\MPI-CEC\Projects\deepxps\RUB MDI\example_spectra_Florian\Co", "Co 2p 0008751 M1.vms"), +# # (C["pielst"], C["EX889"], "vms", f"{C['EX889']}_regular.vms"), +# ((C["pielst"], C["EX889"], "vms", f"{C['EX889']}_irregular.vms"),) +# # (C["schu"], "CleanData-alphaII VOPO4 C2 BC4316.vms"), +# # (C["pielst"], C["EX889"], "vms", "d_reg.vms"), +# ((C["pielst"], C["EX889"], "vms", "d_irreg.vms"),) +# +# for vms_file in os.listdir(data_dir): +# data = mapper.parse_file(file=file) +# +# +# for k, v in d.items(): +# if isinstance(v, str): +# # print(k) +# if "REG" in v: +# print(k) +# ============================================================================= From 15002a0bd6d7a48a8bf8036315f7163e8b2109c1 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 15 Mar 2024 09:28:48 +0100 Subject: [PATCH 17/41] add regular and irregular vms test data --- .../data/{vms => vms_irregular}/eln_data.yaml | 0 tests/data/vms_irregular/irregular.vms | 4141 +++++++++++++++++ tests/data/vms_regular/eln_data.yaml | 147 + tests/data/{vms => vms_regular}/regular.vms | 0 4 files changed, 4288 insertions(+) rename tests/data/{vms => vms_irregular}/eln_data.yaml (100%) create mode 100644 tests/data/vms_irregular/irregular.vms create mode 100644 tests/data/vms_regular/eln_data.yaml rename tests/data/{vms => vms_regular}/regular.vms (100%) diff --git a/tests/data/vms/eln_data.yaml b/tests/data/vms_irregular/eln_data.yaml similarity index 100% rename from tests/data/vms/eln_data.yaml rename to tests/data/vms_irregular/eln_data.yaml diff --git a/tests/data/vms_irregular/irregular.vms b/tests/data/vms_irregular/irregular.vms new file mode 100644 index 00000000..b38b6325 --- /dev/null +++ b/tests/data/vms_irregular/irregular.vms @@ -0,0 +1,4141 @@ +VAMAS Surface Chemical Analysis Standard Data Transfer Format 1988 May 4 +Not Specified +Not Specified +Not Specified +Not Specified +5 +Casa Info Follows CasaXPS Version 2.3.26PR1.0 +0 +Created by SpecsLab Prodigy, Version 4.100.1-r111001 +SourceAnalyserAngle: Not Specified +CasaRowLabel:1 as-loaded +NORM +IRREGULAR +1 +1 +Value +d +0 +0 +0 +0 +1 +Counts per Second +1 as-loaded +0 +0 +0 +0 +0 +0 +0 +6 +Casa Info Follows +0 +0 +0 +0 + +XPS +0 +Al +1486.61 +1e+037 +1e+037 +1e+037 +1e+037 +1e+037 +FAT +1e+037 +1e+037 +1e+037 +1e+037 +1e+037 +1e+037 +1e+037 +1e+037 +Survey + +-1 +3 +Kinetic Energy +eV +Intensity +d +transmission +d +pulse counting +1 +1 +1e+037 +1e+037 +1e+037 +1e+037 +2 +MFP Exponent +d +0 +ESCAPE DEPTH TYPE +d +1 +4053 +0 +1 +0 +1 +0 +1 +136.61 +15598.7 +78.8103 +137.61 +15867.9 +78.5146 +138.61 +15651.5 +78.2222 +139.61 +15321.3 +77.933 +140.61 +15793.4 +77.647 +141.61 +15662 +77.3642 +142.61 +15599 +77.0844 +143.61 +15758.9 +76.8076 +144.61 +15681.7 +76.5338 +145.61 +15968.1 +76.2628 +146.61 +15844.6 +75.9948 +147.61 +15328.3 +75.7295 +148.61 +15541 +75.467 +149.61 +15355.9 +75.2073 +150.61 +15531.3 +74.9501 +151.61 +15831.1 +74.6956 +152.61 +15628.4 +74.4437 +153.61 +15643.4 +74.1943 +154.61 +15649.2 +73.9474 +155.61 +15508.5 +73.703 +156.61 +16168.7 +73.4609 +157.61 +16783.7 +73.2213 +158.61 +16696.5 +72.9839 +159.61 +17242 +72.7489 +160.61 +16225.4 +72.5161 +161.61 +16518.6 +72.2855 +162.61 +16381.9 +72.0571 +163.61 +16956.2 +71.8309 +164.61 +16503.2 +71.6068 +165.61 +17074.8 +71.3847 +166.61 +16608.9 +71.1647 +167.61 +16689.8 +70.9468 +168.61 +16261.6 +70.7308 +169.61 +16260.5 +70.5168 +170.61 +15986.7 +70.3047 +171.61 +15943.1 +70.0945 +172.61 +15576.2 +69.8862 +173.61 +15749.3 +69.6798 +174.61 +15307.1 +69.4751 +175.61 +15088.5 +69.2723 +176.61 +15583.9 +69.0712 +177.61 +15913.9 +68.8719 +178.61 +17185.3 +68.6743 +179.61 +17381.4 +68.4783 +180.61 +20956.8 +68.2841 +181.61 +26719.6 +68.0914 +182.61 +27570.7 +67.9004 +183.61 +22744.5 +67.711 +184.61 +17508.6 +67.5232 +185.61 +15654.7 +67.337 +186.61 +15118.7 +67.1522 +187.61 +15568.8 +66.969 +188.61 +15345.7 +66.7873 +189.61 +15303 +66.607 +190.61 +14938 +66.4282 +191.61 +15054.6 +66.2508 +192.61 +14976.5 +66.0749 +193.61 +15205 +65.9003 +194.61 +15306.2 +65.7271 +195.61 +15772.5 +65.5553 +196.61 +15744.1 +65.3848 +197.61 +15599.9 +65.2156 +198.61 +15973.4 +65.0477 +199.61 +15693.5 +64.8812 +200.61 +15909.2 +64.7159 +201.61 +16198.6 +64.5518 +202.61 +15966.9 +64.389 +203.61 +15489.1 +64.2274 +204.61 +16474.9 +64.0671 +205.61 +15956.1 +63.9079 +206.61 +16501.6 +63.7499 +207.61 +15931.6 +63.5931 +208.61 +16115.7 +63.4374 +209.61 +16611.5 +63.2829 +210.61 +16061 +63.1295 +211.61 +16121.6 +62.9772 +212.61 +16202.9 +62.8259 +213.61 +16392.4 +62.6758 +214.61 +16503.7 +62.5268 +215.61 +16364.4 +62.3788 +216.61 +16383.3 +62.2318 +217.61 +15654.5 +62.0859 +218.61 +16709.3 +61.941 +219.61 +16583.1 +61.7972 +220.61 +17054.4 +61.6543 +221.61 +16442.2 +61.5124 +222.61 +16428.8 +61.3715 +223.61 +16359.6 +61.2315 +224.61 +17035.9 +61.0925 +225.61 +16781.8 +60.9544 +226.61 +16532.9 +60.8173 +227.61 +16559.9 +60.6811 +228.61 +17396.7 +60.5458 +229.61 +17337.8 +60.4114 +230.61 +16964.5 +60.2779 +231.61 +17236.6 +60.1453 +232.61 +17187.5 +60.0135 +233.61 +17685.7 +59.8826 +234.61 +17413.9 +59.7526 +235.61 +17348.1 +59.6234 +236.61 +17745.6 +59.495 +237.61 +17594.6 +59.3675 +238.61 +16802.7 +59.2408 +239.61 +17579.8 +59.1149 +240.61 +17782.9 +58.9898 +241.61 +18013.3 +58.8655 +242.61 +18298.8 +58.7419 +243.61 +18710.3 +58.6192 +244.61 +19254 +58.4972 +245.61 +18792.1 +58.3759 +246.61 +18473.2 +58.2554 +247.61 +18138.4 +58.1357 +248.61 +18382 +58.0167 +249.61 +18782.5 +57.8984 +250.61 +18880.3 +57.7808 +251.61 +18841.1 +57.664 +252.61 +19294.1 +57.5479 +253.61 +19521.4 +57.4324 +254.61 +19505.7 +57.3177 +255.61 +19003.9 +57.2036 +256.61 +18726.7 +57.0902 +257.61 +19079.4 +56.9775 +258.61 +19667.5 +56.8655 +259.61 +19860.6 +56.7541 +260.61 +19563 +56.6433 +261.61 +18944.9 +56.5332 +262.61 +19116.6 +56.4238 +263.61 +19366.5 +56.315 +264.61 +19505.1 +56.2068 +265.61 +19660.1 +56.0992 +266.61 +19174.2 +55.9922 +267.61 +19440.8 +55.8859 +268.61 +18765.7 +55.7801 +269.61 +19529.4 +55.675 +270.61 +19357.7 +55.5704 +271.61 +19126.9 +55.4665 +272.61 +19879 +55.3631 +273.61 +19197.5 +55.2603 +274.61 +18743 +55.158 +275.61 +19303.7 +55.0564 +276.61 +18895.3 +54.9553 +277.61 +18912.6 +54.8547 +278.61 +19686.7 +54.7547 +279.61 +20311.5 +54.6552 +280.61 +20127.5 +54.5563 +281.61 +20015.3 +54.4579 +282.61 +19671.3 +54.3601 +283.61 +20388.9 +54.2627 +284.61 +20034.7 +54.1659 +285.61 +19391.1 +54.0696 +286.61 +20300.1 +53.9738 +287.61 +21079.8 +53.8786 +288.61 +20574.4 +53.7838 +289.61 +20595.9 +53.6895 +290.61 +20473.3 +53.5957 +291.61 +20257.8 +53.5024 +292.61 +20594.2 +53.4096 +293.61 +21018 +53.3173 +294.61 +20826.8 +53.2255 +295.61 +20919.6 +53.1341 +296.61 +21146.1 +53.0432 +297.61 +20211.1 +52.9528 +298.61 +20873.9 +52.8628 +299.61 +21184.1 +52.7733 +300.61 +20921.1 +52.6842 +301.61 +20697.5 +52.5956 +302.61 +21410.1 +52.5074 +303.61 +20987.3 +52.4197 +304.61 +21123.2 +52.3324 +305.61 +21283.8 +52.2455 +306.61 +21746.4 +52.1591 +307.61 +22075.1 +52.0731 +308.61 +21570 +51.9875 +309.61 +21459.8 +51.9024 +310.61 +21401.2 +51.8176 +311.61 +21486.6 +51.7333 +312.61 +21931.1 +51.6494 +313.61 +21588.9 +51.5659 +314.61 +21547.3 +51.4828 +315.61 +23607.3 +51.4001 +316.61 +22903.4 +51.3178 +317.61 +22515.3 +51.2358 +318.61 +22090.6 +51.1543 +319.61 +21863 +51.0732 +320.61 +22432.8 +50.9924 +321.61 +23020.4 +50.9121 +322.61 +22759.1 +50.8321 +323.61 +23162.8 +50.7525 +324.61 +22785.6 +50.6732 +325.61 +22876.4 +50.5944 +326.61 +23135.4 +50.5159 +327.61 +23241.3 +50.4377 +328.61 +23401.4 +50.36 +329.61 +23775.4 +50.2825 +330.61 +23535.7 +50.2055 +331.61 +23399.7 +50.1288 +332.61 +23587.6 +50.0524 +333.61 +23859.4 +49.9764 +334.61 +23837.4 +49.9007 +335.61 +23578.4 +49.8254 +336.61 +23574.6 +49.7504 +337.61 +23347.3 +49.6758 +338.61 +23557.3 +49.6015 +339.61 +23525.4 +49.5275 +340.61 +23911.9 +49.4539 +341.61 +23944.1 +49.3805 +342.61 +24266.8 +49.3076 +343.61 +24470.3 +49.2349 +344.61 +24506 +49.1625 +345.61 +24284 +49.0905 +346.61 +24114.6 +49.0188 +347.61 +24776.2 +48.9474 +348.61 +24734.3 +48.8763 +349.61 +24520.9 +48.8055 +350.61 +24584.1 +48.735 +351.61 +25100.2 +48.6649 +352.61 +24669.4 +48.595 +353.61 +25163.5 +48.5254 +354.61 +24937.1 +48.4561 +355.61 +25585.9 +48.3872 +356.61 +25144.7 +48.3185 +357.61 +25014.5 +48.2501 +358.61 +25424.6 +48.182 +359.61 +25447.9 +48.1142 +360.61 +25640.2 +48.0466 +361.61 +26136.4 +47.9794 +362.61 +25730.6 +47.9124 +363.61 +26115.1 +47.8458 +364.61 +25993.9 +47.7793 +365.61 +26140.3 +47.7132 +366.61 +26458.3 +47.6474 +367.61 +25692.8 +47.5818 +368.61 +25948.6 +47.5165 +369.61 +26384.9 +47.4514 +370.61 +26150.8 +47.3866 +371.61 +26184 +47.3221 +372.61 +26887.5 +47.2579 +373.61 +27048.6 +47.1939 +374.61 +26457.8 +47.1301 +375.61 +26742.6 +47.0667 +376.61 +26680.6 +47.0035 +377.61 +26872.7 +46.9405 +378.61 +27118.8 +46.8778 +379.61 +27491.5 +46.8153 +380.61 +26834.9 +46.7531 +381.61 +27169.7 +46.6911 +382.61 +27231.8 +46.6294 +383.61 +27885 +46.5679 +384.61 +27614.6 +46.5067 +385.61 +27740.6 +46.4457 +386.61 +27574.8 +46.385 +387.61 +27769.5 +46.3244 +388.61 +27314.5 +46.2642 +389.61 +28164.6 +46.2041 +390.61 +28215.2 +46.1443 +391.61 +27772.4 +46.0847 +392.61 +27946.3 +46.0254 +393.61 +28072 +45.9663 +394.61 +28986.1 +45.9074 +395.61 +28640.9 +45.8487 +396.61 +27931.4 +45.7903 +397.61 +27800.6 +45.732 +398.61 +29132.5 +45.674 +399.61 +28665.1 +45.6163 +400.61 +28725.3 +45.5587 +401.61 +29136.3 +45.5014 +402.61 +29238.4 +45.4442 +403.61 +29365.2 +45.3873 +404.61 +29056.3 +45.3306 +405.61 +29495.9 +45.2741 +406.61 +28955.4 +45.2179 +407.61 +29597 +45.1618 +408.61 +29193.9 +45.1059 +409.61 +29321.1 +45.0503 +410.61 +29775.9 +44.9948 +411.61 +29377.4 +44.9396 +412.61 +29529.6 +44.8846 +413.61 +29828.1 +44.8297 +414.61 +30018.2 +44.7751 +415.61 +29834 +44.7206 +416.61 +29996.3 +44.6664 +417.61 +30373.1 +44.6124 +418.61 +30314.6 +44.5585 +419.61 +31086.5 +44.5049 +420.61 +30178 +44.4514 +421.61 +30253.2 +44.3981 +422.61 +30820.5 +44.3451 +423.61 +30735 +44.2922 +424.61 +31271 +44.2395 +425.61 +31323.7 +44.187 +426.61 +30857.3 +44.1346 +427.61 +31076.5 +44.0825 +428.61 +30252.6 +44.0306 +429.61 +31432.3 +43.9788 +430.61 +31016 +43.9272 +431.61 +32185.6 +43.8758 +432.61 +31861.4 +43.8246 +433.61 +31905.9 +43.7735 +434.61 +32140.4 +43.7226 +435.61 +31882.5 +43.672 +436.61 +31804.1 +43.6214 +437.61 +32339.6 +43.5711 +438.61 +31953.6 +43.5209 +439.61 +32897.1 +43.4709 +440.61 +32456.5 +43.4211 +441.61 +32561.5 +43.3715 +442.61 +32865.1 +43.322 +443.61 +32733.6 +43.2727 +444.61 +32345.2 +43.2235 +445.61 +32541.6 +43.1745 +446.61 +33078.3 +43.1257 +447.61 +32882.7 +43.0771 +448.61 +32824.1 +43.0286 +449.61 +32145.7 +42.9803 +450.61 +33879.3 +42.9321 +451.61 +33944.5 +42.8841 +452.61 +33463.8 +42.8363 +453.61 +33995.7 +42.7886 +454.61 +34321.7 +42.7411 +455.61 +33712.2 +42.6937 +456.61 +33822.9 +42.6465 +457.61 +35198.5 +42.5995 +458.61 +34655.7 +42.5526 +459.61 +34811.3 +42.5059 +460.61 +34009.6 +42.4593 +461.61 +34859 +42.4129 +462.61 +35005.1 +42.3666 +463.61 +34346.9 +42.3205 +464.61 +34454.5 +42.2745 +465.61 +35311.3 +42.2287 +466.61 +36074.3 +42.183 +467.61 +36582.6 +42.1374 +468.61 +36478 +42.0921 +469.61 +36448.4 +42.0468 +470.61 +36802.7 +42.0017 +471.61 +37718.8 +41.9568 +472.61 +37531.8 +41.912 +473.61 +36481.2 +41.8673 +474.61 +36675.2 +41.8228 +475.61 +36365.3 +41.7784 +476.61 +36290.3 +41.7342 +477.61 +36313.8 +41.6901 +478.61 +36661.6 +41.6462 +479.61 +37912.6 +41.6024 +480.61 +37630.1 +41.5587 +481.61 +37773.1 +41.5151 +482.61 +37597.9 +41.4717 +483.61 +38116.1 +41.4285 +484.61 +38829.8 +41.3853 +485.61 +39484.7 +41.3423 +486.61 +38626 +41.2995 +487.61 +39142.2 +41.2567 +488.61 +40090.2 +41.2141 +489.61 +39201.1 +41.1717 +490.61 +39574.7 +41.1293 +491.61 +38654.2 +41.0871 +492.61 +37852.7 +41.0451 +493.61 +38725.2 +41.0031 +494.61 +37536.5 +40.9613 +495.61 +38446 +40.9196 +496.61 +38553.7 +40.878 +497.61 +37948.7 +40.8366 +498.61 +38602.9 +40.7953 +499.61 +37477.9 +40.7541 +500.61 +37154.9 +40.713 +501.61 +37456.5 +40.6721 +502.61 +38694.4 +40.6313 +503.61 +39504.9 +40.5906 +504.61 +39709.5 +40.55 +505.61 +40968.1 +40.5096 +506.61 +42570.4 +40.4692 +507.61 +44598.6 +40.429 +508.61 +46921.3 +40.389 +509.61 +47219.7 +40.349 +510.61 +44644 +40.3091 +511.61 +42621.2 +40.2694 +512.61 +41423.9 +40.2298 +513.61 +40569.1 +40.1903 +514.61 +39280.1 +40.1509 +515.61 +38828.2 +40.1116 +516.61 +38663.8 +40.0725 +517.61 +37253.6 +40.0334 +518.61 +37653.3 +39.9945 +519.61 +37098.3 +39.9557 +520.61 +35628.9 +39.917 +521.61 +36215.5 +39.8784 +522.61 +35974.2 +39.84 +523.61 +35966.6 +39.8016 +524.61 +36380.7 +39.7633 +525.61 +36111.9 +39.7252 +526.61 +35791 +39.6872 +527.61 +36429.6 +39.6492 +528.61 +35897.4 +39.6114 +529.61 +35974 +39.5737 +530.61 +35544.8 +39.5361 +531.61 +35471.6 +39.4986 +532.61 +36427.2 +39.4612 +533.61 +36693.3 +39.424 +534.61 +36934.2 +39.3868 +535.61 +36730.8 +39.3497 +536.61 +36751.1 +39.3127 +537.61 +35881.9 +39.2759 +538.61 +36926.7 +39.2391 +539.61 +37109.6 +39.2025 +540.61 +36861 +39.1659 +541.61 +37605.2 +39.1295 +542.61 +37078.4 +39.0931 +543.61 +37794.9 +39.0569 +544.61 +37610.4 +39.0207 +545.61 +37185.9 +38.9847 +546.61 +36840.6 +38.9487 +547.61 +37486.6 +38.9129 +548.61 +38197.9 +38.8771 +549.61 +38255.4 +38.8415 +550.61 +37829.5 +38.8059 +551.61 +38162.7 +38.7705 +552.61 +38173.4 +38.7351 +553.61 +37677.9 +38.6999 +554.61 +38357.6 +38.6647 +555.61 +38313.5 +38.6296 +556.61 +38460.4 +38.5946 +557.61 +38614.9 +38.5598 +558.61 +38816.5 +38.525 +559.61 +38655.6 +38.4903 +560.61 +38574.5 +38.4557 +561.61 +38757.5 +38.4212 +562.61 +39066.8 +38.3868 +563.61 +39293.6 +38.3525 +564.61 +39082.4 +38.3182 +565.61 +38439.1 +38.2841 +566.61 +39090.5 +38.25 +567.61 +38152.9 +38.2161 +568.61 +38546.3 +38.1822 +569.61 +38729.4 +38.1485 +570.61 +39550 +38.1148 +571.61 +39425 +38.0812 +572.61 +39291.3 +38.0477 +573.61 +39660 +38.0142 +574.61 +39880.6 +37.9809 +575.61 +39459.2 +37.9477 +576.61 +40366.3 +37.9145 +577.61 +39404.3 +37.8814 +578.61 +39114 +37.8485 +579.61 +39442.1 +37.8156 +580.61 +39894.8 +37.7828 +581.61 +40594.5 +37.75 +582.61 +41142 +37.7174 +583.61 +41314.5 +37.6848 +584.61 +40379.4 +37.6524 +585.61 +40518.3 +37.62 +586.61 +40805.8 +37.5877 +587.61 +40031.3 +37.5554 +588.61 +40935.1 +37.5233 +589.61 +41727.4 +37.4912 +590.61 +41213.8 +37.4593 +591.61 +40366.5 +37.4274 +592.61 +39954.5 +37.3956 +593.61 +40601.8 +37.3638 +594.61 +41550.4 +37.3322 +595.61 +41174.2 +37.3006 +596.61 +39908.5 +37.2691 +597.61 +40004.1 +37.2377 +598.61 +40413.5 +37.2064 +599.61 +38703.8 +37.1751 +600.61 +37789.9 +37.1439 +601.61 +37104.1 +37.1129 +602.61 +37906 +37.0818 +603.61 +38442 +37.0509 +604.61 +38213.2 +37.02 +605.61 +38043.7 +36.9892 +606.61 +38022.1 +36.9585 +607.61 +37336.4 +36.9279 +608.61 +37188.2 +36.8973 +609.61 +37037.1 +36.8669 +610.61 +37581.6 +36.8365 +611.61 +37433.9 +36.8061 +612.61 +37219.2 +36.7759 +613.61 +37174.9 +36.7457 +614.61 +36637.6 +36.7156 +615.61 +37304.1 +36.6856 +616.61 +38202.2 +36.6556 +617.61 +37762.2 +36.6257 +618.61 +37774.4 +36.5959 +619.61 +37669.5 +36.5662 +620.61 +37697.1 +36.5365 +621.61 +38054.5 +36.5069 +622.61 +38066.4 +36.4774 +623.61 +38224 +36.4479 +624.61 +37840 +36.4185 +625.61 +38640.1 +36.3892 +626.61 +38021.2 +36.36 +627.61 +37930.2 +36.3308 +628.61 +38559.7 +36.3017 +629.61 +38650.8 +36.2727 +630.61 +39697.5 +36.2437 +631.61 +39652.1 +36.2148 +632.61 +39516 +36.186 +633.61 +39685.8 +36.1573 +634.61 +39936.1 +36.1286 +635.61 +40013.3 +36.1 +636.61 +39355 +36.0714 +637.61 +39828.9 +36.0429 +638.61 +40402.7 +36.0145 +639.61 +40237.4 +35.9862 +640.61 +39118.1 +35.9579 +641.61 +39216 +35.9297 +642.61 +40227.9 +35.9015 +643.61 +40883.7 +35.8734 +644.61 +40411.3 +35.8454 +645.61 +40176.1 +35.8175 +646.61 +39271.9 +35.7896 +647.61 +38728.6 +35.7618 +648.61 +38762.4 +35.734 +649.61 +38124.8 +35.7063 +650.61 +38105.2 +35.6787 +651.61 +37059.5 +35.6511 +652.61 +36613.2 +35.6236 +653.61 +35633.9 +35.5962 +654.61 +35011.2 +35.5688 +655.61 +34671.8 +35.5415 +656.61 +34094 +35.5143 +657.61 +34108.6 +35.4871 +658.61 +33420.5 +35.46 +659.61 +33424.4 +35.4329 +660.61 +33410.8 +35.4059 +661.61 +33088.8 +35.379 +662.61 +32447.9 +35.3521 +663.61 +32709.7 +35.3253 +664.61 +33042.6 +35.2986 +665.61 +33160.9 +35.2719 +666.61 +32475 +35.2452 +667.61 +32694.2 +35.2187 +668.61 +33356.6 +35.1922 +669.61 +32765.8 +35.1657 +670.61 +32989.5 +35.1393 +671.61 +33519.9 +35.113 +672.61 +33337.6 +35.0867 +673.61 +32959.6 +35.0605 +674.61 +33471.2 +35.0343 +675.61 +33635.7 +35.0082 +676.61 +34246.7 +34.9822 +677.61 +33536.4 +34.9562 +678.61 +33207 +34.9303 +679.61 +33850 +34.9044 +680.61 +34221.8 +34.8786 +681.61 +34150.6 +34.8529 +682.61 +33819.6 +34.8272 +683.61 +34058.2 +34.8016 +684.61 +34473.3 +34.776 +685.61 +34049.1 +34.7505 +686.61 +33899.6 +34.725 +687.61 +34278.1 +34.6996 +688.61 +32797.2 +34.6742 +689.61 +33498.7 +34.6489 +690.61 +33890.1 +34.6237 +691.61 +33946.7 +34.5985 +692.61 +34235.1 +34.5733 +693.61 +35156.4 +34.5483 +694.61 +35035.1 +34.5232 +695.61 +35841.3 +34.4983 +696.61 +35701.8 +34.4734 +697.61 +36570.7 +34.4485 +698.61 +36075.6 +34.4237 +699.61 +36441.3 +34.3989 +700.61 +37434.5 +34.3742 +701.61 +37228.9 +34.3496 +702.61 +37006.4 +34.325 +703.61 +36580.6 +34.3004 +704.61 +35991.7 +34.2759 +705.61 +35388.6 +34.2515 +706.61 +35170.2 +34.2271 +707.61 +35057.6 +34.2028 +708.61 +33893.8 +34.1785 +709.61 +32926.3 +34.1543 +710.61 +32694.2 +34.1301 +711.61 +33807.6 +34.106 +712.61 +34488.3 +34.0819 +713.61 +34494.1 +34.0578 +714.61 +33890.6 +34.0339 +715.61 +33283.8 +34.0099 +716.61 +33660.7 +33.9861 +717.61 +33621.6 +33.9622 +718.61 +33323.5 +33.9385 +719.61 +33790.5 +33.9147 +720.61 +32614.5 +33.8911 +721.61 +32874.5 +33.8674 +722.61 +32554.7 +33.8439 +723.61 +32398.9 +33.8203 +724.61 +33327.5 +33.7969 +725.61 +32870.3 +33.7734 +726.61 +32982 +33.7501 +727.61 +33512.6 +33.7267 +728.61 +33100.5 +33.7034 +729.61 +33131.8 +33.6802 +730.61 +33334.3 +33.657 +731.61 +32653.9 +33.6339 +732.61 +33982.8 +33.6108 +733.61 +33002.2 +33.5877 +734.61 +34189.1 +33.5647 +735.61 +33936.1 +33.5418 +736.61 +33454.2 +33.5189 +737.61 +33577.4 +33.496 +738.61 +34217.1 +33.4732 +739.61 +34104.8 +33.4505 +740.61 +34752.2 +33.4277 +741.61 +34329.4 +33.4051 +742.61 +35765.6 +33.3824 +743.61 +34927.8 +33.3599 +744.61 +34767.5 +33.3373 +745.61 +34605.9 +33.3148 +746.61 +33289.9 +33.2924 +747.61 +34213.2 +33.27 +748.61 +34434 +33.2477 +749.61 +34758.7 +33.2254 +750.61 +35532.1 +33.2031 +751.61 +36253.6 +33.1809 +752.61 +36049.4 +33.1587 +753.61 +37016.7 +33.1366 +754.61 +36226 +33.1145 +755.61 +36693.6 +33.0925 +756.61 +36628 +33.0705 +757.61 +36425.6 +33.0485 +758.61 +36881.5 +33.0266 +759.61 +37754.5 +33.0047 +760.61 +39094.9 +32.9829 +761.61 +39594.6 +32.9611 +762.61 +38731.3 +32.9394 +763.61 +38004.7 +32.9177 +764.61 +36773.6 +32.8961 +765.61 +34402.9 +32.8744 +766.61 +34239.4 +32.8529 +767.61 +33477 +32.8314 +768.61 +33150.5 +32.8099 +769.61 +33271.1 +32.7884 +770.61 +34049.5 +32.7671 +771.61 +34550.4 +32.7457 +772.61 +36645.3 +32.7244 +773.61 +39476.9 +32.7031 +774.61 +41438.5 +32.6819 +775.61 +40153.4 +32.6607 +776.61 +38074.8 +32.6396 +777.61 +33979.1 +32.6184 +778.61 +28033 +32.5974 +779.61 +24923.7 +32.5764 +780.61 +22677.4 +32.5554 +781.61 +22298.1 +32.5344 +782.61 +21216.5 +32.5135 +783.61 +21232.3 +32.4927 +784.61 +21897.1 +32.4718 +785.61 +21911 +32.4511 +786.61 +21791.9 +32.4303 +787.61 +21148.8 +32.4096 +788.61 +21907 +32.389 +789.61 +21630.1 +32.3683 +790.61 +21832.8 +32.3478 +791.61 +21832.1 +32.3272 +792.61 +21321.1 +32.3067 +793.61 +21291.8 +32.2862 +794.61 +21761.1 +32.2658 +795.61 +21710.7 +32.2454 +796.61 +21849.7 +32.2251 +797.61 +21955.4 +32.2048 +798.61 +22421.9 +32.1845 +799.61 +22618.3 +32.1642 +800.61 +22598.5 +32.144 +801.61 +22553.8 +32.1239 +802.61 +22017.1 +32.1038 +803.61 +22553.9 +32.0837 +804.61 +22201.3 +32.0636 +805.61 +21853.8 +32.0436 +806.61 +22413.4 +32.0237 +807.61 +22045.8 +32.0037 +808.61 +22473.1 +31.9838 +809.61 +22395.6 +31.964 +810.61 +22614.9 +31.9441 +811.61 +22934.8 +31.9244 +812.61 +22728.8 +31.9046 +813.61 +22716.2 +31.8849 +814.61 +22215.3 +31.8652 +815.61 +23144.3 +31.8456 +816.61 +22969.7 +31.826 +817.61 +23106.9 +31.8064 +818.61 +22979.1 +31.7869 +819.61 +22954.4 +31.7674 +820.61 +23272.2 +31.7479 +821.61 +22869.9 +31.7285 +822.61 +22656.1 +31.7091 +823.61 +23237.1 +31.6898 +824.61 +23494.1 +31.6704 +825.61 +22487.2 +31.6512 +826.61 +23008 +31.6319 +827.61 +22590.5 +31.6127 +828.61 +22804.9 +31.5935 +829.61 +23743.4 +31.5744 +830.61 +23271.9 +31.5553 +831.61 +23908.5 +31.5362 +832.61 +24016.9 +31.5172 +833.61 +23802 +31.4982 +834.61 +24074.2 +31.4792 +835.61 +23750.9 +31.4603 +836.61 +23729.7 +31.4414 +837.61 +23353.4 +31.4225 +838.61 +23673.5 +31.4037 +839.61 +23816.2 +31.3849 +840.61 +23586.7 +31.3661 +841.61 +23255 +31.3474 +842.61 +23785.1 +31.3287 +843.61 +24017.7 +31.31 +844.61 +23702.4 +31.2914 +845.61 +24006.4 +31.2728 +846.61 +23742.9 +31.2542 +847.61 +24131.1 +31.2357 +848.61 +24420.7 +31.2172 +849.61 +24073.6 +31.1987 +850.61 +23434.9 +31.1803 +851.61 +23902.9 +31.1619 +852.61 +24731.2 +31.1435 +853.61 +24888.2 +31.1252 +854.61 +24476.1 +31.1069 +855.61 +24263.5 +31.0886 +856.61 +23900.7 +31.0704 +857.61 +24634.5 +31.0522 +858.61 +24252.4 +31.034 +859.61 +25344.1 +31.0158 +860.61 +24700.1 +30.9977 +861.61 +24738.9 +30.9796 +862.61 +24833.9 +30.9616 +863.61 +24472.7 +30.9436 +864.61 +25037.1 +30.9256 +865.61 +24872.1 +30.9076 +866.61 +25410.3 +30.8897 +867.61 +25543.3 +30.8718 +868.61 +25483 +30.854 +869.61 +25342 +30.8361 +870.61 +25642.3 +30.8183 +871.61 +25455.6 +30.8006 +872.61 +25806.4 +30.7828 +873.61 +25269.6 +30.7651 +874.61 +26298.9 +30.7475 +875.61 +25984.2 +30.7298 +876.61 +26255.3 +30.7122 +877.61 +25798.5 +30.6946 +878.61 +25474.2 +30.6771 +879.61 +25671.2 +30.6595 +880.61 +26107.7 +30.642 +881.61 +26169 +30.6246 +882.61 +26033.8 +30.6071 +883.61 +25963.1 +30.5897 +884.61 +25735.6 +30.5724 +885.61 +26018 +30.555 +886.61 +26206.8 +30.5377 +887.61 +26436.4 +30.5204 +888.61 +26345.9 +30.5031 +889.61 +26485.8 +30.4859 +890.61 +26141.4 +30.4687 +891.61 +26645.3 +30.4515 +892.61 +26401.1 +30.4344 +893.61 +26494.7 +30.4173 +894.61 +26203.4 +30.4002 +895.61 +26841.3 +30.3832 +896.61 +27708.6 +30.3661 +897.61 +27401.7 +30.3491 +898.61 +27456.4 +30.3322 +899.61 +27491.5 +30.3152 +900.61 +26847.6 +30.2983 +901.61 +26983.5 +30.2814 +902.61 +26921 +30.2646 +903.61 +26357.8 +30.2477 +904.61 +26796.5 +30.2309 +905.61 +27575.9 +30.2142 +906.61 +27468.2 +30.1974 +907.61 +27363.7 +30.1807 +908.61 +27297.7 +30.164 +909.61 +27563.5 +30.1474 +910.61 +27779.7 +30.1307 +911.61 +27677.8 +30.1141 +912.61 +28141.3 +30.0975 +913.61 +28133.8 +30.081 +914.61 +28335.1 +30.0645 +915.61 +28446.5 +30.048 +916.61 +28001.8 +30.0315 +917.61 +28340.7 +30.0151 +918.61 +28912 +29.9986 +919.61 +29112.9 +29.9823 +920.61 +28637.3 +29.9659 +921.61 +27832.9 +29.9496 +922.61 +28025.4 +29.9333 +923.61 +28725.8 +29.917 +924.61 +28315.6 +29.9007 +925.61 +28760.2 +29.8845 +926.61 +28883.4 +29.8683 +927.61 +29056.2 +29.8521 +928.61 +30108.1 +29.836 +929.61 +30619.1 +29.8198 +930.61 +31800 +29.8037 +931.61 +33085.8 +29.7877 +932.61 +31594 +29.7716 +933.61 +31707.6 +29.7556 +934.61 +31263.6 +29.7396 +935.61 +29989.7 +29.7236 +936.61 +29151.5 +29.7077 +937.61 +29248.3 +29.6918 +938.61 +27126.8 +29.6759 +939.61 +27595.6 +29.66 +940.61 +26335.8 +29.6442 +941.61 +26011.1 +29.6284 +942.61 +26104.7 +29.6126 +943.61 +25259.5 +29.5968 +944.61 +24843.6 +29.5811 +945.61 +24253.4 +29.5654 +946.61 +24451.8 +29.5497 +947.61 +24533 +29.534 +948.61 +23436.6 +29.5184 +949.61 +24577 +29.5028 +950.61 +25820.3 +29.4872 +951.61 +28830.2 +29.4716 +952.61 +35099 +29.4561 +953.61 +49171.7 +29.4406 +954.61 +68714.3 +29.4251 +955.61 +79097.2 +29.4096 +956.61 +63369.1 +29.3942 +957.61 +36418.1 +29.3787 +958.61 +24477.6 +29.3633 +959.61 +21452.6 +29.348 +960.61 +21341.4 +29.3326 +961.61 +20550.5 +29.3173 +962.61 +20585.8 +29.302 +963.61 +21439.9 +29.2867 +964.61 +21296.6 +29.2715 +965.61 +21464.1 +29.2563 +966.61 +21243.4 +29.2411 +967.61 +21958.9 +29.2259 +968.61 +21651.9 +29.2107 +969.61 +21251.3 +29.1956 +970.61 +21762.7 +29.1805 +971.61 +21866.1 +29.1654 +972.61 +21384 +29.1503 +973.61 +21062.2 +29.1353 +974.61 +21850.7 +29.1203 +975.61 +21705.8 +29.1053 +976.61 +21608.4 +29.0903 +977.61 +21938.1 +29.0754 +978.61 +21455.8 +29.0605 +979.61 +21298 +29.0456 +980.61 +22211.5 +29.0307 +981.61 +22462.1 +29.0158 +982.61 +22093.8 +29.001 +983.61 +21722.9 +28.9862 +984.61 +21844 +28.9714 +985.61 +22113.1 +28.9567 +986.61 +22282.1 +28.9419 +987.61 +22340.2 +28.9272 +988.61 +21911.6 +28.9125 +989.61 +22846.7 +28.8978 +990.61 +22079.6 +28.8832 +991.61 +21749.2 +28.8686 +992.61 +22123 +28.8539 +993.61 +22648.3 +28.8394 +994.61 +22194.2 +28.8248 +995.61 +22296.6 +28.8103 +996.61 +22835.1 +28.7957 +997.61 +22514.9 +28.7812 +998.61 +22009.4 +28.7668 +999.61 +22251.5 +28.7523 +1000.61 +22409.7 +28.7379 +1001.61 +22631 +28.7235 +1002.61 +22113.2 +28.7091 +1003.61 +22370.1 +28.6947 +1004.61 +22395 +28.6804 +1005.61 +23215.4 +28.6661 +1006.61 +22945.3 +28.6518 +1007.61 +23343.9 +28.6375 +1008.61 +22369.9 +28.6232 +1009.61 +22478.9 +28.609 +1010.61 +22746 +28.5948 +1011.61 +22736.6 +28.5806 +1012.61 +22485.4 +28.5664 +1013.61 +23013.7 +28.5523 +1014.61 +23706.2 +28.5381 +1015.61 +23086.3 +28.524 +1016.61 +23017.2 +28.5099 +1017.61 +23209.4 +28.4959 +1018.61 +23451.7 +28.4818 +1019.61 +24166.6 +28.4678 +1020.61 +22915.4 +28.4538 +1021.61 +23518.9 +28.4398 +1022.61 +23553.3 +28.4258 +1023.61 +23027.4 +28.4119 +1024.61 +23705.6 +28.398 +1025.61 +23561.1 +28.3841 +1026.61 +22853.4 +28.3702 +1027.61 +23333 +28.3563 +1028.61 +23702.3 +28.3425 +1029.61 +23820.9 +28.3286 +1030.61 +24149.8 +28.3148 +1031.61 +24484.6 +28.3011 +1032.61 +24406 +28.2873 +1033.61 +23817.5 +28.2736 +1034.61 +23419.5 +28.2598 +1035.61 +23855.4 +28.2461 +1036.61 +24184.2 +28.2324 +1037.61 +24460.5 +28.2188 +1038.61 +24046.9 +28.2051 +1039.61 +24804 +28.1915 +1040.61 +24239 +28.1779 +1041.61 +24994.1 +28.1643 +1042.61 +24487.4 +28.1508 +1043.61 +24284.1 +28.1372 +1044.61 +24448.8 +28.1237 +1045.61 +24369.4 +28.1102 +1046.61 +24333.4 +28.0967 +1047.61 +24741.1 +28.0832 +1048.61 +24243.3 +28.0698 +1049.61 +24108.4 +28.0564 +1050.61 +23780.5 +28.043 +1051.61 +24408 +28.0296 +1052.61 +25272.2 +28.0162 +1053.61 +24374.8 +28.0029 +1054.61 +25479.8 +27.9895 +1055.61 +24948.2 +27.9762 +1056.61 +24863.8 +27.9629 +1057.61 +24953.7 +27.9496 +1058.61 +24860.1 +27.9364 +1059.61 +24829.9 +27.9232 +1060.61 +25815.3 +27.9099 +1061.61 +25317.1 +27.8967 +1062.61 +25869.6 +27.8836 +1063.61 +26374.9 +27.8704 +1064.61 +25671.9 +27.8572 +1065.61 +26598.3 +27.8441 +1066.61 +25424.2 +27.831 +1067.61 +26389.9 +27.8179 +1068.61 +25475.4 +27.8049 +1069.61 +25417.8 +27.7918 +1070.61 +25805.4 +27.7788 +1071.61 +25397.3 +27.7658 +1072.61 +25498.9 +27.7528 +1073.61 +25605.6 +27.7398 +1074.61 +26194.3 +27.7268 +1075.61 +26289.5 +27.7139 +1076.61 +27224.6 +27.701 +1077.61 +26943.4 +27.6881 +1078.61 +27404.8 +27.6752 +1079.61 +27351.3 +27.6623 +1080.61 +27300.4 +27.6495 +1081.61 +27027.1 +27.6366 +1082.61 +27231.4 +27.6238 +1083.61 +27314.4 +27.611 +1084.61 +27434.5 +27.5982 +1085.61 +27731.2 +27.5855 +1086.61 +27398.2 +27.5727 +1087.61 +27873 +27.56 +1088.61 +27358.1 +27.5473 +1089.61 +27763.4 +27.5346 +1090.61 +26819.7 +27.5219 +1091.61 +26918.7 +27.5093 +1092.61 +27615.9 +27.4966 +1093.61 +27665.8 +27.484 +1094.61 +27777 +27.4714 +1095.61 +28002.4 +27.4588 +1096.61 +28241 +27.4462 +1097.61 +27928.4 +27.4337 +1098.61 +28587 +27.4212 +1099.61 +29583.7 +27.4086 +1100.61 +31229.1 +27.3961 +1101.61 +33027.1 +27.3836 +1102.61 +32668.5 +27.3712 +1103.61 +31457.8 +27.3587 +1104.61 +29731.6 +27.3463 +1105.61 +29033.5 +27.3339 +1106.61 +28839.9 +27.3215 +1107.61 +29130.9 +27.3091 +1108.61 +29390.3 +27.2967 +1109.61 +28414.1 +27.2844 +1110.61 +28991.1 +27.2721 +1111.61 +29419.4 +27.2597 +1112.61 +30099.2 +27.2474 +1113.61 +29966.2 +27.2352 +1114.61 +29322.1 +27.2229 +1115.61 +28557.8 +27.2106 +1116.61 +28303.2 +27.1984 +1117.61 +28100.4 +27.1862 +1118.61 +28284.8 +27.174 +1119.61 +28291.9 +27.1618 +1120.61 +28384.8 +27.1497 +1121.61 +28811.5 +27.1375 +1122.61 +28849.7 +27.1254 +1123.61 +28415.1 +27.1132 +1124.61 +27943.8 +27.1011 +1125.61 +28015.3 +27.0891 +1126.61 +28593.2 +27.077 +1127.61 +28486 +27.0649 +1128.61 +28903.2 +27.0529 +1129.61 +28669.5 +27.0409 +1130.61 +29885.3 +27.0289 +1131.61 +30651.9 +27.0169 +1132.61 +33538 +27.0049 +1133.61 +40620.5 +26.993 +1134.61 +46163.1 +26.981 +1135.61 +48538.9 +26.9691 +1136.61 +44908.7 +26.9572 +1137.61 +37659.1 +26.9453 +1138.61 +33003.1 +26.9334 +1139.61 +29700.4 +26.9215 +1140.61 +27945.5 +26.9097 +1141.61 +27027.7 +26.8979 +1142.61 +27870.6 +26.8861 +1143.61 +27738.2 +26.8743 +1144.61 +27647.1 +26.8625 +1145.61 +27768.2 +26.8507 +1146.61 +28494 +26.8389 +1147.61 +30488.6 +26.8272 +1148.61 +32851 +26.8155 +1149.61 +35017.6 +26.8038 +1150.61 +33298.9 +26.7921 +1151.61 +30498.9 +26.7804 +1152.61 +29861.1 +26.7688 +1153.61 +29681.1 +26.7571 +1154.61 +31073.1 +26.7455 +1155.61 +31084 +26.7339 +1156.61 +31298.8 +26.7223 +1157.61 +31979.5 +26.7107 +1158.61 +32527.9 +26.6991 +1159.61 +31531.3 +26.6875 +1160.61 +29697.4 +26.676 +1161.61 +29036.1 +26.6645 +1162.61 +28067.9 +26.653 +1163.61 +26307.4 +26.6415 +1164.61 +25255.5 +26.63 +1165.61 +24475.3 +26.6185 +1166.61 +24957.3 +26.6071 +1167.61 +24392.6 +26.5956 +1168.61 +23205.6 +26.5842 +1169.61 +22703.9 +26.5728 +1170.61 +21890 +26.5614 +1171.61 +21464 +26.55 +1172.61 +21459.7 +26.5387 +1173.61 +24813 +26.5273 +1174.61 +29234.9 +26.516 +1175.61 +33361.8 +26.5047 +1176.61 +34971 +26.4934 +1177.61 +38778.9 +26.4821 +1178.61 +56391.1 +26.4708 +1179.61 +85066.3 +26.4595 +1180.61 +108366 +26.4483 +1181.61 +96061 +26.4371 +1182.61 +57359.8 +26.4258 +1183.61 +29576.8 +26.4146 +1184.61 +18228.3 +26.4034 +1185.61 +13167.2 +26.3923 +1186.61 +10857.9 +26.3811 +1187.61 +9705 +26.37 +1188.61 +9261.49 +26.3588 +1189.61 +8851.94 +26.3477 +1190.61 +8621 +26.3366 +1191.61 +7997.02 +26.3255 +1192.61 +8076.53 +26.3144 +1193.61 +7905.56 +26.3034 +1194.61 +8018.22 +26.2923 +1195.61 +8412.77 +26.2813 +1196.61 +8531.77 +26.2703 +1197.61 +9108.74 +26.2593 +1198.61 +10421.1 +26.2483 +1199.61 +12445.3 +26.2373 +1200.61 +15800.5 +26.2263 +1201.61 +14773.9 +26.2154 +1202.61 +10951.6 +26.2044 +1203.61 +8846.79 +26.1935 +1204.61 +8143.72 +26.1826 +1205.61 +7917.12 +26.1717 +1206.61 +7438.45 +26.1608 +1207.61 +7530.34 +26.1499 +1208.61 +7350.1 +26.1391 +1209.61 +7004.11 +26.1282 +1210.61 +7168.32 +26.1174 +1211.61 +7166.58 +26.1066 +1212.61 +7154.84 +26.0958 +1213.61 +7215.96 +26.085 +1214.61 +7476.36 +26.0742 +1215.61 +7102.79 +26.0635 +1216.61 +6973.13 +26.0527 +1217.61 +7001.84 +26.042 +1218.61 +7195.88 +26.0312 +1219.61 +7598.77 +26.0205 +1220.61 +7606.59 +26.0098 +1221.61 +7744.39 +25.9991 +1222.61 +7207.57 +25.9885 +1223.61 +7521.6 +25.9778 +1224.61 +7409.5 +25.9672 +1225.61 +7447.67 +25.9565 +1226.61 +7288.99 +25.9459 +1227.61 +7075.86 +25.9353 +1228.61 +6979.76 +25.9247 +1229.61 +6882.51 +25.9142 +1230.61 +7137.34 +25.9036 +1231.61 +6877.87 +25.893 +1232.61 +6508.49 +25.8825 +1233.61 +7056.12 +25.872 +1234.61 +7229.9 +25.8614 +1235.61 +7197.57 +25.8509 +1236.61 +6896.92 +25.8405 +1237.61 +6680.31 +25.83 +1238.61 +6904.96 +25.8195 +1239.61 +7820.09 +25.8091 +1240.61 +7853.14 +25.7986 +1241.61 +8852.12 +25.7882 +1242.61 +9221.77 +25.7778 +1243.61 +9035.21 +25.7674 +1244.61 +8808.02 +25.757 +1245.61 +7796.19 +25.7466 +1246.61 +7510.4 +25.7363 +1247.61 +7078.66 +25.7259 +1248.61 +7047.54 +25.7156 +1249.61 +6450.32 +25.7052 +1250.61 +6911.09 +25.6949 +1251.61 +7161.91 +25.6846 +1252.61 +6939.09 +25.6743 +1253.61 +6644.48 +25.6641 +1254.61 +6939.13 +25.6538 +1255.61 +7016.25 +25.6436 +1256.61 +6554.99 +25.6333 +1257.61 +6544.45 +25.6231 +1258.61 +6745.67 +25.6129 +1259.61 +6625.13 +25.6027 +1260.61 +6850.18 +25.5925 +1261.61 +6539.53 +25.5823 +1262.61 +6533.73 +25.5721 +1263.61 +6585.06 +25.562 +1264.61 +6827.85 +25.5518 +1265.61 +6627.73 +25.5417 +1266.61 +6388.73 +25.5316 +1267.61 +6685.38 +25.5215 +1268.61 +6876.57 +25.5114 +1269.61 +6664.19 +25.5013 +1270.61 +6384.56 +25.4912 +1271.61 +6587.83 +25.4812 +1272.61 +6921.75 +25.4711 +1273.61 +6788.45 +25.4611 +1274.61 +6671.56 +25.4511 +1275.61 +6818.97 +25.4411 +1276.61 +6593.74 +25.4311 +1277.61 +6468.86 +25.4211 +1278.61 +6753.37 +25.4111 +1279.61 +6905.99 +25.4012 +1280.61 +6776.49 +25.3912 +1281.61 +6501.13 +25.3813 +1282.61 +6476.28 +25.3713 +1283.61 +6459.77 +25.3614 +1284.61 +6564.56 +25.3515 +1285.61 +6959.95 +25.3416 +1286.61 +7099.87 +25.3317 +1287.61 +6935.65 +25.3219 +1288.61 +6773.59 +25.312 +1289.61 +6698.94 +25.3022 +1290.61 +6996.49 +25.2923 +1291.61 +6665.35 +25.2825 +1292.61 +6759.45 +25.2727 +1293.61 +6654.49 +25.2629 +1294.61 +6938.87 +25.2531 +1295.61 +7175.18 +25.2433 +1296.61 +7406.9 +25.2336 +1297.61 +7122.63 +25.2238 +1298.61 +7084.91 +25.2141 +1299.61 +7047.75 +25.2043 +1300.61 +6978.56 +25.1946 +1301.61 +7018.51 +25.1849 +1302.61 +6981.53 +25.1752 +1303.61 +7062.36 +25.1655 +1304.61 +6609.17 +25.1558 +1305.61 +6433.83 +25.1462 +1306.61 +6681.74 +25.1365 +1307.61 +6731.39 +25.1269 +1308.61 +7064.39 +25.1172 +1309.61 +7434.37 +25.1076 +1310.61 +7356.02 +25.098 +1311.61 +7006.26 +25.0884 +1312.61 +6809.74 +25.0788 +1313.61 +7031.62 +25.0692 +1314.61 +7085.84 +25.0597 +1315.61 +6996.02 +25.0501 +1316.61 +7278.02 +25.0406 +1317.61 +7343.13 +25.031 +1318.61 +7148.41 +25.0215 +1319.61 +6918.55 +25.012 +1320.61 +7248.71 +25.0025 +1321.61 +7065.72 +24.993 +1322.61 +7317.03 +24.9835 +1323.61 +7348.06 +24.974 +1324.61 +7527.43 +24.9646 +1325.61 +7315.65 +24.9551 +1326.61 +7342.31 +24.9457 +1327.61 +7125.93 +24.9363 +1328.61 +7173.94 +24.9269 +1329.61 +7415.9 +24.9175 +1330.61 +7458.17 +24.9081 +1331.61 +8097.92 +24.8987 +1332.61 +7987.09 +24.8893 +1333.61 +8409.66 +24.8799 +1334.61 +7592.8 +24.8706 +1335.61 +6897.75 +24.8613 +1336.61 +6919.45 +24.8519 +1337.61 +7272.17 +24.8426 +1338.61 +7556.84 +24.8333 +1339.61 +7399.61 +24.824 +1340.61 +7664.4 +24.8147 +1341.61 +7256.48 +24.8054 +1342.61 +7236.88 +24.7962 +1343.61 +7358.4 +24.7869 +1344.61 +7196.38 +24.7777 +1345.61 +7089.13 +24.7684 +1346.61 +7258.17 +24.7592 +1347.61 +6952.56 +24.75 +1348.61 +7021.68 +24.7408 +1349.61 +6946.62 +24.7316 +1350.61 +7388.86 +24.7224 +1351.61 +7362.27 +24.7132 +1352.61 +7439.42 +24.7041 +1353.61 +7214.55 +24.6949 +1354.61 +7455.32 +24.6858 +1355.61 +7503.44 +24.6766 +1356.61 +7381.52 +24.6675 +1357.61 +7643.07 +24.6584 +1358.61 +7843.43 +24.6493 +1359.61 +7326.64 +24.6402 +1360.61 +7081.89 +24.6311 +1361.61 +7480.1 +24.622 +1362.61 +7717.26 +24.613 +1363.61 +7436.54 +24.6039 +1364.61 +8025.87 +24.5949 +1365.61 +7322.73 +24.5858 +1366.61 +7533.07 +24.5768 +1367.61 +7777.59 +24.5678 +1368.61 +7947.37 +24.5588 +1369.61 +7272.13 +24.5498 +1370.61 +7348.91 +24.5408 +1371.61 +7466.85 +24.5318 +1372.61 +8101.13 +24.5229 +1373.61 +7983.67 +24.5139 +1374.61 +7817.58 +24.505 +1375.61 +7454.57 +24.496 +1376.61 +7968.85 +24.4871 +1377.61 +7726.62 +24.4782 +1378.61 +7522.97 +24.4693 +1379.61 +7789.57 +24.4604 +1380.61 +8046.77 +24.4515 +1381.61 +7913.35 +24.4426 +1382.61 +8388.46 +24.4338 +1383.61 +8558.92 +24.4249 +1384.61 +8345.14 +24.4161 +1385.61 +8251.82 +24.4072 +1386.61 +7920.76 +24.3984 +1387.61 +7657.02 +24.3896 +1388.61 +7314 +24.3808 +1389.61 +7931.43 +24.372 +1390.61 +8071.3 +24.3632 +1391.61 +8479.99 +24.3544 +1392.61 +8346.96 +24.3456 +1393.61 +8299.28 +24.3369 +1394.61 +9574.41 +24.3281 +1395.61 +12283.9 +24.3194 +1396.61 +16114.2 +24.3106 +1397.61 +17100.1 +24.3019 +1398.61 +12203.4 +24.2932 +1399.61 +7752.57 +24.2845 +1400.61 +6576.5 +24.2758 +1401.61 +5892.75 +24.2671 +1402.61 +5555.74 +24.2584 +1403.61 +5401.44 +24.2497 +1404.61 +5352.02 +24.2411 +1405.61 +5615.54 +24.2324 +1406.61 +5929.02 +24.2238 +1407.61 +5673.68 +24.2152 +1408.61 +5587.15 +24.2065 +1409.61 +5937.77 +24.1979 +1410.61 +6026.23 +24.1893 +1411.61 +5858.21 +24.1807 +1412.61 +5691.5 +24.1721 +1413.61 +6144.27 +24.1636 +1414.61 +5691.33 +24.155 +1415.61 +5417.48 +24.1464 +1416.61 +5273.52 +24.1379 +1417.61 +5402.8 +24.1294 +1418.61 +5369.09 +24.1208 +1419.61 +5317.37 +24.1123 +1420.61 +4896.02 +24.1038 +1421.61 +5053.24 +24.0953 +1422.61 +5104.39 +24.0868 +1423.61 +4693.3 +24.0783 +1424.61 +4767.42 +24.0698 +1425.61 +5109.4 +24.0614 +1426.61 +5151.5 +24.0529 +1427.61 +6156.71 +24.0445 +1428.61 +7594.27 +24.036 +1429.61 +8023.59 +24.0276 +1430.61 +8726.65 +24.0192 +1431.61 +7998.13 +24.0107 +1432.61 +6550.19 +24.0023 +1433.61 +5520.74 +23.9939 +1434.61 +6662.62 +23.9856 +1435.61 +9485.4 +23.9772 +1436.61 +9251.54 +23.9688 +1437.61 +4883.65 +23.9604 +1438.61 +2204.89 +23.9521 +1439.61 +1745.42 +23.9437 +1440.61 +1624.44 +23.9354 +1441.61 +1620 +23.9271 +1442.61 +1529.31 +23.9188 +1443.61 +1433.28 +23.9105 +1444.61 +1445.69 +23.9022 +1445.61 +1488.45 +23.8939 +1446.61 +1410.25 +23.8856 +1447.61 +1221.92 +23.8773 +1448.61 +1261.24 +23.869 +1449.61 +1268.15 +23.8608 +1450.61 +1078.27 +23.8525 +1451.61 +1141.64 +23.8443 +1452.61 +1166.53 +23.8361 +1453.61 +1195.57 +23.8278 +1454.61 +1373.64 +23.8196 +1455.61 +1495.81 +23.8114 +1456.61 +1309.29 +23.8032 +1457.61 +1645.28 +23.795 +1458.61 +1806.56 +23.7868 +1459.61 +2077.56 +23.7787 +1460.61 +2390.18 +23.7705 +1461.61 +2829.17 +23.7624 +1462.61 +3145.28 +23.7542 +1463.61 +3378.66 +23.7461 +1464.61 +3374.69 +23.7379 +1465.61 +2433.87 +23.7298 +1466.61 +1654.42 +23.7217 +1467.61 +1169.62 +23.7136 +1468.61 +1052.64 +23.7055 +1469.61 +822.528 +23.6974 +1470.61 +759.785 +23.6893 +1471.61 +762.064 +23.6813 +1472.61 +834.402 +23.6732 +1473.61 +839.909 +23.6651 +1474.61 +889.014 +23.6571 +1475.61 +1201.44 +23.649 +1476.61 +1327.82 +23.641 +1477.61 +1638.34 +23.633 +1478.61 +1912.91 +23.625 +1479.61 +1713.02 +23.617 +1480.61 +1821.52 +23.609 +1481.61 +1751.19 +23.601 +1482.61 +1321.72 +23.593 +1483.61 +1181.31 +23.585 +1484.61 +749.546 +23.5771 +1485.61 +520.199 +23.5691 +1486.61 +181.529 +23.5611 +end of experiment diff --git a/tests/data/vms_regular/eln_data.yaml b/tests/data/vms_regular/eln_data.yaml new file mode 100644 index 00000000..54475cbb --- /dev/null +++ b/tests/data/vms_regular/eln_data.yaml @@ -0,0 +1,147 @@ +definition: + value: NXmpes + version: 1.0 +title: XPS Experiment +start_time: 2022-04-08T11:47:02.0200Z +end_time: 2022-04-08T12:32:06.0200Z +experiment_institution: BESSY II +program_name: SpecsLab 2 +user: + name: Lukas Pielsticker + email: lukas.pielsticker@cec.mpg.de +instrument: + device_information: + vendor: SPECS GmbH + model: XPS setup + identifier: null + energy_resolution: + type: calibrated + resolution: + value: 0.2 + unit: eV + source_probe: + type: Synchrotron X-ray Source + probe: x-ray + device_information: + vendor: null + model: null + identifier: null + beam_probe: + distance: + value: 0.0 + unit: mm + analyser: + description: hemispherical + name: PHOIBOS 150 + device_information: + vendor: SPECS GmbH + model: PHOIBOS 150 + identifier: null + collectioncolumn: + scheme: angular dispersive + device_information: + vendor: null + model: null + identifier: null + energydispersion: + scheme: hemispherical + entrance_slit: unknown + energy_scan_mode: fixed_analyser_transmission + diameter: + unit: mm + value: 150 + device_information: + vendor: null + model: null + identifier: null + detector: + amplifier_type: channeltron + detector_type: Multi-anode + manipulator: + device_information: + vendor: SPECS GmbH + model: 5-axis manipulator + identifier: null + temperature_sensor: + name: type K thermocouple + measurement: temperature + attached_to: sample + type: type K thermocouple + value: + value: 298.0 + unit: K + sample_heater: + name: Coherent Compact Evolution IR Diode LASER (DILAS) + physical_quantity: temperature + type: IR diode laser + heater_power: + value: 0.0 + unit: W + pid: + setpoint: + value: 298.0 + unit: K + cryostat: + name: null + physical_quantity: null + type: null + pid: + setpoint: null + drain_current_amperemeter: + name: Amperemeter 1.0 + measurement: current + type: wire + value: + value: 0.0 + unit: A + sample_bias_voltmeter: + name: XPS sample voltmeter + measurement: voltage + attached_to: sample + type: oscilloscope + value: + value: 0.0 + unit: V + sample_bias_potentiostat: + name: XPS sample potentiostat + physical_quantity: voltage + type: potentiostat + pid: + setpoint: + value: 0.0 + unit: V + pressure_gauge: + name: Atmion + measurement: pressure + type: hot-filament ionization gauge + value: + value: 0.000000001 + unit: mbar + value_log: + value: + value: null + unit: null + flood_gun: + name: FG 22/35 + physical_quantity: current + type: low energy electron source + current: + value: 0.0 + unit: A + current_log: + value: + value: null + unit: null +sample: + description: A polymer material called PBTTT with chemical name poly[2,5-bis(3-dodecylthiophen-2-yl)thieno[3,2-b]thiophene]. + name: Test + substance: + molecular_formula_hill: (C42H62S4)n + situation: vacuum + sample_history: + sample_preparation: + start_time: 2022-04-08T11:02:38.0200Z + end_time: 2022-04-08T11:06:42.200Z + description: From third party + method: null + \ No newline at end of file diff --git a/tests/data/vms/regular.vms b/tests/data/vms_regular/regular.vms similarity index 100% rename from tests/data/vms/regular.vms rename to tests/data/vms_regular/regular.vms From acf658137e148a329ac8c065112d649a4a99170d Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 15 Mar 2024 09:29:18 +0100 Subject: [PATCH 18/41] reset test_reader --- tests/test_reader.py | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/tests/test_reader.py b/tests/test_reader.py index 73180692..237a238e 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -13,20 +13,6 @@ from pynxtools.nexus.nxdl_utils import get_nexus_definitions_path from pynxtools_xps.reader import XPSReader -# from pynxtools_xps.phi.spe_pro_phi import MapperPhi -from pynxtools_xps.sle.sle_specs import SleMapperSpecs - -# from pynxtools_xps.slh.slh_specs import SlhMapperSpecs -from pynxtools_xps.txt.txt_scienta import TxtMapperScienta - -# from pynxtools_xps.txt.txt_specs import TxtMapperSpecs -from pynxtools_xps.txt.txt_vamas_export import ( - TxtMapperVamasExport, -) -from pynxtools_xps.vms.vamas import VamasMapper -from pynxtools_xps.xy.xy_specs import XyMapperSpecs -from pynxtools_xps.xml.xml_specs import XmlMapperSpecs - def test_example_data(): """ @@ -41,7 +27,7 @@ def test_example_data(): reader_dirs = sorted(glob(os.path.join(data_dir, "*"))) - for reader_dir in reader_dirs[:1]: + for reader_dir in reader_dirs: input_files = sorted(glob(os.path.join(reader_dir, "*"))) for supported_nxdl in reader.supported_nxdls: @@ -58,14 +44,10 @@ def test_example_data(): ) assert isinstance(read_data, Template) - # validate_data_dict(template, read_data, root) - # assert validate_data_dict(template, read_data, root) - - return read_data.get_accumulated_dict() - + assert validate_data_dict(template, read_data, root) -data = test_example_data() +## This will be implemented in the future. # ============================================================================= # def test_vms_mapper(): # mapper = VamasMapper From 3ac7f2a022772288ab74b8ecc1283761e2c92b73 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 15 Mar 2024 10:20:37 +0100 Subject: [PATCH 19/41] make units top-level constant --- pynxtools_xps/vms/vamas.py | 47 +++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index 9a86439e..b9dfcb63 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -42,6 +42,26 @@ get_minimal_step, ) +UNITS: dict = { + "instrument/sample_normal_polarangle_tilt": "degree ", + "instrument/sample_tilt_azimuth": "degree", + "instrument/sample_rotation_angle": "degree", + "source/source_analyzer_angle": "degree", + "source/excitation_energy": "eV", + "source/particle_charge": "C", + "analyser/analyzer_take_off_azimuth": "degree", + "analyser/analyzer_take_off_polar": "degree", + "analyser/analysis_width_x": "m", + "analyser/analysis_width_y": "m", + "analyser/target_bias": "V", + "analyser/time_correction": "s", + "analyser/work_function": "eV", + "energydispersion/pass_energy": "eV", + "detector/dwell_time": "s", + "data/start_energy": "eV", + "data/step_size": "eV", +} + class VamasMapper(XPSMapper): """ @@ -51,31 +71,6 @@ class VamasMapper(XPSMapper): config_file = "config_vms.json" - def __init__(self): - self.parsers: List[Any] = [] - - self.units: dict = { - "instrument/sample_normal_polarangle_tilt": "degree ", - "instrument/sample_tilt_azimuth": "degree", - "instrument/sample_rotation_angle": "degree", - "source/source_analyzer_angle": "degree", - "source/excitation_energy": "eV", - "source/particle_charge": "C", - "analyser/analyzer_take_off_azimuth": "degree", - "analyser/analyzer_take_off_polar": "degree", - "analyser/analysis_width_x": "m", - "analyser/analysis_width_y": "m", - "analyser/target_bias": "V", - "analyser/time_correction": "s", - "analyser/work_function": "eV", - "energydispersion/pass_energy": "eV", - "detector/dwell_time": "s", - "data/start_energy": "eV", - "data/step_size": "eV", - } - - super().__init__() - def _select_parser(self): """ Select parser based on the structure of the Vamas file, @@ -288,7 +283,7 @@ def _get_units_for_key(self, unit_key: str): return re.search(r"\[([A-Za-z0-9_]+)\]", unit_key).group(1) except AttributeError: try: - return self.units[unit_key] + return UNITS[unit_key] except KeyError: return "" From 9f28b4c86a2f099c02758f011b350f0d149b0831 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Tue, 20 Feb 2024 10:18:34 +0100 Subject: [PATCH 20/41] add writing of CPS data to vms reader --- pynxtools_xps/vms/vamas.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index 4957f913..e5ef1f6b 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -187,7 +187,8 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): detector_data_key = f'{path_map["detector"]}/{detector_data_key_child}/counts' energy = np.array(spectrum["data"]["x"]) - intensity = np.array(spectrum["data"]["y"]) + intensity_raw = np.array(spectrum["data"]["y"]) + intensity_cps = np.array(spectrum["data"]["y_cps"]) if entry not in self._xps_dict["data"]: self._xps_dict["data"][entry] = xr.Dataset() @@ -203,7 +204,7 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): averaged_scans = np.mean(all_scan_data, axis=0) if averaged_scans.size == 1: # on first scan in cycle - averaged_scans = intensity + averaged_scans = intensity_cps try: self._xps_dict["data"][entry][scan_key.split("_")[0]] = xr.DataArray( @@ -213,13 +214,12 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): except ValueError: pass - # Write scan data to 'data'. self._xps_dict["data"][entry][scan_key] = xr.DataArray( - data=intensity, coords={"energy": energy} + data=intensity_cps, coords={"energy": energy} ) # Write raw intensities to 'detector'. - self._xps_dict[detector_data_key] = intensity + self._xps_dict[detector_data_key] = intensity_raw class VamasParser(ABC): @@ -603,9 +603,16 @@ def build_list(self): for var in range(int(block.no_variables)): if var == 0: key = "y" + + data["y"] = getattr(block, "y") + + if block.variable_label_1 == "Intensity": + y_cps = [np.round(y / block.dwell_time, 2) for y in block.y] + data["y_cps"] = y_cps + else: key = "y" + str(var) - data[key] = getattr(block, key) + data[key] = getattr(block, key) spec_dict = { "time_stamp": date_time, From 9c13c4c1eac522d265aebe6390dd94ef52810f81 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:38:48 +0100 Subject: [PATCH 21/41] make vms comments a list --- pynxtools_xps/vms/vamas.py | 12 ++++++------ pynxtools_xps/vms/vamas_data_model.py | 8 +++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index e5ef1f6b..ec3fab5f 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -435,9 +435,9 @@ def _parse_header(self): for attr in self.attrs["common_header"]: setattr(self.header, attr, self.data.pop(0).strip()) no_comment_lines = int(self.header.no_comment_lines) - comments = "" + comments = [] for _ in range(no_comment_lines): - comments += self.data.pop(0) + comments += [self.data.pop(0)] self.header.comment_lines = comments self.header.exp_mode = self.data.pop(0).strip() if self.header.exp_mode == "NORM": @@ -657,7 +657,7 @@ def _parse_norm_block(self): block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) block.no_comment_lines = int(self.data.pop(0).strip()) for _ in range(block.no_comment_lines): - block.comment_lines += self.data.pop(0) + block.comment_lines += [self.data.pop(0)] block.technique = self.data.pop(0).strip() for _ in range(int(self.header.nr_exp_var)): block.exp_var_value = self.data.pop(0).strip() @@ -739,7 +739,7 @@ def _parse_map_block(self): block.no_comment_lines = int(self.data.pop(0).strip()) for _ in range(block.no_comment_lines): self.data.pop(0) - block.comment_lines += self.data.pop(0) + block.comment_lines += [self.data.pop(0)] block.technique = self.data.pop(0).strip() block.x_coord = self.data.pop(0).strip() block.y_coord = self.data.pop(0).strip() @@ -863,7 +863,7 @@ def _parse_norm_block(self): block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) block.no_comment_lines = int(self.data.pop(0).strip()) for _ in range(block.no_comment_lines): - block.comment_lines += self.data.pop(0) + block.comment_lines += [self.data.pop(0)] block.technique = self.data.pop(0).strip() for _ in range(int(self.header.nr_exp_var)): block.exp_var_value = self.data.pop(0).strip() @@ -945,7 +945,7 @@ def _parse_map_block(self): block.no_comment_lines = int(self.data.pop(0).strip()) for _ in range(block.no_comment_lines): self.data.pop(0) - block.comment_lines += self.data.pop(0) + block.comment_lines += [self.data.pop(0)] block.technique = self.data.pop(0).strip() block.x_coord = self.data.pop(0).strip() block.y_coord = self.data.pop(0).strip() diff --git a/pynxtools_xps/vms/vamas_data_model.py b/pynxtools_xps/vms/vamas_data_model.py index 878445d5..a94b811e 100644 --- a/pynxtools_xps/vms/vamas_data_model.py +++ b/pynxtools_xps/vms/vamas_data_model.py @@ -19,7 +19,7 @@ # # pylint: disable=too-many-instance-attributes -from dataclasses import dataclass +from dataclasses import dataclass, field @dataclass @@ -34,7 +34,9 @@ class VamasHeader: operator_id: str = "Not Specified" experiment_id: str = "Not Specified" no_comment_lines: str = "2" - comment_lines: str = "Casa Info Follows CasaXPS Version 2.3.22PR1.0\n0" + comment_lines: list = field( + default_factory=["Casa Info Follows CasaXPS Version 2.3.22PR1.0\n0"] + ) exp_mode: str = "NORM" scan_mode: str = "REGULAR" nr_regions: str = "0" @@ -64,7 +66,7 @@ class VamasBlock: no_comment_lines: str = "" # This list should contain one element per for each # line in the comment block - comment_lines: str = "" + comment_lines: list = field(default_factory=list) technique: str = "" exp_var_value: str = "" source_label: str = "" From 73376157bca31d429cdd7b3f58bba99b29e48a41 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:39:51 +0100 Subject: [PATCH 22/41] change default value of casa comments --- pynxtools_xps/vms/vamas_data_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pynxtools_xps/vms/vamas_data_model.py b/pynxtools_xps/vms/vamas_data_model.py index a94b811e..35797b70 100644 --- a/pynxtools_xps/vms/vamas_data_model.py +++ b/pynxtools_xps/vms/vamas_data_model.py @@ -35,8 +35,8 @@ class VamasHeader: experiment_id: str = "Not Specified" no_comment_lines: str = "2" comment_lines: list = field( - default_factory=["Casa Info Follows CasaXPS Version 2.3.22PR1.0\n0"] - ) + default_factory=list + ) # ["Casa Info Follows CasaXPS Version 2.3.22PR1.0\n0"] exp_mode: str = "NORM" scan_mode: str = "REGULAR" nr_regions: str = "0" From 4066cd6f62b2bd14491462092bd8ae57914a73dc Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:50:16 +0100 Subject: [PATCH 23/41] change notation in mapper output --- pynxtools_xps/sle/sle_specs.py | 4 ++-- pynxtools_xps/txt/txt_scienta.py | 4 ++-- pynxtools_xps/txt/txt_vamas_export.py | 4 ++-- pynxtools_xps/xy/xy_specs.py | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pynxtools_xps/sle/sle_specs.py b/pynxtools_xps/sle/sle_specs.py index 90a09951..a57a3660 100644 --- a/pynxtools_xps/sle/sle_specs.py +++ b/pynxtools_xps/sle/sle_specs.py @@ -198,8 +198,8 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): """ # pylint: disable=too-many-locals,duplicate-code - group_parent = f'{self._root_path}/RegionGroup_{spectrum["group_name"]}' - region_parent = f'{group_parent}/regions/RegionData_{spectrum["spectrum_type"]}' + group_parent = f'{self._root_path}/Group_{spectrum["group_name"]}' + region_parent = f'{group_parent}/regions/Region_{spectrum["spectrum_type"]}' instrument_parent = f"{region_parent}/instrument" analyser_parent = f"{instrument_parent}/analyser" diff --git a/pynxtools_xps/txt/txt_scienta.py b/pynxtools_xps/txt/txt_scienta.py index 4b456986..09307cbe 100644 --- a/pynxtools_xps/txt/txt_scienta.py +++ b/pynxtools_xps/txt/txt_scienta.py @@ -130,8 +130,8 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): """ # pylint: disable=too-many-locals,duplicate-code - group_parent = f'{self._root_path}/RegionGroup_{spectrum["spectrum_type"]}' - region_parent = f'{group_parent}/regions/RegionData_{spectrum["region_name"]}' + group_parent = f'{self._root_path}/Region_{spectrum["spectrum_type"]}' + region_parent = f'{group_parent}/regions/Region_{spectrum["region_name"]}' file_parent = f"{region_parent}/file_info" instrument_parent = f"{region_parent}/instrument" analyser_parent = f"{instrument_parent}/analyser" diff --git a/pynxtools_xps/txt/txt_vamas_export.py b/pynxtools_xps/txt/txt_vamas_export.py index 4923e266..87a2c3b5 100644 --- a/pynxtools_xps/txt/txt_vamas_export.py +++ b/pynxtools_xps/txt/txt_vamas_export.py @@ -130,8 +130,8 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): """ # pylint: disable=too-many-locals,duplicate-code - group_parent = f'{self._root_path}/RegionGroup_{spectrum["group_name"]}' - region_parent = f'{group_parent}/regions/RegionData_{spectrum["spectrum_type"]}' + group_parent = f'{self._root_path}/Group_{spectrum["group_name"]}' + region_parent = f'{group_parent}/regions/Region_{spectrum["spectrum_type"]}' file_parent = f"{region_parent}/file_info" instrument_parent = f"{region_parent}/instrument" analyser_parent = f"{instrument_parent}/analyser" diff --git a/pynxtools_xps/xy/xy_specs.py b/pynxtools_xps/xy/xy_specs.py index 47f12c70..e327860d 100644 --- a/pynxtools_xps/xy/xy_specs.py +++ b/pynxtools_xps/xy/xy_specs.py @@ -138,8 +138,8 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): """ # pylint: disable=too-many-locals,duplicate-code - group_parent = f'{self._root_path}/RegionGroup_{spectrum["group_name"]}' - region_parent = f'{group_parent}/regions/RegionData_{spectrum["region_name"]}' + group_parent = f'{self._root_path}/Group_{spectrum["group_name"]}' + region_parent = f'{group_parent}/regions/Region_{spectrum["region_name"]}' file_parent = f"{region_parent}/file_info" instrument_parent = f"{region_parent}/instrument" analyser_parent = f"{instrument_parent}/analyser" From 99b8182e1a885fba64e1a2c9e3a26a51a79de562 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:51:52 +0100 Subject: [PATCH 24/41] use XPS dataclass template --- pynxtools_xps/reader_utils.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/pynxtools_xps/reader_utils.py b/pynxtools_xps/reader_utils.py index 2b342695..86cec378 100644 --- a/pynxtools_xps/reader_utils.py +++ b/pynxtools_xps/reader_utils.py @@ -21,6 +21,29 @@ from scipy.interpolate import interp1d import numpy as np +from dataclasses import dataclass + + +@dataclass +class XpsDataclass: + """Generic class to hold a data model and a type validation method.""" + + def validate_types(self): + ret = True + for field_name, field_def in self.__dataclass_fields__.items(): + actual_type = type(getattr(self, field_name)) + if actual_type != field_def.type: + print(f"\t{field_name}: '{actual_type}' instead of '{field_def.type}'") + ret = False + return ret + + def __post_init__(self): + if not self.validate_types(): + raise ValueError("Wrong types") + + def dict(self): + return self.__dict__.copy() + class XPSMapper(ABC): """Abstract base class from mapping from a parser to NXmpes template""" @@ -77,6 +100,11 @@ def construct_data(self): """ +def to_snake_case(string_with_whitespace): + """Convert a string to snake_case.""" + return "_".join(word.lower() for word in string_with_whitespace.split()) + + def safe_arange_with_edges(start, stop, step): """ In order to avoid float point errors in the division by step. @@ -102,7 +130,7 @@ def safe_arange_with_edges(start, stop, step): def check_uniform_step_width(lst): """ - Check to see if a non-uniform step width is used in an lst + Check to see if a non-uniform step width is used in an list. Parameters ---------- From 8cc91542bb8a4369989b1070d970fa3b85849993 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:38:19 +0100 Subject: [PATCH 25/41] add data model for CasaXPS peak fitting --- pynxtools_xps/vms/casa_data_model.py | 299 +++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 pynxtools_xps/vms/casa_data_model.py diff --git a/pynxtools_xps/vms/casa_data_model.py b/pynxtools_xps/vms/casa_data_model.py new file mode 100644 index 00000000..fd1e37e9 --- /dev/null +++ b/pynxtools_xps/vms/casa_data_model.py @@ -0,0 +1,299 @@ +""" +Data model for CasaXPS. +""" +# Copyright The NOMAD Authors. +# +# This file is part of NOMAD. See https://nomad-lab.eu for further info. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# pylint: disable=too-many-instance-attributes + +import re +from typing import List, Dict, Any +from dataclasses import dataclass, field + +from pynxtools_xps.reader_utils import XpsDataclass + + +class CasaProcess: + """Processing and fitting information from CasaXPS.""" + + def __init__(self): + self.n_alignments: int = 0 + self.n_unknown_processes: int = 0 + self.n_regions: int = 0 + self.n_components: int = 0 + + self.alignments: List[Any] = [] + self.unknown_processes: List[Any] = [] + self.regions: List[Any] = [] + self.components: List[Any] = [] + + def process_comments(self, comment_list: List[str]): + line_map = { + "Calib": self.process_alignment, + "CASA region": self.process_region, + "CASA comp": self.process_component, + } + + for line in comment_list: + for token, func in line_map.items(): + if line.startswith(token): + func(line) + + casa_data = { + "alignments": self.alignments, + "regions": self.regions, + "components": self.components, + } + + self.count_occurences() + + return casa_data + + def count_occurences(self): + """Count occurence of different process items.""" + self.n_alignments = len(self.alignments) + self.n_unknown_process = len(self.unknown_processes) + self.n_regions = len(self.regions) + self.n_components = len(self.components) + + def process_alignment(self, align_str: str): + """ + Process one alignment. + + Parameters + ---------- + align_str : str + String with alignment definition in a VMS file. + Typical example: + 'Calib M = 6.8 A = 0 BE ADD' + + + Returns + ------- + None. + + """ + split_line = self._split_line(align_str) + + align = CasaAlignment() + + measured_index = split_line.index("M") + aligned_index = split_line.index("A") + align.measured_energy = float(split_line[measured_index + 2]) + align.aligned_energy = float(split_line[aligned_index + 2]) + + align.energy_type = map_energy_type(split_line[7]) + align.operation = split_line[8] + + if align.operation == "ADD": + align.energy_offset = align.measured_energy - align.aligned_energy + align.operation = "addition" + + align.validate_types() + + self.alignments += [align] + + def process_region(self, region_str: str): + """ + Process one fit region. + + Parameters + ---------- + region_str : str + String with region definition in a VMS file. + Typical example: + 'CASA region (*O1s*) (*Shirley*) 718.88221 726.6 9.74 2 0 9 1450.5943 -450 0 0 (*Mo 3d*) 95.9219 0 9.74' + + Returns + ------- + None. + + """ + split_line = self._split_line(region_str) + + region = CasaRegion() + region.name = split_line[2] + region.bg_type = split_line[3] + region.start = float(split_line[4]) + region.end = float(split_line[5]) + region.rsf = float(split_line[6]) + region.av_width = float(split_line[7]) + region.start_offset = float(split_line[8]) + region.end_offset = float(split_line[9]) + region.cross_section = split_line[10:14] + region.tag = split_line[14] + region.unknown_0 = float(split_line[15]) + region.unknown_1 = float(split_line[16]) + region.rsf_effective = float(split_line[17]) + + region.validate_types() + + self.regions += [region] + + def process_component(self, component_str: str): + """ + Process one fit component if it is defined in the + + Parameters + ---------- + component_str : str + String with component definition in a VMS file. + Typical example: + 'CASA comp (*O1s, lattice*) (*GL(50)*) Area 308996.39 1e-020 15401311 -1 1 MFWHM 1.5315216 0.32 2 -1 1 Position 723.30224 719.3797 726.3 -1 1 RSF 0.063 MASS 15.9994 INDEX -1 (*O 1s*) CONST (**) UNCORRECTEDRSF 2.85' + + + Returns + ------- + None. + + """ + split_line = self._split_line(component_str) + + component = CasaComponent() + component.name = split_line[2] + component.lineshape = split_line[3] + + area_index = split_line.index("Area") + component.area = float(split_line[area_index + 1]) + component.area_min = float(split_line[area_index + 2]) + component.area_max = float(split_line[area_index + 3]) + component.area_ref_comp_id = int(split_line[area_index + 4]) + component.area_ref_comp_factor = float(split_line[area_index + 4]) + + width_index = split_line.index("MFWHM") + component.width = float(split_line[width_index + 1]) + component.width_min = float(split_line[width_index + 2]) + component.width_max = float(split_line[width_index + 3]) + component.width_ref_comp_id = int(split_line[width_index + 4]) + component.width_ref_comp_factor = float(split_line[width_index + 5]) + + position_index = split_line.index("Position") + component.position = float(split_line[position_index + 1]) + component.position_min = float(split_line[position_index + 2]) + component.position_max = float(split_line[position_index + 3]) + component.position_ref_comp_id = int(split_line[position_index + 4]) + component.position_ref_comp_factor = float(split_line[position_index + 5]) + + rsf_index = split_line.index("RSF") + component.rsf = float(split_line[rsf_index + 1]) + mass_index = split_line.index("MASS") + component.mass = float(split_line[mass_index + 1]) + comp_index = split_line.index("INDEX") + component.index = int(split_line[comp_index + 1]) + component.tag = str(split_line[comp_index + 2]) + const_index = split_line.index("CONST") + component.const = str(split_line[const_index + 1]) + uncorrected_rsf_index = split_line.index("UNCORRECTEDRSF") + component.uncorrected_rsf = float(split_line[uncorrected_rsf_index + 1]) + + component.validate_types() + self.components += [component] + + def _split_line(self, line): + """Split line in Casa processing.""" + regex_pattern = r"\s+|\(\*(?:(?!\*\)).)*?\*\)|\S+" + result = [match for match in re.findall(regex_pattern, line) if match.strip()] + return [re.sub(r"[\(*?\*)]", "", text) for text in result] + + +def map_energy_type(energy_str): + """Map energy names to NXDL-compliant concepts.""" + replacements = { + "BE": "binding", + "KE": "kinetic", + "binding energy": "binding", + "binding": "kinetic", + "Binding": "binding", + "Kinetic": "kinetic", + } + return replacements.get(energy_str) + + +@dataclass +class CasaAlignment(XpsDataclass): + """An object to store one CasaXPS alignment.""" + + energy_type: str = "binding" + energy_offset: float = 0.0 + energy_offset_units: str = "eV" + measured_energy: float = 0.0 + measured_energy_units: str = "eV" + aligned_energy: float = 0.0 + measured_energy_units: str = "eV" + operation: str = "eV" + + +@dataclass +class CasaRegion(XpsDataclass): + """An object to store one CasaXPS peak fit region.""" + + name: str = "" + rsf: float = 0.0 + start: float = 0.0 + start_units: str = "eV" + end: float = 0.0 + end_units: str = "eV" + bg_type: str = "" + av_width: float = 0.0 + av_width_units: str = "eV" + start_offset: float = 0.0 + start_offset_units: str = "CPS" + end_offset: float = 0.0 + end_offset_units: str = "CPS" + cross_section: list = field(default_factory=list) + tag: str = "" + unknown_0: float = 0.0 + unknown_1: float = 0.0 + rsf_effective: float = 0.0 + + +@dataclass +class CasaComponent(XpsDataclass): + """An object to store one CasaXPS peak fit component.""" + + name: str = "" + index: int = -1 + lineshape: str = "" + + area: float = 0.0 + area_min: float = 0.0 + area_max: float = 0.0 + area_ref_comp_id: int = -1 + area_ref_comp_factor: float = 0.0 + + width: float = 0.0 + width_units: str = "eV" + width_min: float = 0.0 + width_units: str = "eV" + width_max: float = 0.0 + width_units: str = "eV" + width_ref_comp_id: int = -1 + width_ref_comp_factor: float = 0.0 + + position: float = 0.0 + position_units: str = "eV" + position_min: float = 0.0 + position_min_units: str = "eV" + position_max: float = 0.0 + position_max_units: str = "eV" + position_ref_comp_id: int = -1 + position_ref_comp_factor: float = 0.0 + + rsf: float = 0.0 + uncorrected_rsf: float = 0.0 + mass: float = 0.0 + tag: str = "" + const: str = "" # CONST From e058dc6601b5173ca42288034596eb32aebaa1bc Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:39:33 +0100 Subject: [PATCH 26/41] parsing of units and casa processing --- pynxtools_xps/vms/vamas.py | 174 ++++++++++++++++++++++++++++++++----- 1 file changed, 154 insertions(+), 20 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index ec3fab5f..00dd616d 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -28,12 +28,14 @@ import numpy as np from pynxtools_xps.vms.vamas_data_model import VamasHeader, VamasBlock +from pynxtools_xps.vms.casa_data_model import CasaProcess from pynxtools_xps.reader_utils import ( XPSMapper, construct_entry_name, construct_data_key, construct_detector_data_key, + to_snake_case, ) @@ -56,6 +58,26 @@ def __init__(self): "irregular": VamasParserIrregular, } + self.units = { + "instrument/sample_normal_polarangle_tilt": "degree ", + "instrument/sample_tilt_azimuth": "degree", + "instrument/sample_rotation_angle": "degree", + "source/source_analyzer_angle": "degree", + "source/excitation_energy": "eV", + "source/particle_charge": "C", + "analyser/analyzer_take_off_azimuth": "degree", + "analyser/analyzer_take_off_polar": "degree", + "analyser/analysis_width_x": "m", + "analyser/analysis_width_y": "m", + "analyser/target_bias": "V", + "analyser/time_correction": "s", + "analyser/work_function": "eV", + "energydispersion/pass_energy": "eV", + "detector/dwell_time": "s", + "data/start_energy": "eV", + "data/step_size": "eV", + } + super().__init__() def _select_parser(self): @@ -94,21 +116,28 @@ def construct_data(self): key_map = { "user": [], - "instrument": [], + "instrument": [ + "sample_normal_polarangle_tilt", + "sample_tilt_azimuth", + "sample_rotation_angle", + ], "source": [ "source_label", "source_analyzer_angle", ], - "beam": ["excitation_energy"], + "beam": ["excitation_energy", "particle_charge"], "analyser": [ "analyzer_take_off_azimuth", "analyzer_take_off_polar", "analysis_width_x", "analysis_width_y", "target_bias", + "time_correction", "work_function", ], - "collectioncolumn": [], + "collectioncolumn": [ + "magnification", + ], "energydispersion": [ "scan_mode", "pass_energy", @@ -118,8 +147,7 @@ def construct_data(self): "dwell_time", ], "manipulator": [], - "sample": [], - "calibration": [], + "sample": ["sample_name"], "data": [ "x_label", "x_units", @@ -133,11 +161,16 @@ def construct_data(self): ], "region": [ "analysis_method", - "spectrum_type", - "comments", + "element", + "group_id", + "group_name", + "region", + "scan_no", + "scans", "spectrum_id", + "spectrum_type", + "transition", "time_stamp", - "scans", ], } @@ -147,8 +180,8 @@ def construct_data(self): def _update_xps_dict_with_spectrum(self, spectrum, key_map): """Map one spectrum from raw data to NXmpes-ready dict.""" # pylint: disable=too-many-locals,duplicate-code - group_parent = f'{self._root_path}/RegionGroup_{spectrum["group_name"]}' - region_parent = f'{group_parent}/regions/RegionData_{spectrum["spectrum_type"]}' + group_parent = f'{self._root_path}/Group_{spectrum["group_name"]}' + region_parent = f'{group_parent}/regions/Region_{spectrum["spectrum_type"]}' instrument_parent = f"{region_parent}/instrument" analyser_parent = f"{instrument_parent}/analyser" @@ -162,23 +195,47 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): "energydispersion": f"{analyser_parent}/energydispersion", "detector": f"{analyser_parent}/detector", "manipulator": f"{instrument_parent}/manipulator", - "calibration": f"{instrument_parent}/calibration", "sample": f"{region_parent}/sample", "data": f"{region_parent}/data", + "energy_referencing": f"{region_parent}/calibrations/energy_referencing", + "peak_fitting": f"{region_parent}/peak_fitting", "region": f"{region_parent}", } + used_keys = [] + for grouping, spectrum_keys in key_map.items(): root = path_map[str(grouping)] for spectrum_key in spectrum_keys: - try: - units = re.search(r"\[([A-Za-z0-9_]+)\]", spectrum_key).group(1) - mpes_key = spectrum_key.rsplit(" ", 1)[0] + mpes_key = spectrum_key.rsplit(" ", 1)[0] + self._xps_dict[f"{root}/{mpes_key}"] = spectrum[spectrum_key] + + unit_key = f"{grouping}/{spectrum_key}" + units = self._get_units_for_key(unit_key) + if units: self._xps_dict[f"{root}/{mpes_key}/@units"] = units - self._xps_dict[f"{root}/{mpes_key}"] = spectrum[spectrum_key] - except AttributeError: - mpes_key = spectrum_key - self._xps_dict[f"{root}/{mpes_key}"] = spectrum[spectrum_key] + + # Write process data + process_key_map = { + "energy_referencing": ["alignments"], + "peak_fitting": ["regions", "components"], + } + + for grouping, spectrum_keys in process_key_map.items(): + root = path_map[str(grouping)] + for spectrum_key in spectrum_keys: + try: + processes = spectrum[spectrum_key] + for i, process in enumerate(processes): + process_key = ( + f"{root}/{spectrum_key}/{spectrum_key.rstrip('s')}{i}" + ) + for key, value in process.dict().items(): + key = key.replace("_units", "/@units") + self._xps_dict[f"{process_key}/{key}"] = value + used_keys += [spectrum_key] + except KeyError: + pass # Create keys for writing to data and detector entry = construct_entry_name(region_parent) @@ -217,10 +274,40 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): self._xps_dict["data"][entry][scan_key] = xr.DataArray( data=intensity_cps, coords={"energy": energy} ) + used_keys += ["data"] # Write raw intensities to 'detector'. self._xps_dict[detector_data_key] = intensity_raw + # Write additional keys to region parent. + for spectrum_key, value in spectrum.items(): + if spectrum_key not in used_keys: + self._xps_dict[f"{region_parent}/{spectrum_key}"] = value + + def _get_units_for_key(self, unit_key): + """ + Get correct units for a given key. + + Parameters + ---------- + unit_key : str + Key of type :, e.g. + detector/detector_voltage + + Returns + ------- + str + Unit for that unit_key. + + """ + try: + return re.search(r"\[([A-Za-z0-9_]+)\]", unit_key).group(1) + except AttributeError: + try: + return self.units[unit_key] + except KeyError: + return "" + class VamasParser(ABC): """A parser for reading vamas files.""" @@ -550,7 +637,6 @@ def build_list(self): settings = { "region": block.block_id, "sample_name": block.sample_id, - "comments": block.comment_lines, "analysis_method": block.technique, "source_label": block.source_label, "excitation_energy": block.source_energy, @@ -584,6 +670,9 @@ def build_list(self): "n_values": int(block.num_ord_values / block.no_variables), } + comment_dict = self.handle_block_comments(block.comment_lines) + settings.update(comment_dict) + # Convert the native time format to the datetime string # in the ISO 8601 format tzinfo = datetime.timezone( @@ -606,7 +695,7 @@ def build_list(self): data["y"] = getattr(block, "y") - if block.variable_label_1 == "Intensity": + if block.variable_label_1 in ["Intensity", "counts"]: y_cps = [np.round(y / block.dwell_time, 2) for y in block.y] data["y_cps"] = y_cps @@ -630,6 +719,44 @@ def build_list(self): return spectra + def handle_block_comments(self, comment_list): + """Handle comments (incl. Casa fitting for each block.""" + comments = {} + + if "Casa Info Follows" in comment_list[0]: + # Get all processing and fitting data from Casa comments. + casa = CasaProcess() + casa_data = casa.process_comments(comment_list) + + comments.update(casa_data) + + no_of_casa_lines = 1 + + for number in ( + "n_alignments", + "n_unknown_processes", + "n_regions", + "n_components", + ): + occurence = getattr(casa, number) + no_of_casa_lines += 1 + if occurence >= 1: + no_of_casa_lines += occurence + + non_casa_comments = comment_list[no_of_casa_lines:] + + else: + non_casa_comments = comment_list + + for line in non_casa_comments: + for sep in ("=", ":"): + try: + key, value = [part.strip(" ") for part in line.split("=", 1)] + comments[to_snake_case(key)] = value + except ValueError: + continue + return comments + class VamasParserRegular(VamasParser): """Parser for .vms files of type REGULAR""" @@ -1040,3 +1167,10 @@ def _add_data_values(self, block): data_array_slice = data_array[var::max_var] data_dict[name] = data_array_slice setattr(block, name, data_dict[name]) + + +if __name__ == "__main__": + file = r"C:\Users\pielsticker\Lukas\FAIRMat\user_cases\Schumann_XPS_Catalysis\C2 Activated Vamas Files\CleanData-alphaII VOPO4 C2 BC4316.vms" + parser = VamasParserRegular() + d = parser.parse_file(file) + d0 = d[0] From 138ea710675be8b548c699af68782ca747db497e Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:53:38 +0100 Subject: [PATCH 27/41] fix casa data model --- pynxtools_xps/vms/casa_data_model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pynxtools_xps/vms/casa_data_model.py b/pynxtools_xps/vms/casa_data_model.py index fd1e37e9..525b3ae8 100644 --- a/pynxtools_xps/vms/casa_data_model.py +++ b/pynxtools_xps/vms/casa_data_model.py @@ -232,7 +232,7 @@ class CasaAlignment(XpsDataclass): measured_energy: float = 0.0 measured_energy_units: str = "eV" aligned_energy: float = 0.0 - measured_energy_units: str = "eV" + aligned_energy_units: str = "eV" operation: str = "eV" @@ -277,9 +277,9 @@ class CasaComponent(XpsDataclass): width: float = 0.0 width_units: str = "eV" width_min: float = 0.0 - width_units: str = "eV" + width_min_units: str = "eV" width_max: float = 0.0 - width_units: str = "eV" + width_max_units: str = "eV" width_ref_comp_id: int = -1 width_ref_comp_factor: float = 0.0 From 5d7ddd7f8ae4035652e39c6dad7733a5afac1ed0 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Wed, 6 Mar 2024 17:06:09 +0100 Subject: [PATCH 28/41] add handling of Casa header --- pynxtools_xps/vms/vamas.py | 33 +++++++++++++++++++++++---- pynxtools_xps/vms/vamas_data_model.py | 6 +++-- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index 00dd616d..ff8d4817 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -624,6 +624,10 @@ def build_list(self): temp_group_name = "" spectra = [] + header_dict = {to_snake_case(k): v for (k, v) in self.header.dict().items()} + del header_dict["comment_lines"] + header_dict.update(self.handle_header_comments(self.header.comment_lines)) + for spectrum_id, block in enumerate(self.blocks): group_name = block.sample_id # This set of conditions detects if the group name has changed. @@ -669,9 +673,7 @@ def build_list(self): "sample_rotation_angle": block.sample_rotation, "n_values": int(block.num_ord_values / block.no_variables), } - - comment_dict = self.handle_block_comments(block.comment_lines) - settings.update(comment_dict) + settings.update(header_dict) # Convert the native time format to the datetime string # in the ISO 8601 format @@ -719,8 +721,31 @@ def build_list(self): return spectra + def handle_header_comments(self, comment_list): + """Handle comments (incl. Casa info) for the header.""" + comments = {} + + if "Casa Info Follows" in comment_list[0]: + comments["casa_version"] = ( + comment_list[0].split("Casa Info Follows CasaXPS Version")[1].strip() + ) + non_casa_comments = comment_list[1:] + else: + non_casa_comments = comment_list + + for line in non_casa_comments: + for sep in ("=", ":"): + try: + key, value = [part.strip(" ") for part in line.split(sep, 1)] + comments[to_snake_case(key)] = value + except ValueError: + if "SpecsLab Prodigy" in line: + comments["prodigy_version"] = line.split("Version")[1].strip() + + return comments + def handle_block_comments(self, comment_list): - """Handle comments (incl. Casa fitting for each block.""" + """Handle comments (incl. Casa fitting) for each block.""" comments = {} if "Casa Info Follows" in comment_list[0]: diff --git a/pynxtools_xps/vms/vamas_data_model.py b/pynxtools_xps/vms/vamas_data_model.py index 35797b70..7fb4d4e5 100644 --- a/pynxtools_xps/vms/vamas_data_model.py +++ b/pynxtools_xps/vms/vamas_data_model.py @@ -21,9 +21,11 @@ from dataclasses import dataclass, field +from pynxtools_xps.reader_utils import XpsDataclass + @dataclass -class VamasHeader: +class VamasHeader(XpsDataclass): """An object to store the Vamas header information.""" format_id: str = ( @@ -51,7 +53,7 @@ class VamasHeader: @dataclass -class VamasBlock: +class VamasBlock(XpsDataclass): """An object to store a block of spectrum data and meta-data.""" block_id: str = "" From 3b1fe5bc06e1f344698e953e791e65250e03806a Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Thu, 7 Mar 2024 10:02:49 +0100 Subject: [PATCH 29/41] add parsing of header comments --- pynxtools_xps/reader_utils.py | 18 ++++++- pynxtools_xps/vms/vamas.py | 72 +++++++++++++++++++++++---- pynxtools_xps/vms/vamas_data_model.py | 1 - 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/pynxtools_xps/reader_utils.py b/pynxtools_xps/reader_utils.py index 86cec378..48463b84 100644 --- a/pynxtools_xps/reader_utils.py +++ b/pynxtools_xps/reader_utils.py @@ -17,6 +17,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # +import re from abc import ABC, abstractmethod from scipy.interpolate import interp1d import numpy as np @@ -100,9 +101,22 @@ def construct_data(self): """ -def to_snake_case(string_with_whitespace): +def to_snake_case(str_value): """Convert a string to snake_case.""" - return "_".join(word.lower() for word in string_with_whitespace.split()) + if " " in str_value: + return "_".join(word.lower() for word in str_value.split()) + return convert_pascal_to_snake(str_value) + + +def convert_pascal_to_snake(str_value): + """Convert pascal case text to snake case.""" + pattern = re.compile(r"(? Date: Fri, 8 Mar 2024 16:12:21 +0100 Subject: [PATCH 30/41] enable parsing of irregular vms files --- pynxtools_xps/vms/vamas.py | 951 +++++++++++++++---------------------- 1 file changed, 387 insertions(+), 564 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index cd916cbf..b3c1409e 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -37,6 +37,7 @@ construct_data_key, construct_detector_data_key, to_snake_case, + get_minimal_step, ) @@ -50,14 +51,7 @@ class VamasMapper(XPSMapper): def __init__(self): self.file = None - self.parsers = [ - VamasParserRegular, - VamasParserIrregular, - ] - self.parser_map = { - "regular": VamasParserRegular, - "irregular": VamasParserIrregular, - } + self.parsers = [] self.units = { "instrument/sample_normal_polarangle_tilt": "degree ", @@ -92,21 +86,7 @@ def _select_parser(self): Vamas parser for reading this file structure. """ - vms_type = self._get_vms_type() - return self.parser_map[vms_type]() - - def _get_vms_type(self): - """Check if the vamas file is regular or irregular""" - contents = [] - with open(self.file, "rb") as vms_file: - for line in vms_file: - if line.endswith(b"\r\n"): - contents += [line.decode("utf-8", errors="ignore").strip()] - - for vms_type in self.parser_map: - if vms_type.upper() in contents: - return vms_type - return "" + return VamasParser() def construct_data(self): """Map VMS format to NXmpes-ready dict.""" @@ -310,7 +290,7 @@ def _get_units_for_key(self, unit_key): return "" -class VamasParser(ABC): +class VamasParser: """A parser for reading vamas files.""" def __init__(self): @@ -506,6 +486,7 @@ def parse_file(self, file): return self.build_list() def _read_lines(self, file): + """Read in vamas text file.""" with open(file, "rb") as vms_file: for line in vms_file: if line.endswith(b"\r\n"): @@ -546,34 +527,288 @@ def _add_exp_var(self): setattr(self.header, attr, self.data.pop(0).strip()) def _parse_blocks(self): + """Parse all (metadata) of Vamas blocks.""" for _ in range(int(self.header.no_blocks)): self._parse_one_block() def _parse_one_block(self): + """Parse one Vamas Block.""" if self.header.exp_mode == "NORM": self.blocks += [self._parse_norm_block()] elif self.header.exp_mode == "MAP": self.blocks += [self._parse_map_block()] - @abstractmethod def _parse_norm_block(self): """ Use this method when the NORM keyword is present. - This method has to be implemented in the inherited parsers. + Returns + ------- + block : vamas.Block object. + A block represents one spectrum with its metadata. """ - return VamasBlock() + # pylint: disable=too-many-statements + block = VamasBlock() + block.block_id = self.data.pop(0).strip() + block.sample_id = self.data.pop(0).strip() + block.year = int(self.data.pop(0).strip()) + block.month = int(self.data.pop(0).strip()) + block.day = int(self.data.pop(0).strip()) + block.hour = int(self.data.pop(0).strip()) + block.minute = int(self.data.pop(0).strip()) + block.second = int(self.data.pop(0).strip().split(".")[0]) + block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) + block.no_comment_lines = int(self.data.pop(0).strip()) + for _ in range(block.no_comment_lines): + block.comment_lines += [self.data.pop(0)] + block.technique = self.data.pop(0).strip() + for _ in range(int(self.header.nr_exp_var)): + block.exp_var_value = self.data.pop(0).strip() + block.source_label = self.data.pop(0).strip() + block.source_energy = float(self.data.pop(0).strip()) + block.unknown_1 = self.data.pop(0).strip() + block.unknown_2 = self.data.pop(0).strip() + block.unknown_3 = self.data.pop(0).strip() + block.source_analyzer_angle = self.data.pop(0).strip() + block.unknown_4 = self.data.pop(0).strip() + block.analyzer_mode = self.data.pop(0).strip() + block.resolution = float(self.data.pop(0).strip()) + block.magnification = self.data.pop(0).strip() + block.work_function = float(self.data.pop(0).strip()) + block.target_bias = float(self.data.pop(0).strip()) + block.analyzer_width_x = self.data.pop(0).strip() + block.analyzer_width_y = self.data.pop(0).strip() + block.analyzer_take_off_polar_angle = self.data.pop(0).strip() + block.analyzer_azimuth = self.data.pop(0).strip() + block.species_label = self.data.pop(0).strip() + block.transition_label = self.data.pop(0).strip() + block.particle_charge = self.data.pop(0).strip() + + if self.header.scan_mode == "REGULAR": + block.abscissa_label = self.data.pop(0).strip() + block.abscissa_units = self.data.pop(0).strip() + block.abscissa_start = float(self.data.pop(0).strip()) + block.abscissa_step = float(self.data.pop(0).strip()) + + block.no_variables = int(self.data.pop(0).strip()) + for var in range(block.no_variables): + name = "variable_label_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + name = "variable_units_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + + else: + block.no_variables = int(self.data.pop(0).strip()) - 1 + block.abscissa_label = self.data.pop(0).strip() + block.abscissa_units = self.data.pop(0).strip() + for var in range(block.no_variables): + name = "variable_label_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + name = "variable_units_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + + block.signal_mode = self.data.pop(0).strip() + block.dwell_time = float(self.data.pop(0).strip()) + block.no_scans = int(self.data.pop(0).strip()) + block.time_correction = self.data.pop(0).strip() + block.sample_angle_tilt = float(self.data.pop(0).strip()) + block.sample_tilt_azimuth = float(self.data.pop(0).strip()) + block.sample_rotation = float(self.data.pop(0).strip()) + block.no_additional_params = int(self.data.pop(0).strip()) + for param in range(block.no_additional_params): + name = "param_label_" + str(param + 1) + setattr(block, name, self.data.pop(0)) + name = "param_unit_" + str(param + 1) + setattr(block, name, self.data.pop(0)) + name = "param_value_" + str(param + 1) + setattr(block, name, self.data.pop(0)) + block.num_ord_values = int(self.data.pop(0).strip()) + if self.header.scan_mode == "IRREGULAR": + del self.data[:2] + for var in range(block.no_variables): + name = "min_ord_value_" + str(var + 1) + setattr(block, name, float(self.data.pop(0).strip())) + name = "max_ord_value_" + str(var + 1) + setattr(block, name, float(self.data.pop(0).strip())) - @abstractmethod - def _parse_map_block(self): + self._add_data_values(block) + return block + + def _parse_map_block(self, regular: bool = True): """ Use this method when the MAP keyword is present. - This method has to be implemented in the inherited parsers. + Returns + ------- + block : vamas.Block object. + A block represents one spectrum with its metadata. """ - return VamasBlock() + # pylint: disable=too-many-statements + block = VamasBlock() + block.block_id = self.data.pop(0).strip() + block.sample_id = self.data.pop(0).strip() + block.year = int(self.data.pop(0).strip()) + block.month = int(self.data.pop(0).strip()) + block.day = int(self.data.pop(0).strip()) + block.hour = int(self.data.pop(0).strip()) + block.minute = int(self.data.pop(0).strip()) + block.second = int(self.data.pop(0).strip()) + block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) + block.no_comment_lines = int(self.data.pop(0).strip()) + for _ in range(block.no_comment_lines): + self.data.pop(0) + block.comment_lines += [self.data.pop(0)] + block.technique = self.data.pop(0).strip() + block.x_coord = self.data.pop(0).strip() + block.y_coord = self.data.pop(0).strip() + block.exp_var_value = self.data.pop(0).strip() + block.source_label = self.data.pop(0).strip() + block.source_energy = float(self.data.pop(0).strip()) + block.unknown_1 = self.data.pop(0).strip() + block.unknown_2 = self.data.pop(0).strip() + block.unknown_3 = self.data.pop(0).strip() + block.fov_x = self.data.pop(0).strip() + block.fov_y = self.data.pop(0).strip() + block.source_analyzer_angle = self.data.pop(0).strip() + block.unknown_4 = self.data.pop(0).strip() + block.analyzer_mode = self.data.pop(0).strip() + block.resolution = float(self.data.pop(0).strip()) + block.magnification = self.data.pop(0).strip() + block.work_function = float(self.data.pop(0).strip()) + block.target_bias = float(self.data.pop(0).strip()) + block.analyzer_width_x = self.data.pop(0).strip() + block.analyzer_width_y = self.data.pop(0).strip() + block.analyzer_take_off_polar_angle = self.data.pop(0).strip() + block.analyzer_azimuth = self.data.pop(0).strip() + block.species_label = self.data.pop(0).strip() + block.transition_label = self.data.pop(0).strip() + block.particle_charge = self.data.pop(0).strip() + + if self.header.scan_mode == "REGULAR": + block.abscissa_label = self.data.pop(0).strip() + block.abscissa_units = self.data.pop(0).strip() + block.abscissa_start = float(self.data.pop(0).strip()) + block.abscissa_step = float(self.data.pop(0).strip()) + + block.no_variables = int(self.data.pop(0).strip()) + for var in range(block.no_variables): + name = "variable_label_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + name = "variable_units_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + + else: + block.no_variables = int(self.data.pop(0).strip()) - 1 + block.abscissa_label = self.data.pop(0).strip() + block.abscissa_units = self.data.pop(0).strip() + for var in range(block.no_variables): + name = "variable_label_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + name = "variable_units_" + str(var + 1) + setattr(block, name, self.data.pop(0).strip()) + + block.signal_mode = self.data.pop(0).strip() + block.dwell_time = float(self.data.pop(0).strip()) + block.no_scans = int(self.data.pop(0).strip()) + block.time_correction = self.data.pop(0).strip() + block.sample_angle_tilt = float(self.data.pop(0).strip()) + block.sample_tilt_azimuth = float(self.data.pop(0).strip()) + block.sample_rotation = float(self.data.pop(0).strip()) + block.no_additional_params = int(self.data.pop(0).strip()) + for param in range(block.no_additional_params): + name = "param_label_" + str(param + 1) + setattr(block, name, self.data.pop(0)) + name = "param_unit_" + str(param + 1) + setattr(block, name, self.data.pop(0)) + name = "param_value_" + str(param + 1) + setattr(block, name, self.data.pop(0)) + block.num_ord_values = int(self.data.pop(0).strip()) + if self.header.scan_mode == "IRREGULAR": + del self.data[:2] + for var in range(block.no_variables): + name = "min_ord_value_" + str(var + 1) + setattr(block, name, float(self.data.pop(0).strip())) + name = "max_ord_value_" + str(var + 1) + setattr(block, name, float(self.data.pop(0).strip())) + + self._add_data_values(block) + + return block + + def _add_data_values(self, block): + """Add data values to a Vamas data block.""" + if self.header.scan_mode == "REGULAR": + self._add_regular_data(block) + elif self.header.scan_mode == "IRREGULAR": + self._add_irregular_data(block) + + def _add_regular_data(self, block): + """Parse data with regularly spaced energy axis.""" + data_dict = {} + start = float(block.abscissa_start) + step = float(block.abscissa_step) + num = int(block.num_ord_values / block.no_variables) + energy = [round(start + i * step, 2) for i in range(num)] + + if block.abscissa_label == "binding energy": + energy.reverse() + + setattr(block, "x", energy) + + for var in range(block.no_variables): + if var == 0: + name = "y" + else: + name = "y" + str(var) + data_dict[name] = [] + + data_array = list(np.array(self.data[: block.num_ord_values], dtype=float)) + + self.data = self.data[block.num_ord_values :] + + for var in range(block.no_variables): + max_var = block.no_variables + if var == 0: + name = "y" + else: + name = "y" + str(var) + data_array_slice = data_array[var::max_var] + data_dict[name] = data_array_slice + setattr(block, name, data_dict[name]) + + def _add_irregular_data(self, block): + """Parse data with regularly spaced energy axis.""" + data_dict = {} + + block_data = list(np.array(self.data[: block.num_ord_values], dtype=float)) + + energy = block_data[:: block.no_variables + 1] + if block.abscissa_label == "binding energy": + energy.reverse() + block.x = energy + block.abscissa_start = min(energy) + block.abscissa_stop = max(energy) + block.abscissa_step = get_minimal_step(energy) + + for var in range(block.no_variables): + if var == 0: + name = "y" + else: + name = "y" + str(var) + data_dict[name] = [] + + for var in range(block.no_variables): + if var == 0: + name = "y" + else: + name = "y" + str(var) + data_array_slice = block_data[var + 1 :: block.no_variables + 1] + data_dict[name] = data_array_slice + setattr(block, name, data_dict[name]) + + self.data = self.data[block.num_ord_values + block.no_variables :] def _get_scan_numbers_for_spectra(self, spectra): """ @@ -610,146 +845,34 @@ def _get_scan_numbers_for_spectra(self, spectra): return flattened_spectra - def build_list(self): - """ - Construct a list of dictionaries from the Vamas objects + def handle_header_comments(self, comment_list): + """Handle comments (incl. Casa info) for the header.""" + comments = {} - Returns - ------- - List - Each list element is a dictionary with the data and - metadata of one spectrum. + special_keys = { + "Casa Info Follows": self._handle_casa_header, + "SpecsLab Prodigy": self._handle_prodigy_header, + # "SOFH": self._handle_phi_header, + } - """ - group_id = -1 - temp_group_name = "" - spectra = [] + for keyword, handle_func in special_keys.items(): + if any(keyword in line for line in comment_list): + index = [i for i, line in enumerate(comment_list) if keyword in line][0] - header_dict = {to_snake_case(k): v for (k, v) in self.header.dict().items()} - del header_dict["comment_lines"] - header_dict.update(self.handle_header_comments(self.header.comment_lines)) + if keyword == "Casa Info Follows": + special_comments = comment_list[index] + comment_list = comment_list[index + 1 :] - for spectrum_id, block in enumerate(self.blocks): - group_name = block.sample_id - # This set of conditions detects if the group name has changed. - # If it has, then it increments the group_idx. - if group_name != temp_group_name: - temp_group_name = group_name - group_id += 1 + if keyword == "SpecsLab Prodigy": + special_comments = comment_list[index] + comment_list = comment_list[index + 1 :] - spectrum_type = str(block.species_label + block.transition_label) - - settings = { - "region": block.block_id, - "sample_name": block.sample_id, - "analysis_method": block.technique, - "source_label": block.source_label, - "excitation_energy": block.source_energy, - "source_analyzer_angle": block.source_analyzer_angle, - "scan_mode": block.analyzer_mode, - "pass_energy": block.resolution, - "magnification": block.magnification, - "work_function": block.work_function, - "target_bias": block.target_bias, - "analysis_width_x": block.analyzer_width_x, - "analysis_width_y": block.analyzer_width_y, - "analyzer_take_off_polar": block.analyzer_take_off_polar_angle, - "analyzer_take_off_azimuth": block.analyzer_azimuth, - "element": block.species_label, - "transition": block.transition_label, - "particle_charge": block.particle_charge, - "x_label": block.abscissa_label, - "x_units": block.abscissa_units, - "start_energy": block.abscissa_start, - "step_size": block.abscissa_step, - "y_labels_1": block.variable_label_1, - "y_units_1": block.variable_units_1, - "y_labels_2": block.variable_label_2, - "y_units_2": block.variable_units_2, - "signal_mode": block.signal_mode, - "dwell_time": block.dwell_time, - "time_correction": block.time_correction, - "sample_normal_polarangle_tilt": block.sample_angle_tilt, - "sample_tilt_azimuth": block.sample_tilt_azimuth, - "sample_rotation_angle": block.sample_rotation, - "n_values": int(block.num_ord_values / block.no_variables), - } - settings.update(header_dict) - - # Convert the native time format to the datetime string - # in the ISO 8601 format - tzinfo = datetime.timezone( - datetime.timedelta(hours=block.no_hrs_in_advance_of_gmt) - ) - date_time = datetime.datetime( - block.year, - block.month, - block.day, - block.hour, - block.minute, - block.second, - tzinfo=tzinfo, - ) - - data = {"x": block.x} - for var in range(int(block.no_variables)): - if var == 0: - key = "y" - - data["y"] = getattr(block, "y") - - if block.variable_label_1 in ["Intensity", "counts"]: - y_cps = [np.round(y / block.dwell_time, 2) for y in block.y] - data["y_cps"] = y_cps - - else: - key = "y" + str(var) - data[key] = getattr(block, key) - - spec_dict = { - "time_stamp": date_time, - "group_name": group_name, - "group_id": group_id, - "spectrum_type": spectrum_type, - "spectrum_id": spectrum_id, - "scans": block.no_scans, - "data": data, - } - spec_dict.update(settings) - spectra += [spec_dict] - - spectra = self._get_scan_numbers_for_spectra(spectra) - - return spectra - - def handle_header_comments(self, comment_list): - """Handle comments (incl. Casa info) for the header.""" - comments = {} - - special_keys = { - "Casa Info Follows": self._handle_casa_header, - "SpecsLab Prodigy": self._handle_prodigy_header, - # "SOFH": self._handle_phi_header, - } - - for keyword, handle_func in special_keys.items(): - if any(keyword in line for line in comment_list): - index = [i for i, line in enumerate(comment_list) if keyword in line][0] - - if keyword == "Casa Info Follows": - special_comments = comment_list[index] - comment_list = comment_list[index + 1 :] - - if keyword == "SpecsLab Prodigy": - special_comments = comment_list[index] - comment_list = comment_list[index + 1 :] - - if keyword == "SOFH": - end_index = [ - i for i, line in enumerate(comment_list) if "EOFH" in line - ][0] - special_comments = comment_list[index : end_index + 1] - del comment_list[index : end_index + 1] + if keyword == "SOFH": + end_index = [ + i for i, line in enumerate(comment_list) if "EOFH" in line + ][0] + special_comments = comment_list[index : end_index + 1] + del comment_list[index : end_index + 1] comments.update(handle_func(special_comments)) @@ -834,420 +957,120 @@ def handle_block_comments(self, comment_list): continue return comments - -class VamasParserRegular(VamasParser): - """Parser for .vms files of type REGULAR""" - - def _parse_norm_block(self): + def build_list(self): """ - Use this method when the NORM keyword is present. + Construct a list of dictionaries from the Vamas objects Returns ------- - block : vamas.Block object. - A block represents one spectrum with its metadata. + List + Each list element is a dictionary with the data and + metadata of one spectrum. """ - # pylint: disable=too-many-statements - block = VamasBlock() - block.block_id = self.data.pop(0).strip() - block.sample_id = self.data.pop(0).strip() - block.year = int(self.data.pop(0).strip()) - block.month = int(self.data.pop(0).strip()) - block.day = int(self.data.pop(0).strip()) - block.hour = int(self.data.pop(0).strip()) - block.minute = int(self.data.pop(0).strip()) - block.second = int(self.data.pop(0).strip().split(".")[0]) - block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) - block.no_comment_lines = int(self.data.pop(0).strip()) - for _ in range(block.no_comment_lines): - block.comment_lines += [self.data.pop(0)] - block.technique = self.data.pop(0).strip() - for _ in range(int(self.header.nr_exp_var)): - block.exp_var_value = self.data.pop(0).strip() - block.source_label = self.data.pop(0).strip() - block.source_energy = float(self.data.pop(0).strip()) - block.unknown_1 = self.data.pop(0).strip() - block.unknown_2 = self.data.pop(0).strip() - block.unknown_3 = self.data.pop(0).strip() - block.source_analyzer_angle = self.data.pop(0).strip() - block.unknown_4 = self.data.pop(0).strip() - block.analyzer_mode = self.data.pop(0).strip() - block.resolution = float(self.data.pop(0).strip()) - block.magnification = self.data.pop(0).strip() - block.work_function = float(self.data.pop(0).strip()) - block.target_bias = float(self.data.pop(0).strip()) - block.analyzer_width_x = self.data.pop(0).strip() - block.analyzer_width_y = self.data.pop(0).strip() - block.analyzer_take_off_polar_angle = self.data.pop(0).strip() - block.analyzer_azimuth = self.data.pop(0).strip() - block.species_label = self.data.pop(0).strip() - block.transition_label = self.data.pop(0).strip() - block.particle_charge = self.data.pop(0).strip() - block.abscissa_label = self.data.pop(0).strip() - block.abscissa_units = self.data.pop(0).strip() - block.abscissa_start = float(self.data.pop(0).strip()) - block.abscissa_step = float(self.data.pop(0).strip()) - block.no_variables = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "variable_label_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - name = "variable_units_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - block.signal_mode = self.data.pop(0).strip() - block.dwell_time = float(self.data.pop(0).strip()) - block.no_scans = int(self.data.pop(0).strip()) - block.time_correction = self.data.pop(0).strip() - block.sample_angle_tilt = float(self.data.pop(0).strip()) - block.sample_tilt_azimuth = float(self.data.pop(0).strip()) - block.sample_rotation = float(self.data.pop(0).strip()) - block.no_additional_params = int(self.data.pop(0).strip()) - for param in range(block.no_additional_params): - name = "param_label_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_unit_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_value_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - block.num_ord_values = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "min_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) - name = "max_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) - - self._add_data_values(block) - return block + group_id = -1 + temp_group_name = "" + spectra = [] - def _parse_map_block(self): - """ - Use this method when the MAP keyword is present. + header_dict = {to_snake_case(k): v for (k, v) in self.header.dict().items()} + del header_dict["comment_lines"] + header_dict.update(self.handle_header_comments(self.header.comment_lines)) - Returns - ------- - block : vamas.Block object. - A block represents one spectrum with its metadata. + for spectrum_id, block in enumerate(self.blocks): + group_name = block.sample_id + # This set of conditions detects if the group name has changed. + # If it has, then it increments the group_idx. + if group_name != temp_group_name: + temp_group_name = group_name + group_id += 1 - """ - # pylint: disable=too-many-statements - block = VamasBlock() - block.block_id = self.data.pop(0).strip() - block.sample_id = self.data.pop(0).strip() - block.year = int(self.data.pop(0).strip()) - block.month = int(self.data.pop(0).strip()) - block.day = int(self.data.pop(0).strip()) - block.hour = int(self.data.pop(0).strip()) - block.minute = int(self.data.pop(0).strip()) - block.second = int(self.data.pop(0).strip()) - block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) - block.no_comment_lines = int(self.data.pop(0).strip()) - for _ in range(block.no_comment_lines): - self.data.pop(0) - block.comment_lines += [self.data.pop(0)] - block.technique = self.data.pop(0).strip() - block.x_coord = self.data.pop(0).strip() - block.y_coord = self.data.pop(0).strip() - block.exp_var_value = self.data.pop(0).strip() - block.source_label = self.data.pop(0).strip() - block.source_energy = float(self.data.pop(0).strip()) - block.unknown_1 = self.data.pop(0).strip() - block.unknown_2 = self.data.pop(0).strip() - block.unknown_3 = self.data.pop(0).strip() - block.fov_x = self.data.pop(0).strip() - block.fov_y = self.data.pop(0).strip() - block.source_analyzer_angle = self.data.pop(0).strip() - block.unknown_4 = self.data.pop(0).strip() - block.analyzer_mode = self.data.pop(0).strip() - block.resolution = float(self.data.pop(0).strip()) - block.magnification = self.data.pop(0).strip() - block.work_function = float(self.data.pop(0).strip()) - block.target_bias = float(self.data.pop(0).strip()) - block.analyzer_width_x = self.data.pop(0).strip() - block.analyzer_width_y = self.data.pop(0).strip() - block.analyzer_take_off_polar_angle = self.data.pop(0).strip() - block.analyzer_azimuth = self.data.pop(0).strip() - block.species_label = self.data.pop(0).strip() - block.transition_label = self.data.pop(0).strip() - block.particle_charge = self.data.pop(0).strip() - block.abscissa_label = self.data.pop(0).strip() - block.abscissa_units = self.data.pop(0).strip() - block.abscissa_start = float(self.data.pop(0).strip()) - block.abscissa_step = float(self.data.pop(0).strip()) - block.no_variables = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "variable_label_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - name = "variable_units_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - block.signal_mode = self.data.pop(0).strip() - block.dwell_time = float(self.data.pop(0).strip()) - block.no_scans = int(self.data.pop(0).strip()) - block.time_correction = self.data.pop(0).strip() - block.sample_angle_tilt = float(self.data.pop(0).strip()) - block.sample_tilt_azimuth = float(self.data.pop(0).strip()) - block.sample_rotation = float(self.data.pop(0).strip()) - block.no_additional_params = int(self.data.pop(0).strip()) - for param in range(block.no_additional_params): - name = "param_label_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_unit_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_value_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - block.num_ord_values = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "min_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) - name = "max_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) + spectrum_type = str(block.species_label + block.transition_label) - self._add_data_values(block) - - return block - - def _add_data_values(self, block): - """Add data values to a Vamas data block.""" - data_dict = {} - start = float(block.abscissa_start) - step = float(block.abscissa_step) - num = int(block.num_ord_values / block.no_variables) - energy = [round(start + i * step, 2) for i in range(num)] - - if block.abscissa_label == "binding energy": - energy.reverse() - - setattr(block, "x", energy) - - for var in range(block.no_variables): - if var == 0: - name = "y" - else: - name = "y" + str(var) - data_dict[name] = [] - - data_array = list(np.array(self.data[: block.num_ord_values], dtype=float)) - - self.data = self.data[block.num_ord_values :] - - for var in range(block.no_variables): - max_var = block.no_variables - if var == 0: - name = "y" - else: - name = "y" + str(var) - data_array_slice = data_array[var::max_var] - data_dict[name] = data_array_slice - setattr(block, name, data_dict[name]) - - -# THIS DOESN'T WORK SO FAR!! -class VamasParserIrregular(VamasParser): - """Parser for .vms files of type IRREGULAR""" - - def _parse_norm_block(self): - """ - Use this method when the NORM keyword is present. - - Returns - ------- - block : vamas.Block object. - A block represents one spectrum with its metadata. - - """ - # pylint: disable=too-many-statements - block = VamasBlock() - block.block_id = self.data.pop(0).strip() - block.sample_id = self.data.pop(0).strip() - block.year = int(self.data.pop(0).strip()) - block.month = int(self.data.pop(0).strip()) - block.day = int(self.data.pop(0).strip()) - block.hour = int(self.data.pop(0).strip()) - block.minute = int(self.data.pop(0).strip()) - block.second = int(self.data.pop(0).strip().split(".")[0]) - block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) - block.no_comment_lines = int(self.data.pop(0).strip()) - for _ in range(block.no_comment_lines): - block.comment_lines += [self.data.pop(0)] - block.technique = self.data.pop(0).strip() - for _ in range(int(self.header.nr_exp_var)): - block.exp_var_value = self.data.pop(0).strip() - block.source_label = self.data.pop(0).strip() - block.source_energy = float(self.data.pop(0).strip()) - block.unknown_1 = self.data.pop(0).strip() - block.unknown_2 = self.data.pop(0).strip() - block.unknown_3 = self.data.pop(0).strip() - block.source_analyzer_angle = self.data.pop(0).strip() - block.unknown_4 = self.data.pop(0).strip() - block.analyzer_mode = self.data.pop(0).strip() - block.resolution = float(self.data.pop(0).strip()) - block.magnification = self.data.pop(0).strip() - block.work_function = float(self.data.pop(0).strip()) - block.target_bias = float(self.data.pop(0).strip()) - block.analyzer_width_x = self.data.pop(0).strip() - block.analyzer_width_y = self.data.pop(0).strip() - block.analyzer_take_off_polar_angle = self.data.pop(0).strip() - block.analyzer_azimuth = self.data.pop(0).strip() - block.species_label = self.data.pop(0).strip() - block.transition_label = self.data.pop(0).strip() - block.particle_charge = self.data.pop(0).strip() - block.abscissa_label = self.data.pop(0).strip() - block.abscissa_units = self.data.pop(0).strip() - block.abscissa_start = float(self.data.pop(0).strip()) - block.abscissa_step = float(self.data.pop(0).strip()) - block.no_variables = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "variable_label_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - name = "variable_units_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - block.signal_mode = self.data.pop(0).strip() - block.dwell_time = float(self.data.pop(0).strip()) - block.no_scans = int(self.data.pop(0).strip()) - block.time_correction = self.data.pop(0).strip() - block.sample_angle_tilt = float(self.data.pop(0).strip()) - block.sample_tilt_azimuth = float(self.data.pop(0).strip()) - block.sample_rotation = float(self.data.pop(0).strip()) - block.no_additional_params = int(self.data.pop(0).strip()) - for param in range(block.no_additional_params): - name = "param_label_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_unit_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_value_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - block.num_ord_values = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "min_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) - name = "max_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) - - self._add_data_values(block) - return block - - def _parse_map_block(self): - """ - Use this method when the MAP keyword is present. - - Returns - ------- - block : vamas.Block object. - A block represents one spectrum with its metadata. - - """ - # pylint: disable=too-many-statements - block = VamasBlock() - block.block_id = self.data.pop(0).strip() - block.sample_id = self.data.pop(0).strip() - block.year = int(self.data.pop(0).strip()) - block.month = int(self.data.pop(0).strip()) - block.day = int(self.data.pop(0).strip()) - block.hour = int(self.data.pop(0).strip()) - block.minute = int(self.data.pop(0).strip()) - block.second = int(self.data.pop(0).strip()) - block.no_hrs_in_advance_of_gmt = int(self.data.pop(0).strip()) - block.no_comment_lines = int(self.data.pop(0).strip()) - for _ in range(block.no_comment_lines): - self.data.pop(0) - block.comment_lines += [self.data.pop(0)] - block.technique = self.data.pop(0).strip() - block.x_coord = self.data.pop(0).strip() - block.y_coord = self.data.pop(0).strip() - block.exp_var_value = self.data.pop(0).strip() - block.source_label = self.data.pop(0).strip() - block.source_energy = float(self.data.pop(0).strip()) - block.unknown_1 = self.data.pop(0).strip() - block.unknown_2 = self.data.pop(0).strip() - block.unknown_3 = self.data.pop(0).strip() - block.fov_x = self.data.pop(0).strip() - block.fov_y = self.data.pop(0).strip() - block.source_analyzer_angle = self.data.pop(0).strip() - block.unknown_4 = self.data.pop(0).strip() - block.analyzer_mode = self.data.pop(0).strip() - block.resolution = float(self.data.pop(0).strip()) - block.magnification = self.data.pop(0).strip() - block.work_function = float(self.data.pop(0).strip()) - block.target_bias = float(self.data.pop(0).strip()) - block.analyzer_width_x = self.data.pop(0).strip() - block.analyzer_width_y = self.data.pop(0).strip() - block.analyzer_take_off_polar_angle = self.data.pop(0).strip() - block.analyzer_azimuth = self.data.pop(0).strip() - block.species_label = self.data.pop(0).strip() - block.transition_label = self.data.pop(0).strip() - block.particle_charge = self.data.pop(0).strip() - block.abscissa_label = self.data.pop(0).strip() - block.abscissa_units = self.data.pop(0).strip() - block.abscissa_start = float(self.data.pop(0).strip()) - block.abscissa_step = float(self.data.pop(0).strip()) - block.no_variables = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "variable_label_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - name = "variable_units_" + str(var + 1) - setattr(block, name, self.data.pop(0).strip()) - block.signal_mode = self.data.pop(0).strip() - block.dwell_time = float(self.data.pop(0).strip()) - block.no_scans = int(self.data.pop(0).strip()) - block.time_correction = self.data.pop(0).strip() - block.sample_angle_tilt = float(self.data.pop(0).strip()) - block.sample_tilt_azimuth = float(self.data.pop(0).strip()) - block.sample_rotation = float(self.data.pop(0).strip()) - block.no_additional_params = int(self.data.pop(0).strip()) - for param in range(block.no_additional_params): - name = "param_label_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_unit_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - name = "param_value_" + str(param + 1) - setattr(block, name, self.data.pop(0)) - block.num_ord_values = int(self.data.pop(0).strip()) - for var in range(block.no_variables): - name = "min_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) - name = "max_ord_value_" + str(var + 1) - setattr(block, name, float(self.data.pop(0).strip())) - - self._add_data_values(block) - - return block + settings = { + "region": block.block_id, + "sample_name": block.sample_id, + "analysis_method": block.technique, + "source_label": block.source_label, + "excitation_energy": block.source_energy, + "source_analyzer_angle": block.source_analyzer_angle, + "scan_mode": block.analyzer_mode, + "pass_energy": block.resolution, + "magnification": block.magnification, + "work_function": block.work_function, + "target_bias": block.target_bias, + "analysis_width_x": block.analyzer_width_x, + "analysis_width_y": block.analyzer_width_y, + "analyzer_take_off_polar": block.analyzer_take_off_polar_angle, + "analyzer_take_off_azimuth": block.analyzer_azimuth, + "element": block.species_label, + "transition": block.transition_label, + "particle_charge": block.particle_charge, + "x_label": block.abscissa_label, + "x_units": block.abscissa_units, + "start_energy": block.abscissa_start, + "step_size": block.abscissa_step, + "y_labels_1": block.variable_label_1, + "y_units_1": block.variable_units_1, + "y_labels_2": block.variable_label_2, + "y_units_2": block.variable_units_2, + "signal_mode": block.signal_mode, + "dwell_time": block.dwell_time, + "time_correction": block.time_correction, + "sample_normal_polarangle_tilt": block.sample_angle_tilt, + "sample_tilt_azimuth": block.sample_tilt_azimuth, + "sample_rotation_angle": block.sample_rotation, + "n_values": int(block.num_ord_values / block.no_variables), + } + settings.update(header_dict) - def _add_data_values(self, block): - """Add data values to a Vamas data block.""" - data_dict = {} - start = float(block.abscissa_start) - step = float(block.abscissa_step) - num = int(block.num_ord_values / block.no_variables) - energy = [round(start + i * step, 2) for i in range(num)] + comment_dict = self.handle_block_comments(block.comment_lines) + settings.update(comment_dict) - if block.abscissa_label == "binding energy": - energy.reverse() + # Convert the native time format to the datetime string + # in the ISO 8601 format + tzinfo = datetime.timezone( + datetime.timedelta(hours=block.no_hrs_in_advance_of_gmt) + ) + try: + date_time = datetime.datetime( + block.year, + block.month, + block.day, + block.hour, + block.minute, + block.second, + tzinfo=tzinfo, + ) + except ValueError: + date_time = datetime.datetime.min - setattr(block, "x", energy) + data = {"x": block.x} + for var in range(int(block.no_variables)): + if var == 0: + key = "y" - for var in range(block.no_variables): - if var == 0: - name = "y" - else: - name = "y" + str(var) - data_dict[name] = [] + data["y"] = getattr(block, "y") - data_array = list(np.array(self.data[: block.num_ord_values], dtype=float)) + if block.variable_label_1 in ["Intensity", "counts"]: + y_cps = [np.round(y / block.dwell_time, 2) for y in block.y] + data["y_cps"] = y_cps - self.data = self.data[block.num_ord_values :] + else: + key = "y" + str(var) + data[key] = getattr(block, key) - for var in range(block.no_variables): - max_var = block.no_variables - if var == 0: - name = "y" - else: - name = "y" + str(var) - data_array_slice = data_array[var::max_var] - data_dict[name] = data_array_slice - setattr(block, name, data_dict[name]) + spec_dict = { + "time_stamp": date_time, + "group_name": group_name, + "group_id": group_id, + "spectrum_type": spectrum_type, + "spectrum_id": spectrum_id, + "scans": block.no_scans, + "data": data, + } + spec_dict.update(settings) + spectra += [spec_dict] + spectra = self._get_scan_numbers_for_spectra(spectra) -if __name__ == "__main__": - file = r"C:\Users\pielsticker\Lukas\FAIRMat\user_cases\Schumann_XPS_Catalysis\C2 Activated Vamas Files\CleanData-alphaII VOPO4 C2 BC4316.vms" - parser = VamasParserRegular() - d = parser.parse_file(file) - d0 = d[0] + return spectra From 2cb9dc9ece4d9be292a049e375db6a8919d14206 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 8 Mar 2024 16:51:07 +0100 Subject: [PATCH 31/41] improve static typing --- pynxtools_xps/vms/vamas.py | 99 +++++++++++++++------------ pynxtools_xps/vms/vamas_data_model.py | 64 ++++++++--------- 2 files changed, 87 insertions(+), 76 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index b3c1409e..92b16da5 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -22,7 +22,9 @@ import re from copy import deepcopy import datetime -from abc import ABC, abstractmethod +from pathlib import Path +from typing import Any, Dict, List, Union + from itertools import groupby import xarray as xr import numpy as np @@ -50,10 +52,10 @@ class VamasMapper(XPSMapper): config_file = "config_vms.json" def __init__(self): - self.file = None - self.parsers = [] + self.file: Union[str, Path] = "" + self.parsers: List[Any] = [] - self.units = { + self.units: dict = { "instrument/sample_normal_polarangle_tilt": "degree ", "instrument/sample_tilt_azimuth": "degree", "instrument/sample_rotation_angle": "degree", @@ -93,7 +95,7 @@ def construct_data(self): # pylint: disable=duplicate-code spectra = deepcopy(self.raw_data) - self._xps_dict["data"]: dict = {} + self._xps_dict["data"]: Dict[str, Any] = {} key_map = { "user": [], @@ -158,7 +160,9 @@ def construct_data(self): for spectrum in spectra: self._update_xps_dict_with_spectrum(spectrum, key_map) - def _update_xps_dict_with_spectrum(self, spectrum, key_map): + def _update_xps_dict_with_spectrum( + self, spectrum: Dict[str, Any], key_map: Dict[str, str] + ): """Map one spectrum from raw data to NXmpes-ready dict.""" # pylint: disable=too-many-locals,duplicate-code group_parent = f'{self._root_path}/Group_{spectrum["group_name"]}' @@ -166,7 +170,7 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): instrument_parent = f"{region_parent}/instrument" analyser_parent = f"{instrument_parent}/analyser" - path_map = { + path_map: Dict[str, str] = { "user": f"{region_parent}/user", "instrument": f"{instrument_parent}", "source": f"{instrument_parent}/source", @@ -197,14 +201,14 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): self._xps_dict[f"{root}/{mpes_key}/@units"] = units # Write process data - process_key_map = { + process_key_map: Dict[str, List[str]] = { "energy_referencing": ["alignments"], "peak_fitting": ["regions", "components"], } - for grouping, spectrum_keys in process_key_map.items(): + for grouping, process_key_list in process_key_map.items(): root = path_map[str(grouping)] - for spectrum_key in spectrum_keys: + for spectrum_key in process_key_list: try: processes = spectrum[spectrum_key] for i, process in enumerate(processes): @@ -265,7 +269,7 @@ def _update_xps_dict_with_spectrum(self, spectrum, key_map): if spectrum_key not in used_keys: self._xps_dict[f"{region_parent}/{spectrum_key}"] = value - def _get_units_for_key(self, unit_key): + def _get_units_for_key(self, unit_key: str): """ Get correct units for a given key. @@ -302,10 +306,10 @@ def __init__(self): vamas attribute keys, which are used, depending on how the vamas file is formatted. """ - self.data = [] + self.data: List[str] = [] self.header = VamasHeader() - self.blocks = [] + self.blocks: List[VamasBlock] = [] self.attrs = { "common_header": [ @@ -472,7 +476,7 @@ def __init__(self): ], } - def parse_file(self, file): + def parse_file(self, file: Union[str, Path]): """Parse the vamas file into a list of dictionaries. Parameters @@ -485,7 +489,7 @@ def parse_file(self, file): self._parse_blocks() return self.build_list() - def _read_lines(self, file): + def _read_lines(self, file: Union[str, Path]): """Read in vamas text file.""" with open(file, "rb") as vms_file: for line in vms_file: @@ -521,7 +525,10 @@ def _parse_header(self): if attr == "nr_exp_var": self._add_exp_var() + self.header.validate_types() + def _add_exp_var(self): + """Add experimental variable to header.""" for _ in range(int(self.header.nr_exp_var)): for attr in self.attrs["exp_var"]: setattr(self.header, attr, self.data.pop(0).strip()) @@ -570,20 +577,20 @@ def _parse_norm_block(self): block.unknown_1 = self.data.pop(0).strip() block.unknown_2 = self.data.pop(0).strip() block.unknown_3 = self.data.pop(0).strip() - block.source_analyzer_angle = self.data.pop(0).strip() + block.source_analyzer_angle = float(self.data.pop(0).strip()) block.unknown_4 = self.data.pop(0).strip() block.analyzer_mode = self.data.pop(0).strip() block.resolution = float(self.data.pop(0).strip()) block.magnification = self.data.pop(0).strip() block.work_function = float(self.data.pop(0).strip()) block.target_bias = float(self.data.pop(0).strip()) - block.analyzer_width_x = self.data.pop(0).strip() - block.analyzer_width_y = self.data.pop(0).strip() - block.analyzer_take_off_polar_angle = self.data.pop(0).strip() - block.analyzer_azimuth = self.data.pop(0).strip() + block.analyzer_width_x = float(self.data.pop(0).strip()) + block.analyzer_width_y = float(self.data.pop(0).strip()) + block.analyzer_take_off_polar_angle = float(self.data.pop(0).strip()) + block.analyzer_azimuth = float(self.data.pop(0).strip()) block.species_label = self.data.pop(0).strip() block.transition_label = self.data.pop(0).strip() - block.particle_charge = self.data.pop(0).strip() + block.particle_charge = int(self.data.pop(0).strip()) if self.header.scan_mode == "REGULAR": block.abscissa_label = self.data.pop(0).strip() @@ -633,9 +640,11 @@ def _parse_norm_block(self): setattr(block, name, float(self.data.pop(0).strip())) self._add_data_values(block) + + block.validate_types() return block - def _parse_map_block(self, regular: bool = True): + def _parse_map_block(self): """ Use this method when the MAP keyword is present. @@ -671,20 +680,20 @@ def _parse_map_block(self, regular: bool = True): block.unknown_3 = self.data.pop(0).strip() block.fov_x = self.data.pop(0).strip() block.fov_y = self.data.pop(0).strip() - block.source_analyzer_angle = self.data.pop(0).strip() + block.source_analyzer_angle = float(self.data.pop(0).strip()) block.unknown_4 = self.data.pop(0).strip() block.analyzer_mode = self.data.pop(0).strip() block.resolution = float(self.data.pop(0).strip()) block.magnification = self.data.pop(0).strip() block.work_function = float(self.data.pop(0).strip()) block.target_bias = float(self.data.pop(0).strip()) - block.analyzer_width_x = self.data.pop(0).strip() - block.analyzer_width_y = self.data.pop(0).strip() - block.analyzer_take_off_polar_angle = self.data.pop(0).strip() - block.analyzer_azimuth = self.data.pop(0).strip() + block.analyzer_width_x = float(self.data.pop(0).strip()) + block.analyzer_width_y = float(self.data.pop(0).strip()) + block.analyzer_take_off_polar_angle = float(self.data.pop(0).strip()) + block.analyzer_azimuth = float(self.data.pop(0).strip()) block.species_label = self.data.pop(0).strip() block.transition_label = self.data.pop(0).strip() - block.particle_charge = self.data.pop(0).strip() + block.particle_charge = int(self.data.pop(0).strip()) if self.header.scan_mode == "REGULAR": block.abscissa_label = self.data.pop(0).strip() @@ -737,16 +746,17 @@ def _parse_map_block(self, regular: bool = True): return block - def _add_data_values(self, block): + def _add_data_values(self, block: VamasBlock): """Add data values to a Vamas data block.""" if self.header.scan_mode == "REGULAR": self._add_regular_data(block) elif self.header.scan_mode == "IRREGULAR": self._add_irregular_data(block) - def _add_regular_data(self, block): + def _add_regular_data(self, block: VamasBlock): """Parse data with regularly spaced energy axis.""" - data_dict = {} + data_dict: Dict[str, List] = {} + start = float(block.abscissa_start) step = float(block.abscissa_step) num = int(block.num_ord_values / block.no_variables) @@ -778,19 +788,19 @@ def _add_regular_data(self, block): data_dict[name] = data_array_slice setattr(block, name, data_dict[name]) - def _add_irregular_data(self, block): + def _add_irregular_data(self, block: VamasBlock): """Parse data with regularly spaced energy axis.""" - data_dict = {} + data_dict: Dict[str, List] = {} block_data = list(np.array(self.data[: block.num_ord_values], dtype=float)) energy = block_data[:: block.no_variables + 1] if block.abscissa_label == "binding energy": energy.reverse() - block.x = energy - block.abscissa_start = min(energy) - block.abscissa_stop = max(energy) - block.abscissa_step = get_minimal_step(energy) + + setattr(block, "x", energy) + block.abscissa_start = float(min(energy)) + block.abscissa_step = float(get_minimal_step(energy)) for var in range(block.no_variables): if var == 0: @@ -810,10 +820,11 @@ def _add_irregular_data(self, block): self.data = self.data[block.num_ord_values + block.no_variables :] - def _get_scan_numbers_for_spectra(self, spectra): + def _get_scan_numbers_for_spectra(self, spectra: List[Dict]): """ - For a flat list of spectra, groupby group name and spectrum - type and iteratively give them scan numbers. + For a flat list of spectra dictionaries, group the spectra + by group name and spectrum type and iteratively give them + scan numbers. Parameters ---------- @@ -845,7 +856,7 @@ def _get_scan_numbers_for_spectra(self, spectra): return flattened_spectra - def handle_header_comments(self, comment_list): + def handle_header_comments(self, comment_list: List[str]): """Handle comments (incl. Casa info) for the header.""" comments = {} @@ -871,7 +882,7 @@ def handle_header_comments(self, comment_list): end_index = [ i for i, line in enumerate(comment_list) if "EOFH" in line ][0] - special_comments = comment_list[index : end_index + 1] + special_comments = comment_list[index : end_index + 1] # type: ignore[assignment] del comment_list[index : end_index + 1] comments.update(handle_func(special_comments)) @@ -900,7 +911,7 @@ def _handle_prodigy_header(self, comment_line: str): return {"prodigy_version": comment_line.split("Version")[1].strip()} # ============================================================================= - # def _handle_phi_header(self, comment_list): + # def _handle_phi_header(self, comment_list: List[str]): # """Get metadta from Phi system.""" # phi_parser = PhiParser() # phi_parser.parse_header_into_metadata(comment_list) @@ -919,7 +930,7 @@ def _handle_prodigy_header(self, comment_line: str): # return phi_comments # ============================================================================= - def handle_block_comments(self, comment_list): + def handle_block_comments(self, comment_list: List[str]): """Handle comments (incl. Casa fitting) for each block.""" comments = {} diff --git a/pynxtools_xps/vms/vamas_data_model.py b/pynxtools_xps/vms/vamas_data_model.py index e62a69ab..75d7adf3 100644 --- a/pynxtools_xps/vms/vamas_data_model.py +++ b/pynxtools_xps/vms/vamas_data_model.py @@ -57,72 +57,72 @@ class VamasBlock(XpsDataclass): block_id: str = "" sample_id: str = "" - year: str = "" - month: str = "" - day: str = "" - hour: str = "" - minute: str = "" - second: str = "" - no_hrs_in_advance_of_gmt: str = "0" - no_comment_lines: str = "" + year: int = 0 + month: int = 0 + day: int = 0 + hour: int = 0 + minute: int = 0 + second: int = 0 + no_hrs_in_advance_of_gmt: int = 0 + no_comment_lines: int = 0 # This list should contain one element per for each # line in the comment block comment_lines: list = field(default_factory=list) technique: str = "" exp_var_value: str = "" source_label: str = "" - source_energy: str = "" + source_energy: float = 0.0 unknown_1: str = "0" unknown_2: str = "0" unknown_3: str = "0" - source_analyzer_angle: str = "" + source_analyzer_angle: float = 0.0 unknown_4: str = "180" analyzer_mode: str = "" - resolution: str = "" + resolution: float = 0.0 magnification: str = "1" - work_function: str = "" - target_bias: str = "0" + work_function: float = 0.0 + target_bias: float = 0.0 # analyser slit length divided by the magnification # of the analyser transfer lens - analyzer_width_x: str = "0" - analyzer_width_y: str = "0" + analyzer_width_x: float = 0.0 + analyzer_width_y: float = 0.0 # degrees from upward z-direction, # defined by the sample stage - analyzer_take_off_polar_angle: str = "0" - analyzer_azimuth: str = "0" + analyzer_take_off_polar_angle: float = 0.0 + analyzer_azimuth: float = 0.0 species_label: str = "" transition_label: str = "" - particle_charge: str = "-1" + particle_charge: int = -1 abscissa_label: str = "kinetic energy" abscissa_units: str = "eV" - abscissa_start: str = "" - abscissa_step: str = "" - no_variables: str = "2" + abscissa_start: float = 0.0 + abscissa_step: float = 0.0 + no_variables: int = 2 variable_label_1: str = "counts" variable_units_1: str = "d" variable_label_2: str = "Transmission" variable_units_2: str = "d" signal_mode: str = "pulse counting" - dwell_time: str = "" - no_scans: str = "" + dwell_time: float = 0.0 + no_scans: int = 0 time_correction: str = "0" # degrees from upward z-direction, # defined by the sample stage - sample_angle_tilt: str = "0" + sample_angle_tilt: float = 0.0 # degrees clockwise from the y-direction towards the # operator, defined by the sample stage - sample_tilt_azimuth: str = "0" - sample_rotation: str = "0" - no_additional_params: str = "2" + sample_tilt_azimuth: float = 0.0 + sample_rotation: float = 0.0 + no_additional_params: int = 2 param_label_1: str = "ESCAPE DEPTH TYPE" param_unit_1: str = "d" param_value_1: str = "0" param_label_2: str = "MFP Exponent" param_unit_2: str = "d" param_value_2: str = "0" - num_ord_values: str = "" - min_ord_value_1: str = "" - max_ord_value_1: str = "" - min_ord_value_2: str = "" - max_ord_value_2: str = "" + num_ord_values: int = 0 + min_ord_value_1: float = 0.0 + max_ord_value_1: float = 0.0 + min_ord_value_2: float = 0.0 + max_ord_value_2: float = 0.0 data_string: str = "" From dc153d53a079fd6143ca830791955462a24ce8c3 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 8 Mar 2024 17:02:19 +0100 Subject: [PATCH 32/41] small fix to irregular parsing --- pynxtools_xps/vms/vamas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index 92b16da5..e1902b44 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -818,7 +818,7 @@ def _add_irregular_data(self, block: VamasBlock): data_dict[name] = data_array_slice setattr(block, name, data_dict[name]) - self.data = self.data[block.num_ord_values + block.no_variables :] + self.data = self.data[block.num_ord_values :] # + block.no_variables :] def _get_scan_numbers_for_spectra(self, spectra: List[Dict]): """ From 1d2559a57f2fa1bff2c968c9d1fe5022f3650a93 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 8 Mar 2024 17:03:03 +0100 Subject: [PATCH 33/41] remove unneeded comments --- pynxtools_xps/vms/vamas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index e1902b44..46e5d29e 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -818,7 +818,7 @@ def _add_irregular_data(self, block: VamasBlock): data_dict[name] = data_array_slice setattr(block, name, data_dict[name]) - self.data = self.data[block.num_ord_values :] # + block.no_variables :] + self.data = self.data[block.num_ord_values :] def _get_scan_numbers_for_spectra(self, spectra: List[Dict]): """ From 3380ad437af3dd6f3158ef4e80bea3eca64cf2d0 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Thu, 14 Mar 2024 18:11:57 +0100 Subject: [PATCH 34/41] fix static typing --- pynxtools_xps/reader_utils.py | 8 +++--- pynxtools_xps/vms/vamas.py | 5 ++-- tests/test_reader.py | 49 +++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/pynxtools_xps/reader_utils.py b/pynxtools_xps/reader_utils.py index 48463b84..f8208c52 100644 --- a/pynxtools_xps/reader_utils.py +++ b/pynxtools_xps/reader_utils.py @@ -19,6 +19,8 @@ # import re from abc import ABC, abstractmethod +from typing import Any, Dict, List, Union +from pathlib import Path from scipy.interpolate import interp1d import numpy as np @@ -50,9 +52,9 @@ class XPSMapper(ABC): """Abstract base class from mapping from a parser to NXmpes template""" def __init__(self): - self.file = None - self.raw_data: list = [] - self._xps_dict: dict = {} + self.file: Union[str, Path] = "" + self.raw_data: List[str] = [] + self._xps_dict: Dict[str, Any] = {} self._root_path = "/ENTRY[entry]" self.parser = None diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index 46e5d29e..9a86439e 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -52,7 +52,6 @@ class VamasMapper(XPSMapper): config_file = "config_vms.json" def __init__(self): - self.file: Union[str, Path] = "" self.parsers: List[Any] = [] self.units: dict = { @@ -190,7 +189,7 @@ def _update_xps_dict_with_spectrum( used_keys = [] for grouping, spectrum_keys in key_map.items(): - root = path_map[str(grouping)] + root = path_map[grouping] for spectrum_key in spectrum_keys: mpes_key = spectrum_key.rsplit(" ", 1)[0] self._xps_dict[f"{root}/{mpes_key}"] = spectrum[spectrum_key] @@ -207,7 +206,7 @@ def _update_xps_dict_with_spectrum( } for grouping, process_key_list in process_key_map.items(): - root = path_map[str(grouping)] + root = path_map[grouping] for spectrum_key in process_key_list: try: processes = spectrum[spectrum_key] diff --git a/tests/test_reader.py b/tests/test_reader.py index 1be0a18d..70326871 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -13,6 +13,20 @@ from pynxtools.nexus.nxdl_utils import get_nexus_definitions_path from pynxtools_xps.reader import XPSReader +# from pynxtools_xps.phi.spe_pro_phi import MapperPhi +from pynxtools_xps.sle.sle_specs import SleMapperSpecs + +# from pynxtools_xps.slh.slh_specs import SlhMapperSpecs +from pynxtools_xps.txt.txt_scienta import TxtMapperScienta + +# from pynxtools_xps.txt.txt_specs import TxtMapperSpecs +from pynxtools_xps.txt.txt_vamas_export import ( + TxtMapperVamasExport, +) +from pynxtools_xps.vms.vamas import VamasMapper +from pynxtools_xps.xy.xy_specs import XyMapperSpecs +from pynxtools_xps.xml.xml_specs import XmlMapperSpecs + def test_example_data(): """ @@ -45,3 +59,38 @@ def test_example_data(): assert isinstance(read_data, Template) assert validate_data_dict(template, read_data, root) + + +def test_vms_mapper(): + mapper = VamasMapper + data_dir = os.path.join(os.path.dirname(__file__), "data", "vms") + + files_and_keys = { + "EX889_S1110_MgFe2O4_spent_irregular": { + "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Survey/scan_mode": "REGULAR", + "data['2 S1110, UHV, RT, Epass = 20 eV__MgKLL_1']['cycle0']": 1351, + }, + "EX889_S1110_MgFe2O4_spent_irregular": { + "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Survey/scan_mode": "IRREGULAR", + "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Fe2p/instrument/analyser/energydispersion/scan_mode": "FixedAnalyserTransmission", + "data['2 S1110, UHV, RT, Epass = 20 eV__Fe3s-Si2p-Mg2s']['cycle0']": 761, + }, + } + + # (C["benz"], "20240122_SBenz_102_20240122_SBenz_SnO2_10nm.vms"), + # (r"C:\Users\pielsticker\Lukas\MPI-CEC\Projects\deepxps\RUB MDI\example_spectra_Florian\Co", "Co 2p 0008751 M1.vms"), + # (C["pielst"], C["EX889"], "vms", f"{C['EX889']}_regular.vms"), + ((C["pielst"], C["EX889"], "vms", f"{C['EX889']}_irregular.vms"),) + # (C["schu"], "CleanData-alphaII VOPO4 C2 BC4316.vms"), + # (C["pielst"], C["EX889"], "vms", "d_reg.vms"), + ((C["pielst"], C["EX889"], "vms", "d_irreg.vms"),) + + for vms_file in os.listdir(data_dir): + data = mapper.parse_file(file=file) + + +for k, v in d.items(): + if isinstance(v, str): + # print(k) + if "REG" in v: + print(k) From 2d825f0ae41c4af0edeaa112d265a5adf13e54b4 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 15 Mar 2024 10:38:33 +0100 Subject: [PATCH 35/41] rebase to main --- pynxtools_xps/config/config_vms.json | 2 +- tests/data/vms/eln_data.yaml | 147 ++ tests/data/vms/regular.vms | 2798 ++++++++++++++++++++++++++ tests/test_reader.py | 81 +- 4 files changed, 2990 insertions(+), 38 deletions(-) create mode 100644 tests/data/vms/eln_data.yaml create mode 100644 tests/data/vms/regular.vms diff --git a/pynxtools_xps/config/config_vms.json b/pynxtools_xps/config/config_vms.json index ecbefdfa..cae9d774 100644 --- a/pynxtools_xps/config/config_vms.json +++ b/pynxtools_xps/config/config_vms.json @@ -284,4 +284,4 @@ "@energy_indices":"None", "@energy_depends":"None" } - } \ No newline at end of file + } diff --git a/tests/data/vms/eln_data.yaml b/tests/data/vms/eln_data.yaml new file mode 100644 index 00000000..54475cbb --- /dev/null +++ b/tests/data/vms/eln_data.yaml @@ -0,0 +1,147 @@ +definition: + value: NXmpes + version: 1.0 +title: XPS Experiment +start_time: 2022-04-08T11:47:02.0200Z +end_time: 2022-04-08T12:32:06.0200Z +experiment_institution: BESSY II +program_name: SpecsLab 2 +user: + name: Lukas Pielsticker + email: lukas.pielsticker@cec.mpg.de +instrument: + device_information: + vendor: SPECS GmbH + model: XPS setup + identifier: null + energy_resolution: + type: calibrated + resolution: + value: 0.2 + unit: eV + source_probe: + type: Synchrotron X-ray Source + probe: x-ray + device_information: + vendor: null + model: null + identifier: null + beam_probe: + distance: + value: 0.0 + unit: mm + analyser: + description: hemispherical + name: PHOIBOS 150 + device_information: + vendor: SPECS GmbH + model: PHOIBOS 150 + identifier: null + collectioncolumn: + scheme: angular dispersive + device_information: + vendor: null + model: null + identifier: null + energydispersion: + scheme: hemispherical + entrance_slit: unknown + energy_scan_mode: fixed_analyser_transmission + diameter: + unit: mm + value: 150 + device_information: + vendor: null + model: null + identifier: null + detector: + amplifier_type: channeltron + detector_type: Multi-anode + manipulator: + device_information: + vendor: SPECS GmbH + model: 5-axis manipulator + identifier: null + temperature_sensor: + name: type K thermocouple + measurement: temperature + attached_to: sample + type: type K thermocouple + value: + value: 298.0 + unit: K + sample_heater: + name: Coherent Compact Evolution IR Diode LASER (DILAS) + physical_quantity: temperature + type: IR diode laser + heater_power: + value: 0.0 + unit: W + pid: + setpoint: + value: 298.0 + unit: K + cryostat: + name: null + physical_quantity: null + type: null + pid: + setpoint: null + drain_current_amperemeter: + name: Amperemeter 1.0 + measurement: current + type: wire + value: + value: 0.0 + unit: A + sample_bias_voltmeter: + name: XPS sample voltmeter + measurement: voltage + attached_to: sample + type: oscilloscope + value: + value: 0.0 + unit: V + sample_bias_potentiostat: + name: XPS sample potentiostat + physical_quantity: voltage + type: potentiostat + pid: + setpoint: + value: 0.0 + unit: V + pressure_gauge: + name: Atmion + measurement: pressure + type: hot-filament ionization gauge + value: + value: 0.000000001 + unit: mbar + value_log: + value: + value: null + unit: null + flood_gun: + name: FG 22/35 + physical_quantity: current + type: low energy electron source + current: + value: 0.0 + unit: A + current_log: + value: + value: null + unit: null +sample: + description: A polymer material called PBTTT with chemical name poly[2,5-bis(3-dodecylthiophen-2-yl)thieno[3,2-b]thiophene]. + name: Test + substance: + molecular_formula_hill: (C42H62S4)n + situation: vacuum + sample_history: + sample_preparation: + start_time: 2022-04-08T11:02:38.0200Z + end_time: 2022-04-08T11:06:42.200Z + description: From third party + method: null + \ No newline at end of file diff --git a/tests/data/vms/regular.vms b/tests/data/vms/regular.vms new file mode 100644 index 00000000..dd9f742d --- /dev/null +++ b/tests/data/vms/regular.vms @@ -0,0 +1,2798 @@ +VAMAS Surface Chemical Analysis Standard Data Transfer Format 1988 May 4 +Not Specified +Not Specified +Not Specified +Not Specified +5 +Casa Info Follows CasaXPS Version 2.3.25PR1.0 +0 +Created by SpecsLab Prodigy, Version 4.100.1-r111001 +SourceAnalyserAngle: Not Specified +CasaRowLabel:1 as-loaded +NORM +REGULAR +0 +1 +Exp Variable +d +0 +0 +0 +0 +1 +Survey +1 as-loaded +2023 +8 +24 +14 +19 +47 +0 +14 +Casa Info Follows +0 +0 +0 +0 +File = D:/OwnCloud/Project data/FAIRmat/export test/sle/EX889_S1110_MgFe2O4_spent.sle +Group = 1 as-loaded +First of group = 1 +Spectrum ID = 20 +Analyzer lens = LargeArea:1.5kV +Analyzer slit = 4:7x20c\C:mesh +Scan mode = FixedAnalyzerTransmission +Kinetic energy start = 136.61 +C:\Users\pielsticker\Lukas\FAIRMat\user_cases\Pielsticker_XPS_MPI-CEC\EX889_S1110_MgFe2O4_spent\vms\EX889_S1110_MgFe2O4_spent_regular.vms +XPS +0 +Al +1486.61 +0 +0 +0 +54.5 +180 +FAT +100 +1 +4.1082 +0 +0 +0 +0 +0 +Survey + +-1 +kinetic energy +eV +136.61 +1 +2 +counts +d +Transmission +d +pulse counting +0.1 +1 +0 +0 +0 +0 +2 +ESCAPE DEPTH TYPE +d +1 +MFP Exponent +d +0 +2702 +18.1529 +10836.6 +23.5611 +78.8103 +1559.87 +78.8103 +1586.79 +78.5146 +1565.15 +78.2222 +1532.13 +77.933 +1579.34 +77.647 +1566.2 +77.3642 +1559.9 +77.0844 +1575.89 +76.8076 +1568.17 +76.5338 +1596.81 +76.2628 +1584.46 +75.9948 +1532.83 +75.7295 +1554.1 +75.467 +1535.59 +75.2073 +1553.13 +74.9501 +1583.11 +74.6956 +1562.84 +74.4437 +1564.34 +74.1943 +1564.92 +73.9474 +1550.85 +73.703 +1616.87 +73.4609 +1678.37 +73.2213 +1669.65 +72.9839 +1724.2 +72.7489 +1622.54 +72.5161 +1651.86 +72.2855 +1638.19 +72.0571 +1695.62 +71.8309 +1650.32 +71.6068 +1707.48 +71.3847 +1660.89 +71.1647 +1668.98 +70.9468 +1626.16 +70.7308 +1626.05 +70.5168 +1598.67 +70.3047 +1594.31 +70.0945 +1557.62 +69.8862 +1574.93 +69.6798 +1530.71 +69.4751 +1508.85 +69.2723 +1558.39 +69.0712 +1591.39 +68.8719 +1718.53 +68.6743 +1738.14 +68.4783 +2095.68 +68.2841 +2671.96 +68.0914 +2757.07 +67.9004 +2274.45 +67.711 +1750.86 +67.5232 +1565.47 +67.337 +1511.87 +67.1522 +1556.88 +66.969 +1534.57 +66.7873 +1530.3 +66.607 +1493.8 +66.4282 +1505.46 +66.2508 +1497.65 +66.0749 +1520.5 +65.9003 +1530.62 +65.7271 +1577.25 +65.5553 +1574.41 +65.3848 +1559.99 +65.2156 +1597.34 +65.0477 +1569.35 +64.8812 +1590.92 +64.7159 +1619.86 +64.5518 +1596.69 +64.389 +1548.91 +64.2274 +1647.49 +64.0671 +1595.61 +63.9079 +1650.16 +63.7499 +1593.16 +63.5931 +1611.57 +63.4374 +1661.15 +63.2829 +1606.1 +63.1295 +1612.16 +62.9772 +1620.29 +62.8259 +1639.24 +62.6758 +1650.37 +62.5268 +1636.44 +62.3788 +1638.33 +62.2318 +1565.45 +62.0859 +1670.93 +61.941 +1658.31 +61.7972 +1705.44 +61.6543 +1644.22 +61.5124 +1642.88 +61.3715 +1635.96 +61.2315 +1703.59 +61.0925 +1678.18 +60.9544 +1653.29 +60.8173 +1655.99 +60.6811 +1739.67 +60.5458 +1733.78 +60.4114 +1696.45 +60.2779 +1723.66 +60.1453 +1718.75 +60.0135 +1768.57 +59.8826 +1741.39 +59.7526 +1734.81 +59.6234 +1774.56 +59.495 +1759.46 +59.3675 +1680.27 +59.2408 +1757.98 +59.1149 +1778.29 +58.9898 +1801.33 +58.8655 +1829.88 +58.7419 +1871.03 +58.6192 +1925.4 +58.4972 +1879.21 +58.3759 +1847.32 +58.2554 +1813.84 +58.1357 +1838.2 +58.0167 +1878.25 +57.8984 +1888.03 +57.7808 +1884.11 +57.664 +1929.41 +57.5479 +1952.14 +57.4324 +1950.57 +57.3177 +1900.39 +57.2036 +1872.67 +57.0902 +1907.94 +56.9775 +1966.75 +56.8655 +1986.06 +56.7541 +1956.3 +56.6433 +1894.49 +56.5332 +1911.66 +56.4238 +1936.65 +56.315 +1950.51 +56.2068 +1966.01 +56.0992 +1917.42 +55.9922 +1944.08 +55.8859 +1876.57 +55.7801 +1952.94 +55.675 +1935.77 +55.5704 +1912.69 +55.4665 +1987.9 +55.3631 +1919.75 +55.2603 +1874.3 +55.158 +1930.37 +55.0564 +1889.53 +54.9553 +1891.26 +54.8547 +1968.67 +54.7547 +2031.15 +54.6552 +2012.75 +54.5563 +2001.53 +54.4579 +1967.13 +54.3601 +2038.89 +54.2627 +2003.47 +54.1659 +1939.11 +54.0696 +2030.01 +53.9738 +2107.98 +53.8786 +2057.44 +53.7838 +2059.59 +53.6895 +2047.33 +53.5957 +2025.78 +53.5024 +2059.42 +53.4096 +2101.8 +53.3173 +2082.68 +53.2255 +2091.96 +53.1341 +2114.61 +53.0432 +2021.11 +52.9528 +2087.39 +52.8628 +2118.41 +52.7733 +2092.11 +52.6842 +2069.75 +52.5956 +2141.01 +52.5074 +2098.73 +52.4197 +2112.32 +52.3324 +2128.38 +52.2455 +2174.64 +52.1591 +2207.51 +52.0731 +2157 +51.9875 +2145.98 +51.9024 +2140.12 +51.8176 +2148.66 +51.7333 +2193.11 +51.6494 +2158.89 +51.5659 +2154.73 +51.4828 +2360.73 +51.4001 +2290.34 +51.3178 +2251.53 +51.2358 +2209.06 +51.1543 +2186.3 +51.0732 +2243.28 +50.9924 +2302.04 +50.9121 +2275.91 +50.8321 +2316.28 +50.7525 +2278.56 +50.6732 +2287.64 +50.5944 +2313.54 +50.5159 +2324.13 +50.4377 +2340.14 +50.36 +2377.54 +50.2825 +2353.57 +50.2055 +2339.97 +50.1288 +2358.76 +50.0524 +2385.94 +49.9764 +2383.74 +49.9007 +2357.84 +49.8254 +2357.46 +49.7504 +2334.73 +49.6758 +2355.73 +49.6015 +2352.54 +49.5275 +2391.19 +49.4539 +2394.41 +49.3805 +2426.68 +49.3076 +2447.03 +49.2349 +2450.6 +49.1625 +2428.4 +49.0905 +2411.46 +49.0188 +2477.62 +48.9474 +2473.43 +48.8763 +2452.09 +48.8055 +2458.41 +48.735 +2510.02 +48.6649 +2466.94 +48.595 +2516.35 +48.5254 +2493.71 +48.4561 +2558.59 +48.3872 +2514.47 +48.3185 +2501.45 +48.2501 +2542.46 +48.182 +2544.79 +48.1142 +2564.02 +48.0466 +2613.64 +47.9794 +2573.06 +47.9124 +2611.51 +47.8458 +2599.39 +47.7793 +2614.03 +47.7132 +2645.83 +47.6474 +2569.28 +47.5818 +2594.86 +47.5165 +2638.49 +47.4514 +2615.08 +47.3866 +2618.4 +47.3221 +2688.75 +47.2579 +2704.86 +47.1939 +2645.78 +47.1301 +2674.26 +47.0667 +2668.06 +47.0035 +2687.27 +46.9405 +2711.88 +46.8778 +2749.15 +46.8153 +2683.49 +46.7531 +2716.97 +46.6911 +2723.18 +46.6294 +2788.5 +46.5679 +2761.46 +46.5067 +2774.06 +46.4457 +2757.48 +46.385 +2776.95 +46.3244 +2731.45 +46.2642 +2816.46 +46.2041 +2821.52 +46.1443 +2777.24 +46.0847 +2794.63 +46.0254 +2807.2 +45.9663 +2898.61 +45.9074 +2864.09 +45.8487 +2793.14 +45.7903 +2780.06 +45.732 +2913.25 +45.674 +2866.51 +45.6163 +2872.53 +45.5587 +2913.63 +45.5014 +2923.84 +45.4442 +2936.52 +45.3873 +2905.63 +45.3306 +2949.59 +45.2741 +2895.54 +45.2179 +2959.7 +45.1618 +2919.39 +45.1059 +2932.11 +45.0503 +2977.59 +44.9948 +2937.74 +44.9396 +2952.96 +44.8846 +2982.81 +44.8297 +3001.82 +44.7751 +2983.4 +44.7206 +2999.63 +44.6664 +3037.31 +44.6124 +3031.46 +44.5585 +3108.65 +44.5049 +3017.8 +44.4514 +3025.32 +44.3981 +3082.05 +44.3451 +3073.5 +44.2922 +3127.1 +44.2395 +3132.37 +44.187 +3085.73 +44.1346 +3107.65 +44.0825 +3025.26 +44.0306 +3143.23 +43.9788 +3101.6 +43.9272 +3218.56 +43.8758 +3186.14 +43.8246 +3190.59 +43.7735 +3214.04 +43.7226 +3188.25 +43.672 +3180.41 +43.6214 +3233.96 +43.5711 +3195.36 +43.5209 +3289.71 +43.4709 +3245.65 +43.4211 +3256.15 +43.3715 +3286.51 +43.322 +3273.36 +43.2727 +3234.52 +43.2235 +3254.16 +43.1745 +3307.83 +43.1257 +3288.27 +43.0771 +3282.41 +43.0286 +3214.57 +42.9803 +3387.93 +42.9321 +3394.45 +42.8841 +3346.38 +42.8363 +3399.57 +42.7886 +3432.17 +42.7411 +3371.22 +42.6937 +3382.29 +42.6465 +3519.85 +42.5995 +3465.57 +42.5526 +3481.13 +42.5059 +3400.96 +42.4593 +3485.9 +42.4129 +3500.51 +42.3666 +3434.69 +42.3205 +3445.45 +42.2745 +3531.13 +42.2287 +3607.43 +42.183 +3658.26 +42.1374 +3647.8 +42.0921 +3644.84 +42.0468 +3680.27 +42.0017 +3771.88 +41.9568 +3753.18 +41.912 +3648.12 +41.8673 +3667.52 +41.8228 +3636.53 +41.7784 +3629.03 +41.7342 +3631.38 +41.6901 +3666.16 +41.6462 +3791.26 +41.6024 +3763.01 +41.5587 +3777.31 +41.5151 +3759.79 +41.4717 +3811.61 +41.4285 +3882.98 +41.3853 +3948.47 +41.3423 +3862.6 +41.2995 +3914.22 +41.2567 +4009.02 +41.2141 +3920.11 +41.1717 +3957.47 +41.1293 +3865.42 +41.0871 +3785.27 +41.0451 +3872.52 +41.0031 +3753.65 +40.9613 +3844.6 +40.9196 +3855.37 +40.878 +3794.87 +40.8366 +3860.29 +40.7953 +3747.79 +40.7541 +3715.49 +40.713 +3745.65 +40.6721 +3869.44 +40.6313 +3950.49 +40.5906 +3970.95 +40.55 +4096.81 +40.5096 +4257.04 +40.4692 +4459.86 +40.429 +4692.13 +40.389 +4721.97 +40.349 +4464.4 +40.3091 +4262.12 +40.2694 +4142.39 +40.2298 +4056.91 +40.1903 +3928.01 +40.1509 +3882.82 +40.1116 +3866.38 +40.0725 +3725.36 +40.0334 +3765.33 +39.9945 +3709.83 +39.9557 +3562.89 +39.917 +3621.55 +39.8784 +3597.42 +39.84 +3596.66 +39.8016 +3638.07 +39.7633 +3611.19 +39.7252 +3579.1 +39.6872 +3642.96 +39.6492 +3589.74 +39.6114 +3597.4 +39.5737 +3554.48 +39.5361 +3547.16 +39.4986 +3642.72 +39.4612 +3669.33 +39.424 +3693.42 +39.3868 +3673.08 +39.3497 +3675.11 +39.3127 +3588.19 +39.2759 +3692.67 +39.2391 +3710.96 +39.2025 +3686.1 +39.1659 +3760.52 +39.1295 +3707.84 +39.0931 +3779.49 +39.0569 +3761.04 +39.0207 +3718.59 +38.9847 +3684.06 +38.9487 +3748.66 +38.9129 +3819.79 +38.8771 +3825.54 +38.8415 +3782.95 +38.8059 +3816.27 +38.7705 +3817.34 +38.7351 +3767.79 +38.6999 +3835.76 +38.6647 +3831.35 +38.6296 +3846.04 +38.5946 +3861.49 +38.5598 +3881.65 +38.525 +3865.56 +38.4903 +3857.45 +38.4557 +3875.75 +38.4212 +3906.68 +38.3868 +3929.36 +38.3525 +3908.24 +38.3182 +3843.91 +38.2841 +3909.05 +38.25 +3815.29 +38.2161 +3854.63 +38.1822 +3872.94 +38.1485 +3955 +38.1148 +3942.5 +38.0812 +3929.13 +38.0477 +3966 +38.0142 +3988.06 +37.9809 +3945.92 +37.9477 +4036.63 +37.9145 +3940.43 +37.8814 +3911.4 +37.8485 +3944.21 +37.8156 +3989.48 +37.7828 +4059.45 +37.75 +4114.2 +37.7174 +4131.45 +37.6848 +4037.94 +37.6524 +4051.83 +37.62 +4080.58 +37.5877 +4003.13 +37.5554 +4093.51 +37.5233 +4172.74 +37.4912 +4121.38 +37.4593 +4036.65 +37.4274 +3995.45 +37.3956 +4060.18 +37.3638 +4155.04 +37.3322 +4117.42 +37.3006 +3990.85 +37.2691 +4000.41 +37.2377 +4041.35 +37.2064 +3870.38 +37.1751 +3778.99 +37.1439 +3710.41 +37.1129 +3790.6 +37.0818 +3844.2 +37.0509 +3821.32 +37.02 +3804.37 +36.9892 +3802.21 +36.9585 +3733.64 +36.9279 +3718.82 +36.8973 +3703.71 +36.8669 +3758.16 +36.8365 +3743.39 +36.8061 +3721.92 +36.7759 +3717.49 +36.7457 +3663.76 +36.7156 +3730.41 +36.6856 +3820.22 +36.6556 +3776.22 +36.6257 +3777.44 +36.5959 +3766.95 +36.5662 +3769.71 +36.5365 +3805.45 +36.5069 +3806.64 +36.4774 +3822.4 +36.4479 +3784 +36.4185 +3864.01 +36.3892 +3802.12 +36.36 +3793.02 +36.3308 +3855.97 +36.3017 +3865.08 +36.2727 +3969.75 +36.2437 +3965.21 +36.2148 +3951.6 +36.186 +3968.58 +36.1573 +3993.61 +36.1286 +4001.33 +36.1 +3935.5 +36.0714 +3982.89 +36.0429 +4040.27 +36.0145 +4023.74 +35.9862 +3911.81 +35.9579 +3921.6 +35.9297 +4022.79 +35.9015 +4088.37 +35.8734 +4041.13 +35.8454 +4017.61 +35.8175 +3927.19 +35.7896 +3872.86 +35.7618 +3876.24 +35.734 +3812.48 +35.7063 +3810.52 +35.6787 +3705.95 +35.6511 +3661.32 +35.6236 +3563.39 +35.5962 +3501.12 +35.5688 +3467.18 +35.5415 +3409.4 +35.5143 +3410.86 +35.4871 +3342.05 +35.46 +3342.44 +35.4329 +3341.08 +35.4059 +3308.88 +35.379 +3244.79 +35.3521 +3270.97 +35.3253 +3304.26 +35.2986 +3316.09 +35.2719 +3247.5 +35.2452 +3269.42 +35.2187 +3335.66 +35.1922 +3276.58 +35.1657 +3298.95 +35.1393 +3351.99 +35.113 +3333.76 +35.0867 +3295.96 +35.0605 +3347.12 +35.0343 +3363.57 +35.0082 +3424.67 +34.9822 +3353.64 +34.9562 +3320.7 +34.9303 +3385 +34.9044 +3422.18 +34.8786 +3415.06 +34.8529 +3381.96 +34.8272 +3405.82 +34.8016 +3447.33 +34.776 +3404.91 +34.7505 +3389.96 +34.725 +3427.81 +34.6996 +3279.72 +34.6742 +3349.87 +34.6489 +3389.01 +34.6237 +3394.67 +34.5985 +3423.51 +34.5733 +3515.64 +34.5483 +3503.51 +34.5232 +3584.13 +34.4983 +3570.18 +34.4734 +3657.07 +34.4485 +3607.56 +34.4237 +3644.13 +34.3989 +3743.45 +34.3742 +3722.89 +34.3496 +3700.64 +34.325 +3658.06 +34.3004 +3599.17 +34.2759 +3538.86 +34.2515 +3517.02 +34.2271 +3505.76 +34.2028 +3389.38 +34.1785 +3292.63 +34.1543 +3269.42 +34.1301 +3380.76 +34.106 +3448.83 +34.0819 +3449.41 +34.0578 +3389.06 +34.0339 +3328.38 +34.0099 +3366.07 +33.9861 +3362.16 +33.9622 +3332.35 +33.9385 +3379.05 +33.9147 +3261.45 +33.8911 +3287.45 +33.8674 +3255.47 +33.8439 +3239.89 +33.8203 +3332.75 +33.7969 +3287.03 +33.7734 +3298.2 +33.7501 +3351.26 +33.7267 +3310.05 +33.7034 +3313.18 +33.6802 +3333.43 +33.657 +3265.39 +33.6339 +3398.28 +33.6108 +3300.22 +33.5877 +3418.91 +33.5647 +3393.61 +33.5418 +3345.42 +33.5189 +3357.74 +33.496 +3421.71 +33.4732 +3410.48 +33.4505 +3475.22 +33.4277 +3432.94 +33.4051 +3576.56 +33.3824 +3492.78 +33.3599 +3476.75 +33.3373 +3460.59 +33.3148 +3328.99 +33.2924 +3421.32 +33.27 +3443.4 +33.2477 +3475.87 +33.2254 +3553.21 +33.2031 +3625.36 +33.1809 +3604.94 +33.1587 +3701.67 +33.1366 +3622.6 +33.1145 +3669.36 +33.0925 +3662.8 +33.0705 +3642.56 +33.0485 +3688.15 +33.0266 +3775.45 +33.0047 +3909.49 +32.9829 +3959.46 +32.9611 +3873.13 +32.9394 +3800.47 +32.9177 +3677.36 +32.8961 +3440.29 +32.8744 +3423.94 +32.8529 +3347.7 +32.8314 +3315.05 +32.8099 +3327.11 +32.7884 +3404.95 +32.7671 +3455.04 +32.7457 +3664.53 +32.7244 +3947.69 +32.7031 +4143.85 +32.6819 +4015.34 +32.6607 +3807.48 +32.6396 +3397.91 +32.6184 +2803.3 +32.5974 +2492.37 +32.5764 +2267.74 +32.5554 +2229.81 +32.5344 +2121.65 +32.5135 +2123.23 +32.4927 +2189.71 +32.4718 +2191.1 +32.4511 +2179.19 +32.4303 +2114.88 +32.4096 +2190.7 +32.389 +2163.01 +32.3683 +2183.28 +32.3478 +2183.21 +32.3272 +2132.11 +32.3067 +2129.18 +32.2862 +2176.11 +32.2658 +2171.07 +32.2454 +2184.97 +32.2251 +2195.54 +32.2048 +2242.19 +32.1845 +2261.83 +32.1642 +2259.85 +32.144 +2255.38 +32.1239 +2201.71 +32.1038 +2255.39 +32.0837 +2220.13 +32.0636 +2185.38 +32.0436 +2241.34 +32.0237 +2204.58 +32.0037 +2247.31 +31.9838 +2239.56 +31.964 +2261.49 +31.9441 +2293.48 +31.9244 +2272.88 +31.9046 +2271.62 +31.8849 +2221.53 +31.8652 +2314.43 +31.8456 +2296.97 +31.826 +2310.69 +31.8064 +2297.91 +31.7869 +2295.44 +31.7674 +2327.22 +31.7479 +2286.99 +31.7285 +2265.61 +31.7091 +2323.71 +31.6898 +2349.41 +31.6704 +2248.72 +31.6512 +2300.8 +31.6319 +2259.05 +31.6127 +2280.49 +31.5935 +2374.34 +31.5744 +2327.19 +31.5553 +2390.85 +31.5362 +2401.69 +31.5172 +2380.2 +31.4982 +2407.42 +31.4792 +2375.09 +31.4603 +2372.97 +31.4414 +2335.34 +31.4225 +2367.35 +31.4037 +2381.62 +31.3849 +2358.67 +31.3661 +2325.5 +31.3474 +2378.51 +31.3287 +2401.77 +31.31 +2370.24 +31.2914 +2400.64 +31.2728 +2374.29 +31.2542 +2413.11 +31.2357 +2442.07 +31.2172 +2407.36 +31.1987 +2343.49 +31.1803 +2390.29 +31.1619 +2473.12 +31.1435 +2488.82 +31.1252 +2447.61 +31.1069 +2426.35 +31.0886 +2390.07 +31.0704 +2463.45 +31.0522 +2425.24 +31.034 +2534.41 +31.0158 +2470.01 +30.9977 +2473.89 +30.9796 +2483.39 +30.9616 +2447.27 +30.9436 +2503.71 +30.9256 +2487.21 +30.9076 +2541.03 +30.8897 +2554.33 +30.8718 +2548.3 +30.854 +2534.2 +30.8361 +2564.23 +30.8183 +2545.56 +30.8006 +2580.64 +30.7828 +2526.96 +30.7651 +2629.89 +30.7475 +2598.42 +30.7298 +2625.53 +30.7122 +2579.85 +30.6946 +2547.42 +30.6771 +2567.12 +30.6595 +2610.77 +30.642 +2616.9 +30.6246 +2603.38 +30.6071 +2596.31 +30.5897 +2573.56 +30.5724 +2601.8 +30.555 +2620.68 +30.5377 +2643.64 +30.5204 +2634.59 +30.5031 +2648.58 +30.4859 +2614.14 +30.4687 +2664.53 +30.4515 +2640.11 +30.4344 +2649.47 +30.4173 +2620.34 +30.4002 +2684.13 +30.3832 +2770.86 +30.3661 +2740.17 +30.3491 +2745.64 +30.3322 +2749.15 +30.3152 +2684.76 +30.2983 +2698.35 +30.2814 +2692.1 +30.2646 +2635.78 +30.2477 +2679.65 +30.2309 +2757.59 +30.2142 +2746.82 +30.1974 +2736.37 +30.1807 +2729.77 +30.164 +2756.35 +30.1474 +2777.97 +30.1307 +2767.78 +30.1141 +2814.13 +30.0975 +2813.38 +30.081 +2833.51 +30.0645 +2844.65 +30.048 +2800.18 +30.0315 +2834.07 +30.0151 +2891.2 +29.9986 +2911.29 +29.9823 +2863.73 +29.9659 +2783.29 +29.9496 +2802.54 +29.9333 +2872.58 +29.917 +2831.56 +29.9007 +2876.02 +29.8845 +2888.34 +29.8683 +2905.62 +29.8521 +3010.81 +29.836 +3061.91 +29.8198 +3180 +29.8037 +3308.58 +29.7877 +3159.4 +29.7716 +3170.76 +29.7556 +3126.36 +29.7396 +2998.97 +29.7236 +2915.15 +29.7077 +2924.83 +29.6918 +2712.68 +29.6759 +2759.56 +29.66 +2633.58 +29.6442 +2601.11 +29.6284 +2610.47 +29.6126 +2525.95 +29.5968 +2484.36 +29.5811 +2425.34 +29.5654 +2445.18 +29.5497 +2453.3 +29.534 +2343.66 +29.5184 +2457.7 +29.5028 +2582.03 +29.4872 +2883.02 +29.4716 +3509.9 +29.4561 +4917.17 +29.4406 +6871.43 +29.4251 +7909.72 +29.4096 +6336.91 +29.3942 +3641.81 +29.3787 +2447.76 +29.3633 +2145.26 +29.348 +2134.14 +29.3326 +2055.05 +29.3173 +2058.58 +29.302 +2143.99 +29.2867 +2129.66 +29.2715 +2146.41 +29.2563 +2124.34 +29.2411 +2195.89 +29.2259 +2165.19 +29.2107 +2125.13 +29.1956 +2176.27 +29.1805 +2186.61 +29.1654 +2138.4 +29.1503 +2106.22 +29.1353 +2185.07 +29.1203 +2170.58 +29.1053 +2160.84 +29.0903 +2193.81 +29.0754 +2145.58 +29.0605 +2129.8 +29.0456 +2221.15 +29.0307 +2246.21 +29.0158 +2209.38 +29.001 +2172.29 +28.9862 +2184.4 +28.9714 +2211.31 +28.9567 +2228.21 +28.9419 +2234.02 +28.9272 +2191.16 +28.9125 +2284.67 +28.8978 +2207.96 +28.8832 +2174.92 +28.8686 +2212.3 +28.8539 +2264.83 +28.8394 +2219.42 +28.8248 +2229.66 +28.8103 +2283.51 +28.7957 +2251.49 +28.7812 +2200.94 +28.7668 +2225.15 +28.7523 +2240.97 +28.7379 +2263.1 +28.7235 +2211.32 +28.7091 +2237.01 +28.6947 +2239.5 +28.6804 +2321.54 +28.6661 +2294.53 +28.6518 +2334.39 +28.6375 +2236.99 +28.6232 +2247.89 +28.609 +2274.6 +28.5948 +2273.66 +28.5806 +2248.54 +28.5664 +2301.37 +28.5523 +2370.62 +28.5381 +2308.63 +28.524 +2301.72 +28.5099 +2320.94 +28.4959 +2345.17 +28.4818 +2416.66 +28.4678 +2291.54 +28.4538 +2351.89 +28.4398 +2355.33 +28.4258 +2302.74 +28.4119 +2370.56 +28.398 +2356.11 +28.3841 +2285.34 +28.3702 +2333.3 +28.3563 +2370.23 +28.3425 +2382.09 +28.3286 +2414.98 +28.3148 +2448.46 +28.3011 +2440.6 +28.2873 +2381.75 +28.2736 +2341.95 +28.2598 +2385.54 +28.2461 +2418.42 +28.2324 +2446.05 +28.2188 +2404.69 +28.2051 +2480.4 +28.1915 +2423.9 +28.1779 +2499.41 +28.1643 +2448.74 +28.1508 +2428.41 +28.1372 +2444.88 +28.1237 +2436.94 +28.1102 +2433.34 +28.0967 +2474.11 +28.0832 +2424.33 +28.0698 +2410.84 +28.0564 +2378.05 +28.043 +2440.8 +28.0296 +2527.22 +28.0162 +2437.48 +28.0029 +2547.98 +27.9895 +2494.82 +27.9762 +2486.38 +27.9629 +2495.37 +27.9496 +2486.01 +27.9364 +2482.99 +27.9232 +2581.53 +27.9099 +2531.71 +27.8967 +2586.96 +27.8836 +2637.49 +27.8704 +2567.19 +27.8572 +2659.83 +27.8441 +2542.42 +27.831 +2638.99 +27.8179 +2547.54 +27.8049 +2541.78 +27.7918 +2580.54 +27.7788 +2539.73 +27.7658 +2549.89 +27.7528 +2560.56 +27.7398 +2619.43 +27.7268 +2628.95 +27.7139 +2722.46 +27.701 +2694.34 +27.6881 +2740.48 +27.6752 +2735.13 +27.6623 +2730.04 +27.6495 +2702.71 +27.6366 +2723.14 +27.6238 +2731.44 +27.611 +2743.45 +27.5982 +2773.12 +27.5855 +2739.82 +27.5727 +2787.3 +27.56 +2735.81 +27.5473 +2776.34 +27.5346 +2681.97 +27.5219 +2691.87 +27.5093 +2761.59 +27.4966 +2766.58 +27.484 +2777.7 +27.4714 +2800.24 +27.4588 +2824.1 +27.4462 +2792.84 +27.4337 +2858.7 +27.4212 +2958.37 +27.4086 +3122.91 +27.3961 +3302.71 +27.3836 +3266.85 +27.3712 +3145.78 +27.3587 +2973.16 +27.3463 +2903.35 +27.3339 +2883.99 +27.3215 +2913.09 +27.3091 +2939.03 +27.2967 +2841.41 +27.2844 +2899.11 +27.2721 +2941.94 +27.2597 +3009.92 +27.2474 +2996.62 +27.2352 +2932.21 +27.2229 +2855.78 +27.2106 +2830.32 +27.1984 +2810.04 +27.1862 +2828.48 +27.174 +2829.19 +27.1618 +2838.48 +27.1497 +2881.15 +27.1375 +2884.97 +27.1254 +2841.51 +27.1132 +2794.38 +27.1011 +2801.53 +27.0891 +2859.32 +27.077 +2848.6 +27.0649 +2890.32 +27.0529 +2866.95 +27.0409 +2988.53 +27.0289 +3065.19 +27.0169 +3353.8 +27.0049 +4062.05 +26.993 +4616.31 +26.981 +4853.89 +26.9691 +4490.87 +26.9572 +3765.91 +26.9453 +3300.31 +26.9334 +2970.04 +26.9215 +2794.55 +26.9097 +2702.77 +26.8979 +2787.06 +26.8861 +2773.82 +26.8743 +2764.71 +26.8625 +2776.82 +26.8507 +2849.4 +26.8389 +3048.86 +26.8272 +3285.1 +26.8155 +3501.76 +26.8038 +3329.89 +26.7921 +3049.89 +26.7804 +2986.11 +26.7688 +2968.11 +26.7571 +3107.31 +26.7455 +3108.4 +26.7339 +3129.88 +26.7223 +3197.95 +26.7107 +3252.79 +26.6991 +3153.13 +26.6875 +2969.74 +26.676 +2903.61 +26.6645 +2806.79 +26.653 +2630.74 +26.6415 +2525.55 +26.63 +2447.53 +26.6185 +2495.73 +26.6071 +2439.26 +26.5956 +2320.56 +26.5842 +2270.39 +26.5728 +2189 +26.5614 +2146.4 +26.55 +2145.97 +26.5387 +2481.3 +26.5273 +2923.49 +26.516 +3336.18 +26.5047 +3497.1 +26.4934 +3877.89 +26.4821 +5639.11 +26.4708 +8506.63 +26.4595 +10836.6 +26.4483 +9606.1 +26.4371 +5735.98 +26.4258 +2957.68 +26.4146 +1822.83 +26.4034 +1316.72 +26.3923 +1085.79 +26.3811 +970.5 +26.37 +926.149 +26.3588 +885.194 +26.3477 +862.1 +26.3366 +799.702 +26.3255 +807.653 +26.3144 +790.556 +26.3034 +801.822 +26.2923 +841.277 +26.2813 +853.177 +26.2703 +910.874 +26.2593 +1042.11 +26.2483 +1244.53 +26.2373 +1580.05 +26.2263 +1477.39 +26.2154 +1095.16 +26.2044 +884.679 +26.1935 +814.372 +26.1826 +791.712 +26.1717 +743.845 +26.1608 +753.034 +26.1499 +735.01 +26.1391 +700.411 +26.1282 +716.832 +26.1174 +716.658 +26.1066 +715.484 +26.0958 +721.596 +26.085 +747.636 +26.0742 +710.279 +26.0635 +697.313 +26.0527 +700.184 +26.042 +719.588 +26.0312 +759.877 +26.0205 +760.659 +26.0098 +774.439 +25.9991 +720.757 +25.9885 +752.16 +25.9778 +740.95 +25.9672 +744.767 +25.9565 +728.899 +25.9459 +707.586 +25.9353 +697.976 +25.9247 +688.251 +25.9142 +713.734 +25.9036 +687.787 +25.893 +650.849 +25.8825 +705.612 +25.872 +722.99 +25.8614 +719.757 +25.8509 +689.692 +25.8405 +668.031 +25.83 +690.496 +25.8195 +782.009 +25.8091 +785.314 +25.7986 +885.212 +25.7882 +922.177 +25.7778 +903.521 +25.7674 +880.802 +25.757 +779.619 +25.7466 +751.04 +25.7363 +707.866 +25.7259 +704.754 +25.7156 +645.032 +25.7052 +691.109 +25.6949 +716.191 +25.6846 +693.909 +25.6743 +664.448 +25.6641 +693.913 +25.6538 +701.625 +25.6436 +655.499 +25.6333 +654.445 +25.6231 +674.567 +25.6129 +662.513 +25.6027 +685.018 +25.5925 +653.953 +25.5823 +653.373 +25.5721 +658.506 +25.562 +682.785 +25.5518 +662.773 +25.5417 +638.873 +25.5316 +668.538 +25.5215 +687.657 +25.5114 +666.419 +25.5013 +638.456 +25.4912 +658.783 +25.4812 +692.175 +25.4711 +678.845 +25.4611 +667.156 +25.4511 +681.897 +25.4411 +659.374 +25.4311 +646.886 +25.4211 +675.337 +25.4111 +690.599 +25.4012 +677.649 +25.3912 +650.113 +25.3813 +647.628 +25.3713 +645.977 +25.3614 +656.456 +25.3515 +695.995 +25.3416 +709.987 +25.3317 +693.565 +25.3219 +677.359 +25.312 +669.894 +25.3022 +699.649 +25.2923 +666.535 +25.2825 +675.945 +25.2727 +665.449 +25.2629 +693.887 +25.2531 +717.518 +25.2433 +740.69 +25.2336 +712.263 +25.2238 +708.491 +25.2141 +704.775 +25.2043 +697.856 +25.1946 +701.851 +25.1849 +698.153 +25.1752 +706.236 +25.1655 +660.917 +25.1558 +643.383 +25.1462 +668.174 +25.1365 +673.139 +25.1269 +706.439 +25.1172 +743.437 +25.1076 +735.602 +25.098 +700.626 +25.0884 +680.974 +25.0788 +703.162 +25.0692 +708.584 +25.0597 +699.602 +25.0501 +727.802 +25.0406 +734.313 +25.031 +714.841 +25.0215 +691.855 +25.012 +724.871 +25.0025 +706.572 +24.993 +731.703 +24.9835 +734.806 +24.974 +752.743 +24.9646 +731.565 +24.9551 +734.231 +24.9457 +712.593 +24.9363 +717.394 +24.9269 +741.59 +24.9175 +745.817 +24.9081 +809.792 +24.8987 +798.709 +24.8893 +840.966 +24.8799 +759.28 +24.8706 +689.775 +24.8613 +691.945 +24.8519 +727.217 +24.8426 +755.684 +24.8333 +739.961 +24.824 +766.44 +24.8147 +725.648 +24.8054 +723.688 +24.7962 +735.84 +24.7869 +719.638 +24.7777 +708.913 +24.7684 +725.817 +24.7592 +695.256 +24.75 +702.168 +24.7408 +694.662 +24.7316 +738.886 +24.7224 +736.227 +24.7132 +743.942 +24.7041 +721.455 +24.6949 +745.532 +24.6858 +750.344 +24.6766 +738.152 +24.6675 +764.307 +24.6584 +784.343 +24.6493 +732.664 +24.6402 +708.189 +24.6311 +748.01 +24.622 +771.726 +24.613 +743.654 +24.6039 +802.587 +24.5949 +732.273 +24.5858 +753.307 +24.5768 +777.759 +24.5678 +794.737 +24.5588 +727.213 +24.5498 +734.891 +24.5408 +746.685 +24.5318 +810.113 +24.5229 +798.367 +24.5139 +781.758 +24.505 +745.457 +24.496 +796.885 +24.4871 +772.662 +24.4782 +752.297 +24.4693 +778.957 +24.4604 +804.677 +24.4515 +791.335 +24.4426 +838.846 +24.4338 +855.892 +24.4249 +834.514 +24.4161 +825.182 +24.4072 +792.076 +24.3984 +765.702 +24.3896 +731.4 +24.3808 +793.143 +24.372 +807.13 +24.3632 +847.999 +24.3544 +834.696 +24.3456 +829.928 +24.3369 +957.441 +24.3281 +1228.39 +24.3194 +1611.42 +24.3106 +1710.01 +24.3019 +1220.34 +24.2932 +775.257 +24.2845 +657.65 +24.2758 +589.275 +24.2671 +555.574 +24.2584 +540.144 +24.2497 +535.202 +24.2411 +561.554 +24.2324 +592.902 +24.2238 +567.368 +24.2152 +558.715 +24.2065 +593.777 +24.1979 +602.623 +24.1893 +585.821 +24.1807 +569.15 +24.1721 +614.427 +24.1636 +569.133 +24.155 +541.748 +24.1464 +527.352 +24.1379 +540.28 +24.1294 +536.909 +24.1208 +531.737 +24.1123 +489.602 +24.1038 +505.324 +24.0953 +510.439 +24.0868 +469.33 +24.0783 +476.742 +24.0698 +510.94 +24.0614 +515.15 +24.0529 +615.671 +24.0445 +759.427 +24.036 +802.359 +24.0276 +872.665 +24.0192 +799.813 +24.0107 +655.019 +24.0023 +552.074 +23.9939 +666.262 +23.9856 +948.54 +23.9772 +925.154 +23.9688 +488.365 +23.9604 +220.489 +23.9521 +174.542 +23.9437 +162.444 +23.9354 +162 +23.9271 +152.931 +23.9188 +143.328 +23.9105 +144.569 +23.9022 +148.845 +23.8939 +141.025 +23.8856 +122.192 +23.8773 +126.124 +23.869 +126.815 +23.8608 +107.827 +23.8525 +114.164 +23.8443 +116.653 +23.8361 +119.557 +23.8278 +137.364 +23.8196 +149.581 +23.8114 +130.929 +23.8032 +164.528 +23.795 +180.656 +23.7868 +207.756 +23.7787 +239.018 +23.7705 +282.917 +23.7624 +314.528 +23.7542 +337.866 +23.7461 +337.469 +23.7379 +243.387 +23.7298 +165.442 +23.7217 +116.962 +23.7136 +105.264 +23.7055 +82.2528 +23.6974 +75.9785 +23.6893 +76.2064 +23.6813 +83.4402 +23.6732 +83.9909 +23.6651 +88.9014 +23.6571 +120.144 +23.649 +132.782 +23.641 +163.834 +23.633 +191.291 +23.625 +171.302 +23.617 +182.152 +23.609 +175.119 +23.601 +132.172 +23.593 +118.131 +23.585 +74.9546 +23.5771 +52.0199 +23.5691 +18.1529 +23.5611 +end of experiment diff --git a/tests/test_reader.py b/tests/test_reader.py index 70326871..73180692 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -41,7 +41,7 @@ def test_example_data(): reader_dirs = sorted(glob(os.path.join(data_dir, "*"))) - for reader_dir in reader_dirs: + for reader_dir in reader_dirs[:1]: input_files = sorted(glob(os.path.join(reader_dir, "*"))) for supported_nxdl in reader.supported_nxdls: @@ -58,39 +58,46 @@ def test_example_data(): ) assert isinstance(read_data, Template) - assert validate_data_dict(template, read_data, root) - - -def test_vms_mapper(): - mapper = VamasMapper - data_dir = os.path.join(os.path.dirname(__file__), "data", "vms") - - files_and_keys = { - "EX889_S1110_MgFe2O4_spent_irregular": { - "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Survey/scan_mode": "REGULAR", - "data['2 S1110, UHV, RT, Epass = 20 eV__MgKLL_1']['cycle0']": 1351, - }, - "EX889_S1110_MgFe2O4_spent_irregular": { - "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Survey/scan_mode": "IRREGULAR", - "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Fe2p/instrument/analyser/energydispersion/scan_mode": "FixedAnalyserTransmission", - "data['2 S1110, UHV, RT, Epass = 20 eV__Fe3s-Si2p-Mg2s']['cycle0']": 761, - }, - } - - # (C["benz"], "20240122_SBenz_102_20240122_SBenz_SnO2_10nm.vms"), - # (r"C:\Users\pielsticker\Lukas\MPI-CEC\Projects\deepxps\RUB MDI\example_spectra_Florian\Co", "Co 2p 0008751 M1.vms"), - # (C["pielst"], C["EX889"], "vms", f"{C['EX889']}_regular.vms"), - ((C["pielst"], C["EX889"], "vms", f"{C['EX889']}_irregular.vms"),) - # (C["schu"], "CleanData-alphaII VOPO4 C2 BC4316.vms"), - # (C["pielst"], C["EX889"], "vms", "d_reg.vms"), - ((C["pielst"], C["EX889"], "vms", "d_irreg.vms"),) - - for vms_file in os.listdir(data_dir): - data = mapper.parse_file(file=file) - - -for k, v in d.items(): - if isinstance(v, str): - # print(k) - if "REG" in v: - print(k) + # validate_data_dict(template, read_data, root) + # assert validate_data_dict(template, read_data, root) + + return read_data.get_accumulated_dict() + + +data = test_example_data() + +# ============================================================================= +# def test_vms_mapper(): +# mapper = VamasMapper +# data_dir = os.path.join(os.path.dirname(__file__), "data", "vms") +# +# files_and_keys = { +# "regular": { +# "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Survey/scan_mode": "REGULAR", +# "data['2 S1110, UHV, RT, Epass = 20 eV__MgKLL_1']['cycle0']": 1351, +# }, +# "irregular": { +# "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Survey/scan_mode": "IRREGULAR", +# "/ENTRY[entry]/Group_1 as-loaded/regions/Region_Fe2p/instrument/analyser/energydispersion/scan_mode": "FixedAnalyserTransmission", +# "data['2 S1110, UHV, RT, Epass = 20 eV__Fe3s-Si2p-Mg2s']['cycle0']": 761, +# }, +# } +# +# # (C["benz"], "20240122_SBenz_102_20240122_SBenz_SnO2_10nm.vms"), +# # (r"C:\Users\pielsticker\Lukas\MPI-CEC\Projects\deepxps\RUB MDI\example_spectra_Florian\Co", "Co 2p 0008751 M1.vms"), +# # (C["pielst"], C["EX889"], "vms", f"{C['EX889']}_regular.vms"), +# ((C["pielst"], C["EX889"], "vms", f"{C['EX889']}_irregular.vms"),) +# # (C["schu"], "CleanData-alphaII VOPO4 C2 BC4316.vms"), +# # (C["pielst"], C["EX889"], "vms", "d_reg.vms"), +# ((C["pielst"], C["EX889"], "vms", "d_irreg.vms"),) +# +# for vms_file in os.listdir(data_dir): +# data = mapper.parse_file(file=file) +# +# +# for k, v in d.items(): +# if isinstance(v, str): +# # print(k) +# if "REG" in v: +# print(k) +# ============================================================================= From dc578b046c478908ec1e4dc9ddcf39156eef8009 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 15 Mar 2024 09:28:48 +0100 Subject: [PATCH 36/41] add regular and irregular vms test data --- .../data/{vms => vms_irregular}/eln_data.yaml | 0 tests/data/vms_irregular/irregular.vms | 4141 +++++++++++++++++ tests/data/vms_regular/eln_data.yaml | 147 + tests/data/{vms => vms_regular}/regular.vms | 0 4 files changed, 4288 insertions(+) rename tests/data/{vms => vms_irregular}/eln_data.yaml (100%) create mode 100644 tests/data/vms_irregular/irregular.vms create mode 100644 tests/data/vms_regular/eln_data.yaml rename tests/data/{vms => vms_regular}/regular.vms (100%) diff --git a/tests/data/vms/eln_data.yaml b/tests/data/vms_irregular/eln_data.yaml similarity index 100% rename from tests/data/vms/eln_data.yaml rename to tests/data/vms_irregular/eln_data.yaml diff --git a/tests/data/vms_irregular/irregular.vms b/tests/data/vms_irregular/irregular.vms new file mode 100644 index 00000000..b38b6325 --- /dev/null +++ b/tests/data/vms_irregular/irregular.vms @@ -0,0 +1,4141 @@ +VAMAS Surface Chemical Analysis Standard Data Transfer Format 1988 May 4 +Not Specified +Not Specified +Not Specified +Not Specified +5 +Casa Info Follows CasaXPS Version 2.3.26PR1.0 +0 +Created by SpecsLab Prodigy, Version 4.100.1-r111001 +SourceAnalyserAngle: Not Specified +CasaRowLabel:1 as-loaded +NORM +IRREGULAR +1 +1 +Value +d +0 +0 +0 +0 +1 +Counts per Second +1 as-loaded +0 +0 +0 +0 +0 +0 +0 +6 +Casa Info Follows +0 +0 +0 +0 + +XPS +0 +Al +1486.61 +1e+037 +1e+037 +1e+037 +1e+037 +1e+037 +FAT +1e+037 +1e+037 +1e+037 +1e+037 +1e+037 +1e+037 +1e+037 +1e+037 +Survey + +-1 +3 +Kinetic Energy +eV +Intensity +d +transmission +d +pulse counting +1 +1 +1e+037 +1e+037 +1e+037 +1e+037 +2 +MFP Exponent +d +0 +ESCAPE DEPTH TYPE +d +1 +4053 +0 +1 +0 +1 +0 +1 +136.61 +15598.7 +78.8103 +137.61 +15867.9 +78.5146 +138.61 +15651.5 +78.2222 +139.61 +15321.3 +77.933 +140.61 +15793.4 +77.647 +141.61 +15662 +77.3642 +142.61 +15599 +77.0844 +143.61 +15758.9 +76.8076 +144.61 +15681.7 +76.5338 +145.61 +15968.1 +76.2628 +146.61 +15844.6 +75.9948 +147.61 +15328.3 +75.7295 +148.61 +15541 +75.467 +149.61 +15355.9 +75.2073 +150.61 +15531.3 +74.9501 +151.61 +15831.1 +74.6956 +152.61 +15628.4 +74.4437 +153.61 +15643.4 +74.1943 +154.61 +15649.2 +73.9474 +155.61 +15508.5 +73.703 +156.61 +16168.7 +73.4609 +157.61 +16783.7 +73.2213 +158.61 +16696.5 +72.9839 +159.61 +17242 +72.7489 +160.61 +16225.4 +72.5161 +161.61 +16518.6 +72.2855 +162.61 +16381.9 +72.0571 +163.61 +16956.2 +71.8309 +164.61 +16503.2 +71.6068 +165.61 +17074.8 +71.3847 +166.61 +16608.9 +71.1647 +167.61 +16689.8 +70.9468 +168.61 +16261.6 +70.7308 +169.61 +16260.5 +70.5168 +170.61 +15986.7 +70.3047 +171.61 +15943.1 +70.0945 +172.61 +15576.2 +69.8862 +173.61 +15749.3 +69.6798 +174.61 +15307.1 +69.4751 +175.61 +15088.5 +69.2723 +176.61 +15583.9 +69.0712 +177.61 +15913.9 +68.8719 +178.61 +17185.3 +68.6743 +179.61 +17381.4 +68.4783 +180.61 +20956.8 +68.2841 +181.61 +26719.6 +68.0914 +182.61 +27570.7 +67.9004 +183.61 +22744.5 +67.711 +184.61 +17508.6 +67.5232 +185.61 +15654.7 +67.337 +186.61 +15118.7 +67.1522 +187.61 +15568.8 +66.969 +188.61 +15345.7 +66.7873 +189.61 +15303 +66.607 +190.61 +14938 +66.4282 +191.61 +15054.6 +66.2508 +192.61 +14976.5 +66.0749 +193.61 +15205 +65.9003 +194.61 +15306.2 +65.7271 +195.61 +15772.5 +65.5553 +196.61 +15744.1 +65.3848 +197.61 +15599.9 +65.2156 +198.61 +15973.4 +65.0477 +199.61 +15693.5 +64.8812 +200.61 +15909.2 +64.7159 +201.61 +16198.6 +64.5518 +202.61 +15966.9 +64.389 +203.61 +15489.1 +64.2274 +204.61 +16474.9 +64.0671 +205.61 +15956.1 +63.9079 +206.61 +16501.6 +63.7499 +207.61 +15931.6 +63.5931 +208.61 +16115.7 +63.4374 +209.61 +16611.5 +63.2829 +210.61 +16061 +63.1295 +211.61 +16121.6 +62.9772 +212.61 +16202.9 +62.8259 +213.61 +16392.4 +62.6758 +214.61 +16503.7 +62.5268 +215.61 +16364.4 +62.3788 +216.61 +16383.3 +62.2318 +217.61 +15654.5 +62.0859 +218.61 +16709.3 +61.941 +219.61 +16583.1 +61.7972 +220.61 +17054.4 +61.6543 +221.61 +16442.2 +61.5124 +222.61 +16428.8 +61.3715 +223.61 +16359.6 +61.2315 +224.61 +17035.9 +61.0925 +225.61 +16781.8 +60.9544 +226.61 +16532.9 +60.8173 +227.61 +16559.9 +60.6811 +228.61 +17396.7 +60.5458 +229.61 +17337.8 +60.4114 +230.61 +16964.5 +60.2779 +231.61 +17236.6 +60.1453 +232.61 +17187.5 +60.0135 +233.61 +17685.7 +59.8826 +234.61 +17413.9 +59.7526 +235.61 +17348.1 +59.6234 +236.61 +17745.6 +59.495 +237.61 +17594.6 +59.3675 +238.61 +16802.7 +59.2408 +239.61 +17579.8 +59.1149 +240.61 +17782.9 +58.9898 +241.61 +18013.3 +58.8655 +242.61 +18298.8 +58.7419 +243.61 +18710.3 +58.6192 +244.61 +19254 +58.4972 +245.61 +18792.1 +58.3759 +246.61 +18473.2 +58.2554 +247.61 +18138.4 +58.1357 +248.61 +18382 +58.0167 +249.61 +18782.5 +57.8984 +250.61 +18880.3 +57.7808 +251.61 +18841.1 +57.664 +252.61 +19294.1 +57.5479 +253.61 +19521.4 +57.4324 +254.61 +19505.7 +57.3177 +255.61 +19003.9 +57.2036 +256.61 +18726.7 +57.0902 +257.61 +19079.4 +56.9775 +258.61 +19667.5 +56.8655 +259.61 +19860.6 +56.7541 +260.61 +19563 +56.6433 +261.61 +18944.9 +56.5332 +262.61 +19116.6 +56.4238 +263.61 +19366.5 +56.315 +264.61 +19505.1 +56.2068 +265.61 +19660.1 +56.0992 +266.61 +19174.2 +55.9922 +267.61 +19440.8 +55.8859 +268.61 +18765.7 +55.7801 +269.61 +19529.4 +55.675 +270.61 +19357.7 +55.5704 +271.61 +19126.9 +55.4665 +272.61 +19879 +55.3631 +273.61 +19197.5 +55.2603 +274.61 +18743 +55.158 +275.61 +19303.7 +55.0564 +276.61 +18895.3 +54.9553 +277.61 +18912.6 +54.8547 +278.61 +19686.7 +54.7547 +279.61 +20311.5 +54.6552 +280.61 +20127.5 +54.5563 +281.61 +20015.3 +54.4579 +282.61 +19671.3 +54.3601 +283.61 +20388.9 +54.2627 +284.61 +20034.7 +54.1659 +285.61 +19391.1 +54.0696 +286.61 +20300.1 +53.9738 +287.61 +21079.8 +53.8786 +288.61 +20574.4 +53.7838 +289.61 +20595.9 +53.6895 +290.61 +20473.3 +53.5957 +291.61 +20257.8 +53.5024 +292.61 +20594.2 +53.4096 +293.61 +21018 +53.3173 +294.61 +20826.8 +53.2255 +295.61 +20919.6 +53.1341 +296.61 +21146.1 +53.0432 +297.61 +20211.1 +52.9528 +298.61 +20873.9 +52.8628 +299.61 +21184.1 +52.7733 +300.61 +20921.1 +52.6842 +301.61 +20697.5 +52.5956 +302.61 +21410.1 +52.5074 +303.61 +20987.3 +52.4197 +304.61 +21123.2 +52.3324 +305.61 +21283.8 +52.2455 +306.61 +21746.4 +52.1591 +307.61 +22075.1 +52.0731 +308.61 +21570 +51.9875 +309.61 +21459.8 +51.9024 +310.61 +21401.2 +51.8176 +311.61 +21486.6 +51.7333 +312.61 +21931.1 +51.6494 +313.61 +21588.9 +51.5659 +314.61 +21547.3 +51.4828 +315.61 +23607.3 +51.4001 +316.61 +22903.4 +51.3178 +317.61 +22515.3 +51.2358 +318.61 +22090.6 +51.1543 +319.61 +21863 +51.0732 +320.61 +22432.8 +50.9924 +321.61 +23020.4 +50.9121 +322.61 +22759.1 +50.8321 +323.61 +23162.8 +50.7525 +324.61 +22785.6 +50.6732 +325.61 +22876.4 +50.5944 +326.61 +23135.4 +50.5159 +327.61 +23241.3 +50.4377 +328.61 +23401.4 +50.36 +329.61 +23775.4 +50.2825 +330.61 +23535.7 +50.2055 +331.61 +23399.7 +50.1288 +332.61 +23587.6 +50.0524 +333.61 +23859.4 +49.9764 +334.61 +23837.4 +49.9007 +335.61 +23578.4 +49.8254 +336.61 +23574.6 +49.7504 +337.61 +23347.3 +49.6758 +338.61 +23557.3 +49.6015 +339.61 +23525.4 +49.5275 +340.61 +23911.9 +49.4539 +341.61 +23944.1 +49.3805 +342.61 +24266.8 +49.3076 +343.61 +24470.3 +49.2349 +344.61 +24506 +49.1625 +345.61 +24284 +49.0905 +346.61 +24114.6 +49.0188 +347.61 +24776.2 +48.9474 +348.61 +24734.3 +48.8763 +349.61 +24520.9 +48.8055 +350.61 +24584.1 +48.735 +351.61 +25100.2 +48.6649 +352.61 +24669.4 +48.595 +353.61 +25163.5 +48.5254 +354.61 +24937.1 +48.4561 +355.61 +25585.9 +48.3872 +356.61 +25144.7 +48.3185 +357.61 +25014.5 +48.2501 +358.61 +25424.6 +48.182 +359.61 +25447.9 +48.1142 +360.61 +25640.2 +48.0466 +361.61 +26136.4 +47.9794 +362.61 +25730.6 +47.9124 +363.61 +26115.1 +47.8458 +364.61 +25993.9 +47.7793 +365.61 +26140.3 +47.7132 +366.61 +26458.3 +47.6474 +367.61 +25692.8 +47.5818 +368.61 +25948.6 +47.5165 +369.61 +26384.9 +47.4514 +370.61 +26150.8 +47.3866 +371.61 +26184 +47.3221 +372.61 +26887.5 +47.2579 +373.61 +27048.6 +47.1939 +374.61 +26457.8 +47.1301 +375.61 +26742.6 +47.0667 +376.61 +26680.6 +47.0035 +377.61 +26872.7 +46.9405 +378.61 +27118.8 +46.8778 +379.61 +27491.5 +46.8153 +380.61 +26834.9 +46.7531 +381.61 +27169.7 +46.6911 +382.61 +27231.8 +46.6294 +383.61 +27885 +46.5679 +384.61 +27614.6 +46.5067 +385.61 +27740.6 +46.4457 +386.61 +27574.8 +46.385 +387.61 +27769.5 +46.3244 +388.61 +27314.5 +46.2642 +389.61 +28164.6 +46.2041 +390.61 +28215.2 +46.1443 +391.61 +27772.4 +46.0847 +392.61 +27946.3 +46.0254 +393.61 +28072 +45.9663 +394.61 +28986.1 +45.9074 +395.61 +28640.9 +45.8487 +396.61 +27931.4 +45.7903 +397.61 +27800.6 +45.732 +398.61 +29132.5 +45.674 +399.61 +28665.1 +45.6163 +400.61 +28725.3 +45.5587 +401.61 +29136.3 +45.5014 +402.61 +29238.4 +45.4442 +403.61 +29365.2 +45.3873 +404.61 +29056.3 +45.3306 +405.61 +29495.9 +45.2741 +406.61 +28955.4 +45.2179 +407.61 +29597 +45.1618 +408.61 +29193.9 +45.1059 +409.61 +29321.1 +45.0503 +410.61 +29775.9 +44.9948 +411.61 +29377.4 +44.9396 +412.61 +29529.6 +44.8846 +413.61 +29828.1 +44.8297 +414.61 +30018.2 +44.7751 +415.61 +29834 +44.7206 +416.61 +29996.3 +44.6664 +417.61 +30373.1 +44.6124 +418.61 +30314.6 +44.5585 +419.61 +31086.5 +44.5049 +420.61 +30178 +44.4514 +421.61 +30253.2 +44.3981 +422.61 +30820.5 +44.3451 +423.61 +30735 +44.2922 +424.61 +31271 +44.2395 +425.61 +31323.7 +44.187 +426.61 +30857.3 +44.1346 +427.61 +31076.5 +44.0825 +428.61 +30252.6 +44.0306 +429.61 +31432.3 +43.9788 +430.61 +31016 +43.9272 +431.61 +32185.6 +43.8758 +432.61 +31861.4 +43.8246 +433.61 +31905.9 +43.7735 +434.61 +32140.4 +43.7226 +435.61 +31882.5 +43.672 +436.61 +31804.1 +43.6214 +437.61 +32339.6 +43.5711 +438.61 +31953.6 +43.5209 +439.61 +32897.1 +43.4709 +440.61 +32456.5 +43.4211 +441.61 +32561.5 +43.3715 +442.61 +32865.1 +43.322 +443.61 +32733.6 +43.2727 +444.61 +32345.2 +43.2235 +445.61 +32541.6 +43.1745 +446.61 +33078.3 +43.1257 +447.61 +32882.7 +43.0771 +448.61 +32824.1 +43.0286 +449.61 +32145.7 +42.9803 +450.61 +33879.3 +42.9321 +451.61 +33944.5 +42.8841 +452.61 +33463.8 +42.8363 +453.61 +33995.7 +42.7886 +454.61 +34321.7 +42.7411 +455.61 +33712.2 +42.6937 +456.61 +33822.9 +42.6465 +457.61 +35198.5 +42.5995 +458.61 +34655.7 +42.5526 +459.61 +34811.3 +42.5059 +460.61 +34009.6 +42.4593 +461.61 +34859 +42.4129 +462.61 +35005.1 +42.3666 +463.61 +34346.9 +42.3205 +464.61 +34454.5 +42.2745 +465.61 +35311.3 +42.2287 +466.61 +36074.3 +42.183 +467.61 +36582.6 +42.1374 +468.61 +36478 +42.0921 +469.61 +36448.4 +42.0468 +470.61 +36802.7 +42.0017 +471.61 +37718.8 +41.9568 +472.61 +37531.8 +41.912 +473.61 +36481.2 +41.8673 +474.61 +36675.2 +41.8228 +475.61 +36365.3 +41.7784 +476.61 +36290.3 +41.7342 +477.61 +36313.8 +41.6901 +478.61 +36661.6 +41.6462 +479.61 +37912.6 +41.6024 +480.61 +37630.1 +41.5587 +481.61 +37773.1 +41.5151 +482.61 +37597.9 +41.4717 +483.61 +38116.1 +41.4285 +484.61 +38829.8 +41.3853 +485.61 +39484.7 +41.3423 +486.61 +38626 +41.2995 +487.61 +39142.2 +41.2567 +488.61 +40090.2 +41.2141 +489.61 +39201.1 +41.1717 +490.61 +39574.7 +41.1293 +491.61 +38654.2 +41.0871 +492.61 +37852.7 +41.0451 +493.61 +38725.2 +41.0031 +494.61 +37536.5 +40.9613 +495.61 +38446 +40.9196 +496.61 +38553.7 +40.878 +497.61 +37948.7 +40.8366 +498.61 +38602.9 +40.7953 +499.61 +37477.9 +40.7541 +500.61 +37154.9 +40.713 +501.61 +37456.5 +40.6721 +502.61 +38694.4 +40.6313 +503.61 +39504.9 +40.5906 +504.61 +39709.5 +40.55 +505.61 +40968.1 +40.5096 +506.61 +42570.4 +40.4692 +507.61 +44598.6 +40.429 +508.61 +46921.3 +40.389 +509.61 +47219.7 +40.349 +510.61 +44644 +40.3091 +511.61 +42621.2 +40.2694 +512.61 +41423.9 +40.2298 +513.61 +40569.1 +40.1903 +514.61 +39280.1 +40.1509 +515.61 +38828.2 +40.1116 +516.61 +38663.8 +40.0725 +517.61 +37253.6 +40.0334 +518.61 +37653.3 +39.9945 +519.61 +37098.3 +39.9557 +520.61 +35628.9 +39.917 +521.61 +36215.5 +39.8784 +522.61 +35974.2 +39.84 +523.61 +35966.6 +39.8016 +524.61 +36380.7 +39.7633 +525.61 +36111.9 +39.7252 +526.61 +35791 +39.6872 +527.61 +36429.6 +39.6492 +528.61 +35897.4 +39.6114 +529.61 +35974 +39.5737 +530.61 +35544.8 +39.5361 +531.61 +35471.6 +39.4986 +532.61 +36427.2 +39.4612 +533.61 +36693.3 +39.424 +534.61 +36934.2 +39.3868 +535.61 +36730.8 +39.3497 +536.61 +36751.1 +39.3127 +537.61 +35881.9 +39.2759 +538.61 +36926.7 +39.2391 +539.61 +37109.6 +39.2025 +540.61 +36861 +39.1659 +541.61 +37605.2 +39.1295 +542.61 +37078.4 +39.0931 +543.61 +37794.9 +39.0569 +544.61 +37610.4 +39.0207 +545.61 +37185.9 +38.9847 +546.61 +36840.6 +38.9487 +547.61 +37486.6 +38.9129 +548.61 +38197.9 +38.8771 +549.61 +38255.4 +38.8415 +550.61 +37829.5 +38.8059 +551.61 +38162.7 +38.7705 +552.61 +38173.4 +38.7351 +553.61 +37677.9 +38.6999 +554.61 +38357.6 +38.6647 +555.61 +38313.5 +38.6296 +556.61 +38460.4 +38.5946 +557.61 +38614.9 +38.5598 +558.61 +38816.5 +38.525 +559.61 +38655.6 +38.4903 +560.61 +38574.5 +38.4557 +561.61 +38757.5 +38.4212 +562.61 +39066.8 +38.3868 +563.61 +39293.6 +38.3525 +564.61 +39082.4 +38.3182 +565.61 +38439.1 +38.2841 +566.61 +39090.5 +38.25 +567.61 +38152.9 +38.2161 +568.61 +38546.3 +38.1822 +569.61 +38729.4 +38.1485 +570.61 +39550 +38.1148 +571.61 +39425 +38.0812 +572.61 +39291.3 +38.0477 +573.61 +39660 +38.0142 +574.61 +39880.6 +37.9809 +575.61 +39459.2 +37.9477 +576.61 +40366.3 +37.9145 +577.61 +39404.3 +37.8814 +578.61 +39114 +37.8485 +579.61 +39442.1 +37.8156 +580.61 +39894.8 +37.7828 +581.61 +40594.5 +37.75 +582.61 +41142 +37.7174 +583.61 +41314.5 +37.6848 +584.61 +40379.4 +37.6524 +585.61 +40518.3 +37.62 +586.61 +40805.8 +37.5877 +587.61 +40031.3 +37.5554 +588.61 +40935.1 +37.5233 +589.61 +41727.4 +37.4912 +590.61 +41213.8 +37.4593 +591.61 +40366.5 +37.4274 +592.61 +39954.5 +37.3956 +593.61 +40601.8 +37.3638 +594.61 +41550.4 +37.3322 +595.61 +41174.2 +37.3006 +596.61 +39908.5 +37.2691 +597.61 +40004.1 +37.2377 +598.61 +40413.5 +37.2064 +599.61 +38703.8 +37.1751 +600.61 +37789.9 +37.1439 +601.61 +37104.1 +37.1129 +602.61 +37906 +37.0818 +603.61 +38442 +37.0509 +604.61 +38213.2 +37.02 +605.61 +38043.7 +36.9892 +606.61 +38022.1 +36.9585 +607.61 +37336.4 +36.9279 +608.61 +37188.2 +36.8973 +609.61 +37037.1 +36.8669 +610.61 +37581.6 +36.8365 +611.61 +37433.9 +36.8061 +612.61 +37219.2 +36.7759 +613.61 +37174.9 +36.7457 +614.61 +36637.6 +36.7156 +615.61 +37304.1 +36.6856 +616.61 +38202.2 +36.6556 +617.61 +37762.2 +36.6257 +618.61 +37774.4 +36.5959 +619.61 +37669.5 +36.5662 +620.61 +37697.1 +36.5365 +621.61 +38054.5 +36.5069 +622.61 +38066.4 +36.4774 +623.61 +38224 +36.4479 +624.61 +37840 +36.4185 +625.61 +38640.1 +36.3892 +626.61 +38021.2 +36.36 +627.61 +37930.2 +36.3308 +628.61 +38559.7 +36.3017 +629.61 +38650.8 +36.2727 +630.61 +39697.5 +36.2437 +631.61 +39652.1 +36.2148 +632.61 +39516 +36.186 +633.61 +39685.8 +36.1573 +634.61 +39936.1 +36.1286 +635.61 +40013.3 +36.1 +636.61 +39355 +36.0714 +637.61 +39828.9 +36.0429 +638.61 +40402.7 +36.0145 +639.61 +40237.4 +35.9862 +640.61 +39118.1 +35.9579 +641.61 +39216 +35.9297 +642.61 +40227.9 +35.9015 +643.61 +40883.7 +35.8734 +644.61 +40411.3 +35.8454 +645.61 +40176.1 +35.8175 +646.61 +39271.9 +35.7896 +647.61 +38728.6 +35.7618 +648.61 +38762.4 +35.734 +649.61 +38124.8 +35.7063 +650.61 +38105.2 +35.6787 +651.61 +37059.5 +35.6511 +652.61 +36613.2 +35.6236 +653.61 +35633.9 +35.5962 +654.61 +35011.2 +35.5688 +655.61 +34671.8 +35.5415 +656.61 +34094 +35.5143 +657.61 +34108.6 +35.4871 +658.61 +33420.5 +35.46 +659.61 +33424.4 +35.4329 +660.61 +33410.8 +35.4059 +661.61 +33088.8 +35.379 +662.61 +32447.9 +35.3521 +663.61 +32709.7 +35.3253 +664.61 +33042.6 +35.2986 +665.61 +33160.9 +35.2719 +666.61 +32475 +35.2452 +667.61 +32694.2 +35.2187 +668.61 +33356.6 +35.1922 +669.61 +32765.8 +35.1657 +670.61 +32989.5 +35.1393 +671.61 +33519.9 +35.113 +672.61 +33337.6 +35.0867 +673.61 +32959.6 +35.0605 +674.61 +33471.2 +35.0343 +675.61 +33635.7 +35.0082 +676.61 +34246.7 +34.9822 +677.61 +33536.4 +34.9562 +678.61 +33207 +34.9303 +679.61 +33850 +34.9044 +680.61 +34221.8 +34.8786 +681.61 +34150.6 +34.8529 +682.61 +33819.6 +34.8272 +683.61 +34058.2 +34.8016 +684.61 +34473.3 +34.776 +685.61 +34049.1 +34.7505 +686.61 +33899.6 +34.725 +687.61 +34278.1 +34.6996 +688.61 +32797.2 +34.6742 +689.61 +33498.7 +34.6489 +690.61 +33890.1 +34.6237 +691.61 +33946.7 +34.5985 +692.61 +34235.1 +34.5733 +693.61 +35156.4 +34.5483 +694.61 +35035.1 +34.5232 +695.61 +35841.3 +34.4983 +696.61 +35701.8 +34.4734 +697.61 +36570.7 +34.4485 +698.61 +36075.6 +34.4237 +699.61 +36441.3 +34.3989 +700.61 +37434.5 +34.3742 +701.61 +37228.9 +34.3496 +702.61 +37006.4 +34.325 +703.61 +36580.6 +34.3004 +704.61 +35991.7 +34.2759 +705.61 +35388.6 +34.2515 +706.61 +35170.2 +34.2271 +707.61 +35057.6 +34.2028 +708.61 +33893.8 +34.1785 +709.61 +32926.3 +34.1543 +710.61 +32694.2 +34.1301 +711.61 +33807.6 +34.106 +712.61 +34488.3 +34.0819 +713.61 +34494.1 +34.0578 +714.61 +33890.6 +34.0339 +715.61 +33283.8 +34.0099 +716.61 +33660.7 +33.9861 +717.61 +33621.6 +33.9622 +718.61 +33323.5 +33.9385 +719.61 +33790.5 +33.9147 +720.61 +32614.5 +33.8911 +721.61 +32874.5 +33.8674 +722.61 +32554.7 +33.8439 +723.61 +32398.9 +33.8203 +724.61 +33327.5 +33.7969 +725.61 +32870.3 +33.7734 +726.61 +32982 +33.7501 +727.61 +33512.6 +33.7267 +728.61 +33100.5 +33.7034 +729.61 +33131.8 +33.6802 +730.61 +33334.3 +33.657 +731.61 +32653.9 +33.6339 +732.61 +33982.8 +33.6108 +733.61 +33002.2 +33.5877 +734.61 +34189.1 +33.5647 +735.61 +33936.1 +33.5418 +736.61 +33454.2 +33.5189 +737.61 +33577.4 +33.496 +738.61 +34217.1 +33.4732 +739.61 +34104.8 +33.4505 +740.61 +34752.2 +33.4277 +741.61 +34329.4 +33.4051 +742.61 +35765.6 +33.3824 +743.61 +34927.8 +33.3599 +744.61 +34767.5 +33.3373 +745.61 +34605.9 +33.3148 +746.61 +33289.9 +33.2924 +747.61 +34213.2 +33.27 +748.61 +34434 +33.2477 +749.61 +34758.7 +33.2254 +750.61 +35532.1 +33.2031 +751.61 +36253.6 +33.1809 +752.61 +36049.4 +33.1587 +753.61 +37016.7 +33.1366 +754.61 +36226 +33.1145 +755.61 +36693.6 +33.0925 +756.61 +36628 +33.0705 +757.61 +36425.6 +33.0485 +758.61 +36881.5 +33.0266 +759.61 +37754.5 +33.0047 +760.61 +39094.9 +32.9829 +761.61 +39594.6 +32.9611 +762.61 +38731.3 +32.9394 +763.61 +38004.7 +32.9177 +764.61 +36773.6 +32.8961 +765.61 +34402.9 +32.8744 +766.61 +34239.4 +32.8529 +767.61 +33477 +32.8314 +768.61 +33150.5 +32.8099 +769.61 +33271.1 +32.7884 +770.61 +34049.5 +32.7671 +771.61 +34550.4 +32.7457 +772.61 +36645.3 +32.7244 +773.61 +39476.9 +32.7031 +774.61 +41438.5 +32.6819 +775.61 +40153.4 +32.6607 +776.61 +38074.8 +32.6396 +777.61 +33979.1 +32.6184 +778.61 +28033 +32.5974 +779.61 +24923.7 +32.5764 +780.61 +22677.4 +32.5554 +781.61 +22298.1 +32.5344 +782.61 +21216.5 +32.5135 +783.61 +21232.3 +32.4927 +784.61 +21897.1 +32.4718 +785.61 +21911 +32.4511 +786.61 +21791.9 +32.4303 +787.61 +21148.8 +32.4096 +788.61 +21907 +32.389 +789.61 +21630.1 +32.3683 +790.61 +21832.8 +32.3478 +791.61 +21832.1 +32.3272 +792.61 +21321.1 +32.3067 +793.61 +21291.8 +32.2862 +794.61 +21761.1 +32.2658 +795.61 +21710.7 +32.2454 +796.61 +21849.7 +32.2251 +797.61 +21955.4 +32.2048 +798.61 +22421.9 +32.1845 +799.61 +22618.3 +32.1642 +800.61 +22598.5 +32.144 +801.61 +22553.8 +32.1239 +802.61 +22017.1 +32.1038 +803.61 +22553.9 +32.0837 +804.61 +22201.3 +32.0636 +805.61 +21853.8 +32.0436 +806.61 +22413.4 +32.0237 +807.61 +22045.8 +32.0037 +808.61 +22473.1 +31.9838 +809.61 +22395.6 +31.964 +810.61 +22614.9 +31.9441 +811.61 +22934.8 +31.9244 +812.61 +22728.8 +31.9046 +813.61 +22716.2 +31.8849 +814.61 +22215.3 +31.8652 +815.61 +23144.3 +31.8456 +816.61 +22969.7 +31.826 +817.61 +23106.9 +31.8064 +818.61 +22979.1 +31.7869 +819.61 +22954.4 +31.7674 +820.61 +23272.2 +31.7479 +821.61 +22869.9 +31.7285 +822.61 +22656.1 +31.7091 +823.61 +23237.1 +31.6898 +824.61 +23494.1 +31.6704 +825.61 +22487.2 +31.6512 +826.61 +23008 +31.6319 +827.61 +22590.5 +31.6127 +828.61 +22804.9 +31.5935 +829.61 +23743.4 +31.5744 +830.61 +23271.9 +31.5553 +831.61 +23908.5 +31.5362 +832.61 +24016.9 +31.5172 +833.61 +23802 +31.4982 +834.61 +24074.2 +31.4792 +835.61 +23750.9 +31.4603 +836.61 +23729.7 +31.4414 +837.61 +23353.4 +31.4225 +838.61 +23673.5 +31.4037 +839.61 +23816.2 +31.3849 +840.61 +23586.7 +31.3661 +841.61 +23255 +31.3474 +842.61 +23785.1 +31.3287 +843.61 +24017.7 +31.31 +844.61 +23702.4 +31.2914 +845.61 +24006.4 +31.2728 +846.61 +23742.9 +31.2542 +847.61 +24131.1 +31.2357 +848.61 +24420.7 +31.2172 +849.61 +24073.6 +31.1987 +850.61 +23434.9 +31.1803 +851.61 +23902.9 +31.1619 +852.61 +24731.2 +31.1435 +853.61 +24888.2 +31.1252 +854.61 +24476.1 +31.1069 +855.61 +24263.5 +31.0886 +856.61 +23900.7 +31.0704 +857.61 +24634.5 +31.0522 +858.61 +24252.4 +31.034 +859.61 +25344.1 +31.0158 +860.61 +24700.1 +30.9977 +861.61 +24738.9 +30.9796 +862.61 +24833.9 +30.9616 +863.61 +24472.7 +30.9436 +864.61 +25037.1 +30.9256 +865.61 +24872.1 +30.9076 +866.61 +25410.3 +30.8897 +867.61 +25543.3 +30.8718 +868.61 +25483 +30.854 +869.61 +25342 +30.8361 +870.61 +25642.3 +30.8183 +871.61 +25455.6 +30.8006 +872.61 +25806.4 +30.7828 +873.61 +25269.6 +30.7651 +874.61 +26298.9 +30.7475 +875.61 +25984.2 +30.7298 +876.61 +26255.3 +30.7122 +877.61 +25798.5 +30.6946 +878.61 +25474.2 +30.6771 +879.61 +25671.2 +30.6595 +880.61 +26107.7 +30.642 +881.61 +26169 +30.6246 +882.61 +26033.8 +30.6071 +883.61 +25963.1 +30.5897 +884.61 +25735.6 +30.5724 +885.61 +26018 +30.555 +886.61 +26206.8 +30.5377 +887.61 +26436.4 +30.5204 +888.61 +26345.9 +30.5031 +889.61 +26485.8 +30.4859 +890.61 +26141.4 +30.4687 +891.61 +26645.3 +30.4515 +892.61 +26401.1 +30.4344 +893.61 +26494.7 +30.4173 +894.61 +26203.4 +30.4002 +895.61 +26841.3 +30.3832 +896.61 +27708.6 +30.3661 +897.61 +27401.7 +30.3491 +898.61 +27456.4 +30.3322 +899.61 +27491.5 +30.3152 +900.61 +26847.6 +30.2983 +901.61 +26983.5 +30.2814 +902.61 +26921 +30.2646 +903.61 +26357.8 +30.2477 +904.61 +26796.5 +30.2309 +905.61 +27575.9 +30.2142 +906.61 +27468.2 +30.1974 +907.61 +27363.7 +30.1807 +908.61 +27297.7 +30.164 +909.61 +27563.5 +30.1474 +910.61 +27779.7 +30.1307 +911.61 +27677.8 +30.1141 +912.61 +28141.3 +30.0975 +913.61 +28133.8 +30.081 +914.61 +28335.1 +30.0645 +915.61 +28446.5 +30.048 +916.61 +28001.8 +30.0315 +917.61 +28340.7 +30.0151 +918.61 +28912 +29.9986 +919.61 +29112.9 +29.9823 +920.61 +28637.3 +29.9659 +921.61 +27832.9 +29.9496 +922.61 +28025.4 +29.9333 +923.61 +28725.8 +29.917 +924.61 +28315.6 +29.9007 +925.61 +28760.2 +29.8845 +926.61 +28883.4 +29.8683 +927.61 +29056.2 +29.8521 +928.61 +30108.1 +29.836 +929.61 +30619.1 +29.8198 +930.61 +31800 +29.8037 +931.61 +33085.8 +29.7877 +932.61 +31594 +29.7716 +933.61 +31707.6 +29.7556 +934.61 +31263.6 +29.7396 +935.61 +29989.7 +29.7236 +936.61 +29151.5 +29.7077 +937.61 +29248.3 +29.6918 +938.61 +27126.8 +29.6759 +939.61 +27595.6 +29.66 +940.61 +26335.8 +29.6442 +941.61 +26011.1 +29.6284 +942.61 +26104.7 +29.6126 +943.61 +25259.5 +29.5968 +944.61 +24843.6 +29.5811 +945.61 +24253.4 +29.5654 +946.61 +24451.8 +29.5497 +947.61 +24533 +29.534 +948.61 +23436.6 +29.5184 +949.61 +24577 +29.5028 +950.61 +25820.3 +29.4872 +951.61 +28830.2 +29.4716 +952.61 +35099 +29.4561 +953.61 +49171.7 +29.4406 +954.61 +68714.3 +29.4251 +955.61 +79097.2 +29.4096 +956.61 +63369.1 +29.3942 +957.61 +36418.1 +29.3787 +958.61 +24477.6 +29.3633 +959.61 +21452.6 +29.348 +960.61 +21341.4 +29.3326 +961.61 +20550.5 +29.3173 +962.61 +20585.8 +29.302 +963.61 +21439.9 +29.2867 +964.61 +21296.6 +29.2715 +965.61 +21464.1 +29.2563 +966.61 +21243.4 +29.2411 +967.61 +21958.9 +29.2259 +968.61 +21651.9 +29.2107 +969.61 +21251.3 +29.1956 +970.61 +21762.7 +29.1805 +971.61 +21866.1 +29.1654 +972.61 +21384 +29.1503 +973.61 +21062.2 +29.1353 +974.61 +21850.7 +29.1203 +975.61 +21705.8 +29.1053 +976.61 +21608.4 +29.0903 +977.61 +21938.1 +29.0754 +978.61 +21455.8 +29.0605 +979.61 +21298 +29.0456 +980.61 +22211.5 +29.0307 +981.61 +22462.1 +29.0158 +982.61 +22093.8 +29.001 +983.61 +21722.9 +28.9862 +984.61 +21844 +28.9714 +985.61 +22113.1 +28.9567 +986.61 +22282.1 +28.9419 +987.61 +22340.2 +28.9272 +988.61 +21911.6 +28.9125 +989.61 +22846.7 +28.8978 +990.61 +22079.6 +28.8832 +991.61 +21749.2 +28.8686 +992.61 +22123 +28.8539 +993.61 +22648.3 +28.8394 +994.61 +22194.2 +28.8248 +995.61 +22296.6 +28.8103 +996.61 +22835.1 +28.7957 +997.61 +22514.9 +28.7812 +998.61 +22009.4 +28.7668 +999.61 +22251.5 +28.7523 +1000.61 +22409.7 +28.7379 +1001.61 +22631 +28.7235 +1002.61 +22113.2 +28.7091 +1003.61 +22370.1 +28.6947 +1004.61 +22395 +28.6804 +1005.61 +23215.4 +28.6661 +1006.61 +22945.3 +28.6518 +1007.61 +23343.9 +28.6375 +1008.61 +22369.9 +28.6232 +1009.61 +22478.9 +28.609 +1010.61 +22746 +28.5948 +1011.61 +22736.6 +28.5806 +1012.61 +22485.4 +28.5664 +1013.61 +23013.7 +28.5523 +1014.61 +23706.2 +28.5381 +1015.61 +23086.3 +28.524 +1016.61 +23017.2 +28.5099 +1017.61 +23209.4 +28.4959 +1018.61 +23451.7 +28.4818 +1019.61 +24166.6 +28.4678 +1020.61 +22915.4 +28.4538 +1021.61 +23518.9 +28.4398 +1022.61 +23553.3 +28.4258 +1023.61 +23027.4 +28.4119 +1024.61 +23705.6 +28.398 +1025.61 +23561.1 +28.3841 +1026.61 +22853.4 +28.3702 +1027.61 +23333 +28.3563 +1028.61 +23702.3 +28.3425 +1029.61 +23820.9 +28.3286 +1030.61 +24149.8 +28.3148 +1031.61 +24484.6 +28.3011 +1032.61 +24406 +28.2873 +1033.61 +23817.5 +28.2736 +1034.61 +23419.5 +28.2598 +1035.61 +23855.4 +28.2461 +1036.61 +24184.2 +28.2324 +1037.61 +24460.5 +28.2188 +1038.61 +24046.9 +28.2051 +1039.61 +24804 +28.1915 +1040.61 +24239 +28.1779 +1041.61 +24994.1 +28.1643 +1042.61 +24487.4 +28.1508 +1043.61 +24284.1 +28.1372 +1044.61 +24448.8 +28.1237 +1045.61 +24369.4 +28.1102 +1046.61 +24333.4 +28.0967 +1047.61 +24741.1 +28.0832 +1048.61 +24243.3 +28.0698 +1049.61 +24108.4 +28.0564 +1050.61 +23780.5 +28.043 +1051.61 +24408 +28.0296 +1052.61 +25272.2 +28.0162 +1053.61 +24374.8 +28.0029 +1054.61 +25479.8 +27.9895 +1055.61 +24948.2 +27.9762 +1056.61 +24863.8 +27.9629 +1057.61 +24953.7 +27.9496 +1058.61 +24860.1 +27.9364 +1059.61 +24829.9 +27.9232 +1060.61 +25815.3 +27.9099 +1061.61 +25317.1 +27.8967 +1062.61 +25869.6 +27.8836 +1063.61 +26374.9 +27.8704 +1064.61 +25671.9 +27.8572 +1065.61 +26598.3 +27.8441 +1066.61 +25424.2 +27.831 +1067.61 +26389.9 +27.8179 +1068.61 +25475.4 +27.8049 +1069.61 +25417.8 +27.7918 +1070.61 +25805.4 +27.7788 +1071.61 +25397.3 +27.7658 +1072.61 +25498.9 +27.7528 +1073.61 +25605.6 +27.7398 +1074.61 +26194.3 +27.7268 +1075.61 +26289.5 +27.7139 +1076.61 +27224.6 +27.701 +1077.61 +26943.4 +27.6881 +1078.61 +27404.8 +27.6752 +1079.61 +27351.3 +27.6623 +1080.61 +27300.4 +27.6495 +1081.61 +27027.1 +27.6366 +1082.61 +27231.4 +27.6238 +1083.61 +27314.4 +27.611 +1084.61 +27434.5 +27.5982 +1085.61 +27731.2 +27.5855 +1086.61 +27398.2 +27.5727 +1087.61 +27873 +27.56 +1088.61 +27358.1 +27.5473 +1089.61 +27763.4 +27.5346 +1090.61 +26819.7 +27.5219 +1091.61 +26918.7 +27.5093 +1092.61 +27615.9 +27.4966 +1093.61 +27665.8 +27.484 +1094.61 +27777 +27.4714 +1095.61 +28002.4 +27.4588 +1096.61 +28241 +27.4462 +1097.61 +27928.4 +27.4337 +1098.61 +28587 +27.4212 +1099.61 +29583.7 +27.4086 +1100.61 +31229.1 +27.3961 +1101.61 +33027.1 +27.3836 +1102.61 +32668.5 +27.3712 +1103.61 +31457.8 +27.3587 +1104.61 +29731.6 +27.3463 +1105.61 +29033.5 +27.3339 +1106.61 +28839.9 +27.3215 +1107.61 +29130.9 +27.3091 +1108.61 +29390.3 +27.2967 +1109.61 +28414.1 +27.2844 +1110.61 +28991.1 +27.2721 +1111.61 +29419.4 +27.2597 +1112.61 +30099.2 +27.2474 +1113.61 +29966.2 +27.2352 +1114.61 +29322.1 +27.2229 +1115.61 +28557.8 +27.2106 +1116.61 +28303.2 +27.1984 +1117.61 +28100.4 +27.1862 +1118.61 +28284.8 +27.174 +1119.61 +28291.9 +27.1618 +1120.61 +28384.8 +27.1497 +1121.61 +28811.5 +27.1375 +1122.61 +28849.7 +27.1254 +1123.61 +28415.1 +27.1132 +1124.61 +27943.8 +27.1011 +1125.61 +28015.3 +27.0891 +1126.61 +28593.2 +27.077 +1127.61 +28486 +27.0649 +1128.61 +28903.2 +27.0529 +1129.61 +28669.5 +27.0409 +1130.61 +29885.3 +27.0289 +1131.61 +30651.9 +27.0169 +1132.61 +33538 +27.0049 +1133.61 +40620.5 +26.993 +1134.61 +46163.1 +26.981 +1135.61 +48538.9 +26.9691 +1136.61 +44908.7 +26.9572 +1137.61 +37659.1 +26.9453 +1138.61 +33003.1 +26.9334 +1139.61 +29700.4 +26.9215 +1140.61 +27945.5 +26.9097 +1141.61 +27027.7 +26.8979 +1142.61 +27870.6 +26.8861 +1143.61 +27738.2 +26.8743 +1144.61 +27647.1 +26.8625 +1145.61 +27768.2 +26.8507 +1146.61 +28494 +26.8389 +1147.61 +30488.6 +26.8272 +1148.61 +32851 +26.8155 +1149.61 +35017.6 +26.8038 +1150.61 +33298.9 +26.7921 +1151.61 +30498.9 +26.7804 +1152.61 +29861.1 +26.7688 +1153.61 +29681.1 +26.7571 +1154.61 +31073.1 +26.7455 +1155.61 +31084 +26.7339 +1156.61 +31298.8 +26.7223 +1157.61 +31979.5 +26.7107 +1158.61 +32527.9 +26.6991 +1159.61 +31531.3 +26.6875 +1160.61 +29697.4 +26.676 +1161.61 +29036.1 +26.6645 +1162.61 +28067.9 +26.653 +1163.61 +26307.4 +26.6415 +1164.61 +25255.5 +26.63 +1165.61 +24475.3 +26.6185 +1166.61 +24957.3 +26.6071 +1167.61 +24392.6 +26.5956 +1168.61 +23205.6 +26.5842 +1169.61 +22703.9 +26.5728 +1170.61 +21890 +26.5614 +1171.61 +21464 +26.55 +1172.61 +21459.7 +26.5387 +1173.61 +24813 +26.5273 +1174.61 +29234.9 +26.516 +1175.61 +33361.8 +26.5047 +1176.61 +34971 +26.4934 +1177.61 +38778.9 +26.4821 +1178.61 +56391.1 +26.4708 +1179.61 +85066.3 +26.4595 +1180.61 +108366 +26.4483 +1181.61 +96061 +26.4371 +1182.61 +57359.8 +26.4258 +1183.61 +29576.8 +26.4146 +1184.61 +18228.3 +26.4034 +1185.61 +13167.2 +26.3923 +1186.61 +10857.9 +26.3811 +1187.61 +9705 +26.37 +1188.61 +9261.49 +26.3588 +1189.61 +8851.94 +26.3477 +1190.61 +8621 +26.3366 +1191.61 +7997.02 +26.3255 +1192.61 +8076.53 +26.3144 +1193.61 +7905.56 +26.3034 +1194.61 +8018.22 +26.2923 +1195.61 +8412.77 +26.2813 +1196.61 +8531.77 +26.2703 +1197.61 +9108.74 +26.2593 +1198.61 +10421.1 +26.2483 +1199.61 +12445.3 +26.2373 +1200.61 +15800.5 +26.2263 +1201.61 +14773.9 +26.2154 +1202.61 +10951.6 +26.2044 +1203.61 +8846.79 +26.1935 +1204.61 +8143.72 +26.1826 +1205.61 +7917.12 +26.1717 +1206.61 +7438.45 +26.1608 +1207.61 +7530.34 +26.1499 +1208.61 +7350.1 +26.1391 +1209.61 +7004.11 +26.1282 +1210.61 +7168.32 +26.1174 +1211.61 +7166.58 +26.1066 +1212.61 +7154.84 +26.0958 +1213.61 +7215.96 +26.085 +1214.61 +7476.36 +26.0742 +1215.61 +7102.79 +26.0635 +1216.61 +6973.13 +26.0527 +1217.61 +7001.84 +26.042 +1218.61 +7195.88 +26.0312 +1219.61 +7598.77 +26.0205 +1220.61 +7606.59 +26.0098 +1221.61 +7744.39 +25.9991 +1222.61 +7207.57 +25.9885 +1223.61 +7521.6 +25.9778 +1224.61 +7409.5 +25.9672 +1225.61 +7447.67 +25.9565 +1226.61 +7288.99 +25.9459 +1227.61 +7075.86 +25.9353 +1228.61 +6979.76 +25.9247 +1229.61 +6882.51 +25.9142 +1230.61 +7137.34 +25.9036 +1231.61 +6877.87 +25.893 +1232.61 +6508.49 +25.8825 +1233.61 +7056.12 +25.872 +1234.61 +7229.9 +25.8614 +1235.61 +7197.57 +25.8509 +1236.61 +6896.92 +25.8405 +1237.61 +6680.31 +25.83 +1238.61 +6904.96 +25.8195 +1239.61 +7820.09 +25.8091 +1240.61 +7853.14 +25.7986 +1241.61 +8852.12 +25.7882 +1242.61 +9221.77 +25.7778 +1243.61 +9035.21 +25.7674 +1244.61 +8808.02 +25.757 +1245.61 +7796.19 +25.7466 +1246.61 +7510.4 +25.7363 +1247.61 +7078.66 +25.7259 +1248.61 +7047.54 +25.7156 +1249.61 +6450.32 +25.7052 +1250.61 +6911.09 +25.6949 +1251.61 +7161.91 +25.6846 +1252.61 +6939.09 +25.6743 +1253.61 +6644.48 +25.6641 +1254.61 +6939.13 +25.6538 +1255.61 +7016.25 +25.6436 +1256.61 +6554.99 +25.6333 +1257.61 +6544.45 +25.6231 +1258.61 +6745.67 +25.6129 +1259.61 +6625.13 +25.6027 +1260.61 +6850.18 +25.5925 +1261.61 +6539.53 +25.5823 +1262.61 +6533.73 +25.5721 +1263.61 +6585.06 +25.562 +1264.61 +6827.85 +25.5518 +1265.61 +6627.73 +25.5417 +1266.61 +6388.73 +25.5316 +1267.61 +6685.38 +25.5215 +1268.61 +6876.57 +25.5114 +1269.61 +6664.19 +25.5013 +1270.61 +6384.56 +25.4912 +1271.61 +6587.83 +25.4812 +1272.61 +6921.75 +25.4711 +1273.61 +6788.45 +25.4611 +1274.61 +6671.56 +25.4511 +1275.61 +6818.97 +25.4411 +1276.61 +6593.74 +25.4311 +1277.61 +6468.86 +25.4211 +1278.61 +6753.37 +25.4111 +1279.61 +6905.99 +25.4012 +1280.61 +6776.49 +25.3912 +1281.61 +6501.13 +25.3813 +1282.61 +6476.28 +25.3713 +1283.61 +6459.77 +25.3614 +1284.61 +6564.56 +25.3515 +1285.61 +6959.95 +25.3416 +1286.61 +7099.87 +25.3317 +1287.61 +6935.65 +25.3219 +1288.61 +6773.59 +25.312 +1289.61 +6698.94 +25.3022 +1290.61 +6996.49 +25.2923 +1291.61 +6665.35 +25.2825 +1292.61 +6759.45 +25.2727 +1293.61 +6654.49 +25.2629 +1294.61 +6938.87 +25.2531 +1295.61 +7175.18 +25.2433 +1296.61 +7406.9 +25.2336 +1297.61 +7122.63 +25.2238 +1298.61 +7084.91 +25.2141 +1299.61 +7047.75 +25.2043 +1300.61 +6978.56 +25.1946 +1301.61 +7018.51 +25.1849 +1302.61 +6981.53 +25.1752 +1303.61 +7062.36 +25.1655 +1304.61 +6609.17 +25.1558 +1305.61 +6433.83 +25.1462 +1306.61 +6681.74 +25.1365 +1307.61 +6731.39 +25.1269 +1308.61 +7064.39 +25.1172 +1309.61 +7434.37 +25.1076 +1310.61 +7356.02 +25.098 +1311.61 +7006.26 +25.0884 +1312.61 +6809.74 +25.0788 +1313.61 +7031.62 +25.0692 +1314.61 +7085.84 +25.0597 +1315.61 +6996.02 +25.0501 +1316.61 +7278.02 +25.0406 +1317.61 +7343.13 +25.031 +1318.61 +7148.41 +25.0215 +1319.61 +6918.55 +25.012 +1320.61 +7248.71 +25.0025 +1321.61 +7065.72 +24.993 +1322.61 +7317.03 +24.9835 +1323.61 +7348.06 +24.974 +1324.61 +7527.43 +24.9646 +1325.61 +7315.65 +24.9551 +1326.61 +7342.31 +24.9457 +1327.61 +7125.93 +24.9363 +1328.61 +7173.94 +24.9269 +1329.61 +7415.9 +24.9175 +1330.61 +7458.17 +24.9081 +1331.61 +8097.92 +24.8987 +1332.61 +7987.09 +24.8893 +1333.61 +8409.66 +24.8799 +1334.61 +7592.8 +24.8706 +1335.61 +6897.75 +24.8613 +1336.61 +6919.45 +24.8519 +1337.61 +7272.17 +24.8426 +1338.61 +7556.84 +24.8333 +1339.61 +7399.61 +24.824 +1340.61 +7664.4 +24.8147 +1341.61 +7256.48 +24.8054 +1342.61 +7236.88 +24.7962 +1343.61 +7358.4 +24.7869 +1344.61 +7196.38 +24.7777 +1345.61 +7089.13 +24.7684 +1346.61 +7258.17 +24.7592 +1347.61 +6952.56 +24.75 +1348.61 +7021.68 +24.7408 +1349.61 +6946.62 +24.7316 +1350.61 +7388.86 +24.7224 +1351.61 +7362.27 +24.7132 +1352.61 +7439.42 +24.7041 +1353.61 +7214.55 +24.6949 +1354.61 +7455.32 +24.6858 +1355.61 +7503.44 +24.6766 +1356.61 +7381.52 +24.6675 +1357.61 +7643.07 +24.6584 +1358.61 +7843.43 +24.6493 +1359.61 +7326.64 +24.6402 +1360.61 +7081.89 +24.6311 +1361.61 +7480.1 +24.622 +1362.61 +7717.26 +24.613 +1363.61 +7436.54 +24.6039 +1364.61 +8025.87 +24.5949 +1365.61 +7322.73 +24.5858 +1366.61 +7533.07 +24.5768 +1367.61 +7777.59 +24.5678 +1368.61 +7947.37 +24.5588 +1369.61 +7272.13 +24.5498 +1370.61 +7348.91 +24.5408 +1371.61 +7466.85 +24.5318 +1372.61 +8101.13 +24.5229 +1373.61 +7983.67 +24.5139 +1374.61 +7817.58 +24.505 +1375.61 +7454.57 +24.496 +1376.61 +7968.85 +24.4871 +1377.61 +7726.62 +24.4782 +1378.61 +7522.97 +24.4693 +1379.61 +7789.57 +24.4604 +1380.61 +8046.77 +24.4515 +1381.61 +7913.35 +24.4426 +1382.61 +8388.46 +24.4338 +1383.61 +8558.92 +24.4249 +1384.61 +8345.14 +24.4161 +1385.61 +8251.82 +24.4072 +1386.61 +7920.76 +24.3984 +1387.61 +7657.02 +24.3896 +1388.61 +7314 +24.3808 +1389.61 +7931.43 +24.372 +1390.61 +8071.3 +24.3632 +1391.61 +8479.99 +24.3544 +1392.61 +8346.96 +24.3456 +1393.61 +8299.28 +24.3369 +1394.61 +9574.41 +24.3281 +1395.61 +12283.9 +24.3194 +1396.61 +16114.2 +24.3106 +1397.61 +17100.1 +24.3019 +1398.61 +12203.4 +24.2932 +1399.61 +7752.57 +24.2845 +1400.61 +6576.5 +24.2758 +1401.61 +5892.75 +24.2671 +1402.61 +5555.74 +24.2584 +1403.61 +5401.44 +24.2497 +1404.61 +5352.02 +24.2411 +1405.61 +5615.54 +24.2324 +1406.61 +5929.02 +24.2238 +1407.61 +5673.68 +24.2152 +1408.61 +5587.15 +24.2065 +1409.61 +5937.77 +24.1979 +1410.61 +6026.23 +24.1893 +1411.61 +5858.21 +24.1807 +1412.61 +5691.5 +24.1721 +1413.61 +6144.27 +24.1636 +1414.61 +5691.33 +24.155 +1415.61 +5417.48 +24.1464 +1416.61 +5273.52 +24.1379 +1417.61 +5402.8 +24.1294 +1418.61 +5369.09 +24.1208 +1419.61 +5317.37 +24.1123 +1420.61 +4896.02 +24.1038 +1421.61 +5053.24 +24.0953 +1422.61 +5104.39 +24.0868 +1423.61 +4693.3 +24.0783 +1424.61 +4767.42 +24.0698 +1425.61 +5109.4 +24.0614 +1426.61 +5151.5 +24.0529 +1427.61 +6156.71 +24.0445 +1428.61 +7594.27 +24.036 +1429.61 +8023.59 +24.0276 +1430.61 +8726.65 +24.0192 +1431.61 +7998.13 +24.0107 +1432.61 +6550.19 +24.0023 +1433.61 +5520.74 +23.9939 +1434.61 +6662.62 +23.9856 +1435.61 +9485.4 +23.9772 +1436.61 +9251.54 +23.9688 +1437.61 +4883.65 +23.9604 +1438.61 +2204.89 +23.9521 +1439.61 +1745.42 +23.9437 +1440.61 +1624.44 +23.9354 +1441.61 +1620 +23.9271 +1442.61 +1529.31 +23.9188 +1443.61 +1433.28 +23.9105 +1444.61 +1445.69 +23.9022 +1445.61 +1488.45 +23.8939 +1446.61 +1410.25 +23.8856 +1447.61 +1221.92 +23.8773 +1448.61 +1261.24 +23.869 +1449.61 +1268.15 +23.8608 +1450.61 +1078.27 +23.8525 +1451.61 +1141.64 +23.8443 +1452.61 +1166.53 +23.8361 +1453.61 +1195.57 +23.8278 +1454.61 +1373.64 +23.8196 +1455.61 +1495.81 +23.8114 +1456.61 +1309.29 +23.8032 +1457.61 +1645.28 +23.795 +1458.61 +1806.56 +23.7868 +1459.61 +2077.56 +23.7787 +1460.61 +2390.18 +23.7705 +1461.61 +2829.17 +23.7624 +1462.61 +3145.28 +23.7542 +1463.61 +3378.66 +23.7461 +1464.61 +3374.69 +23.7379 +1465.61 +2433.87 +23.7298 +1466.61 +1654.42 +23.7217 +1467.61 +1169.62 +23.7136 +1468.61 +1052.64 +23.7055 +1469.61 +822.528 +23.6974 +1470.61 +759.785 +23.6893 +1471.61 +762.064 +23.6813 +1472.61 +834.402 +23.6732 +1473.61 +839.909 +23.6651 +1474.61 +889.014 +23.6571 +1475.61 +1201.44 +23.649 +1476.61 +1327.82 +23.641 +1477.61 +1638.34 +23.633 +1478.61 +1912.91 +23.625 +1479.61 +1713.02 +23.617 +1480.61 +1821.52 +23.609 +1481.61 +1751.19 +23.601 +1482.61 +1321.72 +23.593 +1483.61 +1181.31 +23.585 +1484.61 +749.546 +23.5771 +1485.61 +520.199 +23.5691 +1486.61 +181.529 +23.5611 +end of experiment diff --git a/tests/data/vms_regular/eln_data.yaml b/tests/data/vms_regular/eln_data.yaml new file mode 100644 index 00000000..54475cbb --- /dev/null +++ b/tests/data/vms_regular/eln_data.yaml @@ -0,0 +1,147 @@ +definition: + value: NXmpes + version: 1.0 +title: XPS Experiment +start_time: 2022-04-08T11:47:02.0200Z +end_time: 2022-04-08T12:32:06.0200Z +experiment_institution: BESSY II +program_name: SpecsLab 2 +user: + name: Lukas Pielsticker + email: lukas.pielsticker@cec.mpg.de +instrument: + device_information: + vendor: SPECS GmbH + model: XPS setup + identifier: null + energy_resolution: + type: calibrated + resolution: + value: 0.2 + unit: eV + source_probe: + type: Synchrotron X-ray Source + probe: x-ray + device_information: + vendor: null + model: null + identifier: null + beam_probe: + distance: + value: 0.0 + unit: mm + analyser: + description: hemispherical + name: PHOIBOS 150 + device_information: + vendor: SPECS GmbH + model: PHOIBOS 150 + identifier: null + collectioncolumn: + scheme: angular dispersive + device_information: + vendor: null + model: null + identifier: null + energydispersion: + scheme: hemispherical + entrance_slit: unknown + energy_scan_mode: fixed_analyser_transmission + diameter: + unit: mm + value: 150 + device_information: + vendor: null + model: null + identifier: null + detector: + amplifier_type: channeltron + detector_type: Multi-anode + manipulator: + device_information: + vendor: SPECS GmbH + model: 5-axis manipulator + identifier: null + temperature_sensor: + name: type K thermocouple + measurement: temperature + attached_to: sample + type: type K thermocouple + value: + value: 298.0 + unit: K + sample_heater: + name: Coherent Compact Evolution IR Diode LASER (DILAS) + physical_quantity: temperature + type: IR diode laser + heater_power: + value: 0.0 + unit: W + pid: + setpoint: + value: 298.0 + unit: K + cryostat: + name: null + physical_quantity: null + type: null + pid: + setpoint: null + drain_current_amperemeter: + name: Amperemeter 1.0 + measurement: current + type: wire + value: + value: 0.0 + unit: A + sample_bias_voltmeter: + name: XPS sample voltmeter + measurement: voltage + attached_to: sample + type: oscilloscope + value: + value: 0.0 + unit: V + sample_bias_potentiostat: + name: XPS sample potentiostat + physical_quantity: voltage + type: potentiostat + pid: + setpoint: + value: 0.0 + unit: V + pressure_gauge: + name: Atmion + measurement: pressure + type: hot-filament ionization gauge + value: + value: 0.000000001 + unit: mbar + value_log: + value: + value: null + unit: null + flood_gun: + name: FG 22/35 + physical_quantity: current + type: low energy electron source + current: + value: 0.0 + unit: A + current_log: + value: + value: null + unit: null +sample: + description: A polymer material called PBTTT with chemical name poly[2,5-bis(3-dodecylthiophen-2-yl)thieno[3,2-b]thiophene]. + name: Test + substance: + molecular_formula_hill: (C42H62S4)n + situation: vacuum + sample_history: + sample_preparation: + start_time: 2022-04-08T11:02:38.0200Z + end_time: 2022-04-08T11:06:42.200Z + description: From third party + method: null + \ No newline at end of file diff --git a/tests/data/vms/regular.vms b/tests/data/vms_regular/regular.vms similarity index 100% rename from tests/data/vms/regular.vms rename to tests/data/vms_regular/regular.vms From 142bd777d60f59dd276bc78e94fde62c23af6878 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 15 Mar 2024 09:29:18 +0100 Subject: [PATCH 37/41] reset test_reader --- tests/test_reader.py | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/tests/test_reader.py b/tests/test_reader.py index 73180692..237a238e 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -13,20 +13,6 @@ from pynxtools.nexus.nxdl_utils import get_nexus_definitions_path from pynxtools_xps.reader import XPSReader -# from pynxtools_xps.phi.spe_pro_phi import MapperPhi -from pynxtools_xps.sle.sle_specs import SleMapperSpecs - -# from pynxtools_xps.slh.slh_specs import SlhMapperSpecs -from pynxtools_xps.txt.txt_scienta import TxtMapperScienta - -# from pynxtools_xps.txt.txt_specs import TxtMapperSpecs -from pynxtools_xps.txt.txt_vamas_export import ( - TxtMapperVamasExport, -) -from pynxtools_xps.vms.vamas import VamasMapper -from pynxtools_xps.xy.xy_specs import XyMapperSpecs -from pynxtools_xps.xml.xml_specs import XmlMapperSpecs - def test_example_data(): """ @@ -41,7 +27,7 @@ def test_example_data(): reader_dirs = sorted(glob(os.path.join(data_dir, "*"))) - for reader_dir in reader_dirs[:1]: + for reader_dir in reader_dirs: input_files = sorted(glob(os.path.join(reader_dir, "*"))) for supported_nxdl in reader.supported_nxdls: @@ -58,14 +44,10 @@ def test_example_data(): ) assert isinstance(read_data, Template) - # validate_data_dict(template, read_data, root) - # assert validate_data_dict(template, read_data, root) - - return read_data.get_accumulated_dict() - + assert validate_data_dict(template, read_data, root) -data = test_example_data() +## This will be implemented in the future. # ============================================================================= # def test_vms_mapper(): # mapper = VamasMapper From 4c26b371a4db17114ef45a6142132e23c071d5c7 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 15 Mar 2024 10:20:37 +0100 Subject: [PATCH 38/41] make units top-level constant --- pynxtools_xps/vms/vamas.py | 47 +++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index 9a86439e..b9dfcb63 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -42,6 +42,26 @@ get_minimal_step, ) +UNITS: dict = { + "instrument/sample_normal_polarangle_tilt": "degree ", + "instrument/sample_tilt_azimuth": "degree", + "instrument/sample_rotation_angle": "degree", + "source/source_analyzer_angle": "degree", + "source/excitation_energy": "eV", + "source/particle_charge": "C", + "analyser/analyzer_take_off_azimuth": "degree", + "analyser/analyzer_take_off_polar": "degree", + "analyser/analysis_width_x": "m", + "analyser/analysis_width_y": "m", + "analyser/target_bias": "V", + "analyser/time_correction": "s", + "analyser/work_function": "eV", + "energydispersion/pass_energy": "eV", + "detector/dwell_time": "s", + "data/start_energy": "eV", + "data/step_size": "eV", +} + class VamasMapper(XPSMapper): """ @@ -51,31 +71,6 @@ class VamasMapper(XPSMapper): config_file = "config_vms.json" - def __init__(self): - self.parsers: List[Any] = [] - - self.units: dict = { - "instrument/sample_normal_polarangle_tilt": "degree ", - "instrument/sample_tilt_azimuth": "degree", - "instrument/sample_rotation_angle": "degree", - "source/source_analyzer_angle": "degree", - "source/excitation_energy": "eV", - "source/particle_charge": "C", - "analyser/analyzer_take_off_azimuth": "degree", - "analyser/analyzer_take_off_polar": "degree", - "analyser/analysis_width_x": "m", - "analyser/analysis_width_y": "m", - "analyser/target_bias": "V", - "analyser/time_correction": "s", - "analyser/work_function": "eV", - "energydispersion/pass_energy": "eV", - "detector/dwell_time": "s", - "data/start_energy": "eV", - "data/step_size": "eV", - } - - super().__init__() - def _select_parser(self): """ Select parser based on the structure of the Vamas file, @@ -288,7 +283,7 @@ def _get_units_for_key(self, unit_key: str): return re.search(r"\[([A-Za-z0-9_]+)\]", unit_key).group(1) except AttributeError: try: - return self.units[unit_key] + return UNITS[unit_key] except KeyError: return "" From eb363e61b9fec88b903927d0a401303e098f7ae9 Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 15 Mar 2024 11:05:38 +0100 Subject: [PATCH 39/41] avoid unneeded double checking for existence of keyword --- pynxtools_xps/config/config_vms.json | 2 +- pynxtools_xps/vms/vamas.py | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pynxtools_xps/config/config_vms.json b/pynxtools_xps/config/config_vms.json index cae9d774..eafddd5f 100644 --- a/pynxtools_xps/config/config_vms.json +++ b/pynxtools_xps/config/config_vms.json @@ -122,7 +122,7 @@ "vendor":"@eln", "model":"@eln", "identifier":"@eln" - }, + } }, "DETECTOR[detector]":{ "@default":"raw_data", diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index b9dfcb63..ead0e181 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -768,7 +768,7 @@ def _add_regular_data(self, block: VamasBlock): name = "y" + str(var) data_dict[name] = [] - data_array = list(np.array(self.data[: block.num_ord_values], dtype=float)) + data_array = np.array(self.data[: block.num_ord_values], dtype=float) self.data = self.data[block.num_ord_values :] @@ -786,7 +786,7 @@ def _add_irregular_data(self, block: VamasBlock): """Parse data with regularly spaced energy axis.""" data_dict: Dict[str, List] = {} - block_data = list(np.array(self.data[: block.num_ord_values], dtype=float)) + block_data = np.array(self.data[: block.num_ord_values], dtype=float) energy = block_data[:: block.no_variables + 1] if block.abscissa_label == "binding energy": @@ -861,9 +861,11 @@ def handle_header_comments(self, comment_list: List[str]): } for keyword, handle_func in special_keys.items(): - if any(keyword in line for line in comment_list): - index = [i for i, line in enumerate(comment_list) if keyword in line][0] + # if any(keyword in line for line in comment_list): + indices = [i for i, line in enumerate(comment_list) if keyword in line] + if indices: + index = indices[0] if keyword == "Casa Info Follows": special_comments = comment_list[index] comment_list = comment_list[index + 1 :] From 105b18e96c2db40b0633a3ddd8902716ee81a37c Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 15 Mar 2024 11:10:59 +0100 Subject: [PATCH 40/41] typo fix in config file --- pynxtools_xps/config/config_vms.json | 576 ++++++++++++++------------- 1 file changed, 290 insertions(+), 286 deletions(-) diff --git a/pynxtools_xps/config/config_vms.json b/pynxtools_xps/config/config_vms.json index eafddd5f..d7d9cdb2 100644 --- a/pynxtools_xps/config/config_vms.json +++ b/pynxtools_xps/config/config_vms.json @@ -1,287 +1,291 @@ { - "/@default":"None", - "/ENTRY[entry]":{ - "@default":"data", - "definition":"@eln", - "definition/@version":"@eln", - "title":"@eln", - "start_time":"@xps_token:region/time_stamp", - "end_time":"@eln", - "experiment_institution":"@eln", - "experiment_facility":"@eln", - "experiment_laboratory":"@eln", - "entry_identifier":"@eln", - "duration":"None", - "duration/@units":"s", - "method":"@xps_token:region/analysis_method", - "program_name":"@eln" - }, - "/ENTRY[entry]/USER[user]":{ - "name":"@eln", - "affiliation":"@eln", - "address":"@eln", - "orcid":"@eln", - "email":"@eln" - }, - "/ENTRY[entry]/INSTRUMENT[instrument]":{ - "@default": "electronanalyser", - "device_information":{ - "vendor":"@eln", - "identifier":"@eln", - "model":"@eln" - }, - "energy_resolution":{ - "physical_quantity":"energy", - "type":"derived", - "resolution":"@xps_token:data/step_size", - "resolution/@units":"eV" - }, - "source_TYPE[source_probe]":{ - "type":"@eln", - "name":"@xps_token:source/source_label", - "probe":"photon", - "device_information":{ - "vendor":"@eln", - "identifier":"@eln", - "model":"@eln" - }, - "associated_beam":"@link:/entry/instrument/beam_probe", - "source_analyzer_angle": "source_analyzer_angle", - "source_analyzer_angle/@units": "degree" - }, - "beam_TYPE[beam_probe]":{ - "distance":"@eln", - "distance/@units":"@eln", - "incident_energy":"@xps_token:beam/excitation_energy", - "incident_energy/@units":"eV", - "incident_energy_spread":"None", - "incident_energy_spread/@units":"None", - "incident_polarization":"None", - "incident_polarization/@units":"None", - "extent":"None", - "associated_source":"@link:/entry/instrument/source_probe" - }, - "ELECTRONANALYSER[electronanalyser]":{ - "@default": "detector0", - "name":"@xps_token:analyser/analyser_name", - "description":"@eln", - "work_function":"@xps_token:analyser/work_function", - "work_function/@units":"eV", - "fast_axes":"None", - "slow_axes":"energy", - "analyzer_take_off_azimuth": "@xps_token:analyser/analyzer_take_off_azimuth", - "analyzer_take_off_azimuth/@units": "degree", - "analyzer_take_off_polar": "@xps_token:analyser/analyzer_take_off_polar", - "analyzer_take_off_polar/@units": "degree", - "analysis_width_x": "@xps_token:analyser/analysis_width_x", - "analysis_width_x/@units": "mm", - "analysis_width_y": "@xps_token:analyser/analysis_width_y", - "analysis_width_y/@units": "mm", - "target_bias": "@xps_token:analyser/target_bias", - "target_bias/@units": "V", - "device_information":{ - "vendor":"@eln", - "model":"@eln", - "identifier":"@eln" - }, - "energy_resolution":{ - "physical_quantity":"energy", - "type":"estimated", - "resolution":"@xps_token:data/step_size", - "resolution/@units":"eV" - }, - "transmission_function":{ - "@signal":"relative_intensity", - "@axes":["kinetic_energy"], - "kinetic_energy":"@xps_token:transmission_function/kinetic_energy", - "kinetic_energy/@units":"@xps_token:transmission_function/kinetic_energy/@units", - "relative_intensity":"@xps_token:collectioncolumn/transmission_function/relative_intensity" - }, - "COLLECTIONCOLUMN[collectioncolumn]":{ - "scheme":"@eln", - "lens_mode":"@xps_token:collectioncolumn/lens_mode", - "projection":"None", - "angular_acceptance":"None", - "spatial_acceptance":"None", - "field_aperture":"None", - "contrast_aperture":"None", - "device_information":{ - "vendor":"@eln", - "model":"@eln", - "identifier":"@eln" - } - }, - "ENERGYDISPERSION[energydispersion]":{ - "scheme":"@eln", - "pass_energy":"@xps_token:energydispersion/pass_energy", - "pass_energy/@units":"@xps_token:energydispersion/pass_energy/@units", - "energy_scan_mode":"@xps_token:energydispersion/scan_mode", - "entrance_slit":"@eln", - "exit_slit":"@eln", - "device_information":{ - "vendor":"@eln", - "model":"@eln", - "identifier":"@eln" - } - }, - "DETECTOR[detector]":{ - "@default":"raw_data", - "amplifier_type":"@eln", - "detector_type":"@eln", - "detector_voltage": "@xps_token:detector/detector_voltage", - "detector_voltage/@units": "V", - "count_time":"@xps_token:detector/dwell_time", - "count_time/@units":"s", - "acquisition_mode": "@xps_token:detector/signal_mode", - "device_information":{ - "vendor":"@eln", - "model":"@eln", - "identifier":"@eln" - }, - "raw_data":{ - "@signal":"raw", - "raw":"@detector_data:cycles/Cycle_", - "raw/@units":"counts" - } - } - }, - "MANIPULATOR[manipulator]":{ - "device_information":{ - "vendor":"@eln", - "model":"@eln", - "identifier":"@eln" - }, - "temperature_sensor":{ - "name":"@eln", - "measurement":"@eln", - "type":"@eln", - "attached_to":"@eln", - "value":"@eln" - }, - "sample_heater":{ - "name":"@eln", - "physical_quantity":"@eln", - "type":"@eln", - "heater_power":"@eln", - "PID[pid]/setpoint":"@eln" - }, - "cryostat":{ - "name":"None", - "physical_quantity":"None", - "type":"None", - "PID[pid]/setpoint":"None" - }, - "drain_current_amperemeter":{ - "name":"@eln", - "measurement":"@eln", - "type":"@eln", - "value":"@eln" - }, - "sample_bias_voltmeter":{ - "name":"@eln", - "measurement":"@eln", - "type":"@eln", - "value":"@xps_token:sample/target_bias", - "value/@units": "V" - }, - "sample_bias_potentiostat":{ - "name":"@eln", - "physical_quantity":"@eln", - "type":"@eln", - "PID[pid]/setpoint":"@eln" - } - }, - "pressure_gauge":{ - "name":"@eln", - "measurement":"@eln", - "type":"@eln", - "value":"@eln", - "value_log/value":"@eln" - }, - "flood_gun":{ - "name":"@eln", - "physical_quantity":"@eln", - "type":"@eln", - "current":"@eln", - "current_log/value":"@eln" - } - }, - "/ENTRY[entry]/PROCESS[process]":{ - "energy_calibration":{ - "calibrated_axis":"@data:energy", - "calibrated_axis/@units":"eV", - }, - "energy_referencing":{ - "level":"None", - "reference_peak":"None", - "binding_energy":"None", - "offset":"None", - "calibrated_axis":"None" - }, - "transmission_correction":{ - "transmission_function":{ - "@axes":"None", - "@signal":"None", - "kinetic_energy":"None", - "kinetic_energy/@units":"None", - "relative_intensity":"None" - } - } - }, - "/ENTRY[entry]/SAMPLE[sample]":{ - "name":"@eln", - "sample_id":"@eln", - "atom_types":"@eln", - "physical_form":"@eln", - "situation":"@eln", - "SUBSTANCE[substance]":{ - "name":"@eln", - "molecular_mass":"@eln", - "cas_number":"@eln", - "molecular_formula_hill":"@eln" - }, - "sample_history":{ - "sample_preparation":{ - "start_time":"@eln", - "end_time":"@eln", - "description":"@eln", - "method":"@eln" - }, - "PHYSICAL_PROCESS[sample_loading]":{ - "start_time":"@eln", - "end_time":"@eln", - "description":"@eln", - "method":"@eln" - } - }, - "temperature":{ - "temperature_sensor": "@link:/entry/instrument/manipulator/temperature_sensor", - "sample_heater":"@link:/entry/instrument/manipulator/sample_heater", - "cryostat":"None" - }, - "gas_pressure":{ - "pressure_gauge":"@link:/entry/instrument/pressure_gauge" - }, - "bias":{ - "potentiostat":"@link:/entry/instrument/manipulator/sample_bias_potentiostat", - "voltmeter":"@link:/entry/instrument/manipulator/sample_bias_voltmeter" - }, - "drain_current":{ - "amperemeter":"@link:/entry/instrument/manipulator/drain_current_amperemeter" - }, - "flood_gun_current":{ - "flood_gun":"@link:/entry/instrument/flood_gun" - } - }, - "/ENTRY[entry]/data":{ - "@signal":"data", - "@axes":["energy"], - "data":"@data:cycle", - "data/@units":"@xps_token:data/y_units_1", - "energy": "@data:energy", - "energy/@type":"@xps_token:data/x_units_1", - "energy/@units":"eV", - "@energy_indices":"None", - "@energy_depends":"None" - } - } + "/@default":"None", + "/ENTRY[entry]":{ + "@default":"data", + "definition":"@eln", + "definition/@version":"@eln", + "title":"@eln", + "start_time":"@xps_token:region/time_stamp", + "end_time":"@eln", + "experiment_institution":"@eln", + "experiment_facility":"@eln", + "experiment_laboratory":"@eln", + "entry_identifier":"@eln", + "duration":"None", + "duration/@units":"s", + "method":"@xps_token:region/analysis_method", + "program_name":"@eln" + }, + "/ENTRY[entry]/USER[user]":{ + "name":"@eln", + "affiliation":"@eln", + "address":"@eln", + "orcid":"@eln", + "email":"@eln" + }, + "/ENTRY[entry]/INSTRUMENT[instrument]":{ + "@default":"electronanalyser", + "device_information":{ + "vendor":"@eln", + "identifier":"@eln", + "model":"@eln" + }, + "energy_resolution":{ + "physical_quantity":"energy", + "type":"derived", + "resolution":"@xps_token:data/step_size", + "resolution/@units":"eV" + }, + "source_TYPE[source_probe]":{ + "type":"@eln", + "name":"@xps_token:source/source_label", + "probe":"photon", + "device_information":{ + "vendor":"@eln", + "identifier":"@eln", + "model":"@eln" + }, + "associated_beam":"@link:/entry/instrument/beam_probe", + "source_analyzer_angle":"source_analyzer_angle", + "source_analyzer_angle/@units":"degree" + }, + "beam_TYPE[beam_probe]":{ + "distance":"@eln", + "distance/@units":"@eln", + "incident_energy":"@xps_token:beam/excitation_energy", + "incident_energy/@units":"eV", + "incident_energy_spread":"None", + "incident_energy_spread/@units":"None", + "incident_polarization":"None", + "incident_polarization/@units":"None", + "extent":"None", + "associated_source":"@link:/entry/instrument/source_probe" + }, + "ELECTRONANALYSER[electronanalyser]":{ + "@default":"detector0", + "name":"@xps_token:analyser/analyser_name", + "description":"@eln", + "work_function":"@xps_token:analyser/work_function", + "work_function/@units":"eV", + "fast_axes":"None", + "slow_axes":"energy", + "analyzer_take_off_azimuth":"@xps_token:analyser/analyzer_take_off_azimuth", + "analyzer_take_off_azimuth/@units":"degree", + "analyzer_take_off_polar":"@xps_token:analyser/analyzer_take_off_polar", + "analyzer_take_off_polar/@units":"degree", + "analysis_width_x":"@xps_token:analyser/analysis_width_x", + "analysis_width_x/@units":"mm", + "analysis_width_y":"@xps_token:analyser/analysis_width_y", + "analysis_width_y/@units":"mm", + "target_bias":"@xps_token:analyser/target_bias", + "target_bias/@units":"V", + "device_information":{ + "vendor":"@eln", + "model":"@eln", + "identifier":"@eln" + }, + "energy_resolution":{ + "physical_quantity":"energy", + "type":"estimated", + "resolution":"@xps_token:data/step_size", + "resolution/@units":"eV" + }, + "transmission_function":{ + "@signal":"relative_intensity", + "@axes":[ + "kinetic_energy" + ], + "kinetic_energy":"@xps_token:transmission_function/kinetic_energy", + "kinetic_energy/@units":"@xps_token:transmission_function/kinetic_energy/@units", + "relative_intensity":"@xps_token:collectioncolumn/transmission_function/relative_intensity" + }, + "COLLECTIONCOLUMN[collectioncolumn]":{ + "scheme":"@eln", + "lens_mode":"@xps_token:collectioncolumn/lens_mode", + "projection":"None", + "angular_acceptance":"None", + "spatial_acceptance":"None", + "field_aperture":"None", + "contrast_aperture":"None", + "device_information":{ + "vendor":"@eln", + "model":"@eln", + "identifier":"@eln" + } + }, + "ENERGYDISPERSION[energydispersion]":{ + "scheme":"@eln", + "pass_energy":"@xps_token:energydispersion/pass_energy", + "pass_energy/@units":"@xps_token:energydispersion/pass_energy/@units", + "energy_scan_mode":"@xps_token:energydispersion/scan_mode", + "entrance_slit":"@eln", + "exit_slit":"@eln", + "device_information":{ + "vendor":"@eln", + "model":"@eln", + "identifier":"@eln" + } + }, + "DETECTOR[detector]":{ + "@default":"raw_data", + "amplifier_type":"@eln", + "detector_type":"@eln", + "detector_voltage":"@xps_token:detector/detector_voltage", + "detector_voltage/@units":"V", + "count_time":"@xps_token:detector/dwell_time", + "count_time/@units":"s", + "acquisition_mode":"@xps_token:detector/signal_mode", + "device_information":{ + "vendor":"@eln", + "model":"@eln", + "identifier":"@eln" + }, + "raw_data":{ + "@signal":"raw", + "raw":"@detector_data:cycles/Cycle_", + "raw/@units":"counts" + } + } + }, + "MANIPULATOR[manipulator]":{ + "device_information":{ + "vendor":"@eln", + "model":"@eln", + "identifier":"@eln" + }, + "temperature_sensor":{ + "name":"@eln", + "measurement":"@eln", + "type":"@eln", + "attached_to":"@eln", + "value":"@eln" + }, + "sample_heater":{ + "name":"@eln", + "physical_quantity":"@eln", + "type":"@eln", + "heater_power":"@eln", + "PID[pid]/setpoint":"@eln" + }, + "cryostat":{ + "name":"None", + "physical_quantity":"None", + "type":"None", + "PID[pid]/setpoint":"None" + }, + "drain_current_amperemeter":{ + "name":"@eln", + "measurement":"@eln", + "type":"@eln", + "value":"@eln" + }, + "sample_bias_voltmeter":{ + "name":"@eln", + "measurement":"@eln", + "type":"@eln", + "value":"@xps_token:sample/target_bias", + "value/@units":"V" + }, + "sample_bias_potentiostat":{ + "name":"@eln", + "physical_quantity":"@eln", + "type":"@eln", + "PID[pid]/setpoint":"@eln" + } + }, + "pressure_gauge":{ + "name":"@eln", + "measurement":"@eln", + "type":"@eln", + "value":"@eln", + "value_log/value":"@eln" + }, + "flood_gun":{ + "name":"@eln", + "physical_quantity":"@eln", + "type":"@eln", + "current":"@eln", + "current_log/value":"@eln" + } + }, + "/ENTRY[entry]/PROCESS[process]":{ + "energy_calibration":{ + "calibrated_axis":"@data:energy", + "calibrated_axis/@units":"eV" + }, + "energy_referencing":{ + "level":"None", + "reference_peak":"None", + "binding_energy":"None", + "offset":"None", + "calibrated_axis":"None" + }, + "transmission_correction":{ + "transmission_function":{ + "@axes":"None", + "@signal":"None", + "kinetic_energy":"None", + "kinetic_energy/@units":"None", + "relative_intensity":"None" + } + } + }, + "/ENTRY[entry]/SAMPLE[sample]":{ + "name":"@eln", + "sample_id":"@eln", + "atom_types":"@eln", + "physical_form":"@eln", + "situation":"@eln", + "SUBSTANCE[substance]":{ + "name":"@eln", + "molecular_mass":"@eln", + "cas_number":"@eln", + "molecular_formula_hill":"@eln" + }, + "sample_history":{ + "sample_preparation":{ + "start_time":"@eln", + "end_time":"@eln", + "description":"@eln", + "method":"@eln" + }, + "PHYSICAL_PROCESS[sample_loading]":{ + "start_time":"@eln", + "end_time":"@eln", + "description":"@eln", + "method":"@eln" + } + }, + "temperature":{ + "temperature_sensor":"@link:/entry/instrument/manipulator/temperature_sensor", + "sample_heater":"@link:/entry/instrument/manipulator/sample_heater", + "cryostat":"None" + }, + "gas_pressure":{ + "pressure_gauge":"@link:/entry/instrument/pressure_gauge" + }, + "bias":{ + "potentiostat":"@link:/entry/instrument/manipulator/sample_bias_potentiostat", + "voltmeter":"@link:/entry/instrument/manipulator/sample_bias_voltmeter" + }, + "drain_current":{ + "amperemeter":"@link:/entry/instrument/manipulator/drain_current_amperemeter" + }, + "flood_gun_current":{ + "flood_gun":"@link:/entry/instrument/flood_gun" + } + }, + "/ENTRY[entry]/data":{ + "@signal":"data", + "@axes":[ + "energy" + ], + "data":"@data:cycle", + "data/@units":"@xps_token:data/y_units_1", + "energy":"@data:energy", + "energy/@type":"@xps_token:data/x_units_1", + "energy/@units":"eV", + "@energy_indices":"None", + "@energy_depends":"None" + } + } \ No newline at end of file From 27284611f5c282f84e914affffdc851f4b92504a Mon Sep 17 00:00:00 2001 From: Lukas Pielsticker <50139597+lukaspie@users.noreply.github.com> Date: Fri, 15 Mar 2024 11:22:02 +0100 Subject: [PATCH 41/41] change some static typing --- pynxtools_xps/vms/vamas.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pynxtools_xps/vms/vamas.py b/pynxtools_xps/vms/vamas.py index ead0e181..97c2e160 100644 --- a/pynxtools_xps/vms/vamas.py +++ b/pynxtools_xps/vms/vamas.py @@ -749,15 +749,15 @@ def _add_data_values(self, block: VamasBlock): def _add_regular_data(self, block: VamasBlock): """Parse data with regularly spaced energy axis.""" - data_dict: Dict[str, List] = {} + data_dict: Dict[str, np.ndarray] = {} start = float(block.abscissa_start) step = float(block.abscissa_step) num = int(block.num_ord_values / block.no_variables) - energy = [round(start + i * step, 2) for i in range(num)] + energy = np.array([round(start + i * step, 2) for i in range(num)]) if block.abscissa_label == "binding energy": - energy.reverse() + energy = np.flip(energy) setattr(block, "x", energy) @@ -766,7 +766,6 @@ def _add_regular_data(self, block: VamasBlock): name = "y" else: name = "y" + str(var) - data_dict[name] = [] data_array = np.array(self.data[: block.num_ord_values], dtype=float) @@ -784,13 +783,13 @@ def _add_regular_data(self, block: VamasBlock): def _add_irregular_data(self, block: VamasBlock): """Parse data with regularly spaced energy axis.""" - data_dict: Dict[str, List] = {} + data_dict: Dict[str, np.ndarray] = {} block_data = np.array(self.data[: block.num_ord_values], dtype=float) energy = block_data[:: block.no_variables + 1] if block.abscissa_label == "binding energy": - energy.reverse() + energy = np.flip(energy) setattr(block, "x", energy) block.abscissa_start = float(min(energy)) @@ -801,7 +800,6 @@ def _add_irregular_data(self, block: VamasBlock): name = "y" else: name = "y" + str(var) - data_dict[name] = [] for var in range(block.no_variables): if var == 0: @@ -1060,7 +1058,7 @@ def build_list(self): if block.variable_label_1 in ["Intensity", "counts"]: y_cps = [np.round(y / block.dwell_time, 2) for y in block.y] - data["y_cps"] = y_cps + data["y_cps"] = np.array(y_cps) else: key = "y" + str(var)