Repository 'larch_athena'
hg clone https://toolshed.g2.bx.psu.edu/repos/muon-spectroscopy-computational-project/larch_athena

Changeset 1:2b3115342fef (2023-12-06)
Previous changeset 0:ae2f265ecf8e (2023-11-14) Next changeset 2:a1e26990131c (2024-03-04)
Commit message:
planemo upload for repository https://github.com/MaterialsGalaxy/larch-tools/tree/main/larch_athena commit 1cf6d7160497ba58fe16a51f00d088a20934eba6
modified:
common.py
larch_athena.py
larch_athena.xml
macros.xml
added:
test-data/ffi1.tabular
test-data/multiple.prj
b
diff -r ae2f265ecf8e -r 2b3115342fef common.py
--- a/common.py Tue Nov 14 15:34:40 2023 +0000
+++ b/common.py Wed Dec 06 13:03:55 2023 +0000
[
@@ -7,38 +7,145 @@
 
 
 def get_group(athena_group: AthenaGroup, key: str = None) -> Group:
+    group_keys = list(athena_group._athena_groups.keys())
     if key is None:
-        group_keys = list(athena_group._athena_groups.keys())
         key = group_keys[0]
-    return extract_athenagroup(athena_group._athena_groups[key])
+    else:
+        key = key.replace("-", "_")
+
+    try:
+        return extract_athenagroup(athena_group._athena_groups[key])
+    except KeyError as e:
+        raise KeyError(f"{key} not in {group_keys}") from e
+
+
+def read_all_groups(dat_file: str, key: str = None) -> "dict[str, Group]":
+    # Cannot rely on do_ABC as _larch is None
+    athena_group = read_athena(
+        dat_file,
+        do_preedge=False,
+        do_bkg=False,
+        do_fft=False,
+    )
+    all_groups = {}
+    for key in athena_group._athena_groups.keys():
+        group = get_group(athena_group, key)
+        pre_edge_with_defaults(group=group)
+        xftf_with_defaults(group=group)
+        all_groups[key] = group
+
+    return all_groups
+
+
+def read_group(dat_file: str, key: str = None):
+    # Cannot rely on do_ABC as _larch is None
+    athena_group = read_athena(
+        dat_file,
+        do_preedge=False,
+        do_bkg=False,
+        do_fft=False,
+    )
+    group = get_group(athena_group, key)
+    pre_edge_with_defaults(group=group)
+    xftf_with_defaults(group=group)
+    return group
 
 
-def read_group(dat_file: str, key: str = None, xftf_params: dict = None):
-    athena_group = read_athena(dat_file)
-    group = get_group(athena_group, key)
-    bkg_parameters = group.athena_params.bkg
-    print(group.athena_params.fft)
-    print(group.athena_params.fft.__dict__)
-    pre_edge(
-        group,
-        e0=bkg_parameters.e0,
-        pre1=bkg_parameters.pre1,
-        pre2=bkg_parameters.pre2,
-        norm1=bkg_parameters.nor1,
-        norm2=bkg_parameters.nor2,
-        nnorm=bkg_parameters.nnorm,
-        make_flat=bkg_parameters.flatten,
+def pre_edge_with_defaults(group: Group, settings: dict = None):
+    merged_settings = {}
+    try:
+        bkg_parameters = group.athena_params.bkg
+    except AttributeError as e:
+        print(f"Cannot load group.athena_params.bkg from group:\n{e}")
+        bkg_parameters = None
+
+    keys = (
+        ("e0", "e0", None),
+        ("pre1", "pre1", None),
+        ("pre2", "pre2", None),
+        ("norm1", "nor1", None),
+        ("norm2", "nor2", None),
+        ("nnorm", "nnorm", None),
+        ("make_flat", "flatten", None),
+        ("step", "step", None),
+        # This cannot be read from file as it is not stored by Larch (0.9.71)
+        # ("nvict", "nvict", None),
     )
-    autobk(group)
-    if xftf_params is None:
-        xftf(group)
-    else:
-        print(xftf_params)
-        xftf(group, **xftf_params)
-        xftf_details = Group()
-        setattr(xftf_details, "call_args", xftf_params)
-        group.xftf_details = xftf_details
-    return group
+    for key, parameters_key, default in keys:
+        extract_attribute(
+            merged_settings, key, bkg_parameters, parameters_key, default
+        )
+
+    if settings:
+        for k, v in settings.items():
+            if k == "nvict":
+                print(
+                    "WARNING: `nvict` can be used for pre-edge but is not "
+                    "saved to file, so value used will not be accessible in "
+                    "future operations using this Athena .prj"
+                )
+            merged_settings[k] = v
+
+    print(f"Pre-edge normalization with {merged_settings}")
+    try:
+        pre_edge(group, **merged_settings)
+    except Warning as e:
+        raise Warning(
+            "Unable to perform pre-edge fitting with:\n\n"
+            f"energy:\n{group.energy}\n\nmu:{group.mu}\n\n"
+            "Consider checking the correct columns have been extracted"
+        ) from e
+    autobk(group, pre_edge_kws=merged_settings)
+
+
+def xftf_with_defaults(group: Group, settings: dict = None):
+    merged_settings = {}
+    try:
+        fft_parameters = group.athena_params.fft
+    except AttributeError as e:
+        print(f"Cannot load group.athena_params.fft from group:\n{e}")
+        fft_parameters = None
+
+    keys = (
+        ("kmin", "kmin", 0),
+        ("kmax", "kmax", 20),
+        ("dk", "dk", 1),
+        ("kweight", "kw", 2),
+        ("kweight", "kweight", 2),
+        ("window", "kwindow", "kaiser"),
+    )
+    for key, parameters_key, default in keys:
+        extract_attribute(
+            merged_settings, key, fft_parameters, parameters_key, default
+        )
+
+    if settings:
+        for k, v in settings.items():
+            merged_settings[k] = v
+
+    print(f"XFTF with {merged_settings}")
+    xftf(group, **merged_settings)
+    xftf_details = Group()
+    setattr(xftf_details, "call_args", merged_settings)
+    group.xftf_details = xftf_details
+
+
+def extract_attribute(
+    merged_settings: dict,
+    key: str,
+    parameters_group: Group,
+    parameters_key: str,
+    default: "str|int" = None,
+):
+    if parameters_group is not None:
+        try:
+            merged_settings[key] = getattr(parameters_group, parameters_key)
+            return
+        except AttributeError:
+            pass
+
+    if default is not None:
+        merged_settings[key] = default
 
 
 def read_groups(dat_files: "list[str]", key: str = None) -> Iterable[Group]:
b
diff -r ae2f265ecf8e -r 2b3115342fef larch_athena.py
--- a/larch_athena.py Tue Nov 14 15:34:40 2023 +0000
+++ b/larch_athena.py Wed Dec 06 13:03:55 2023 +0000
[
b'@@ -4,7 +4,9 @@\n import re\n import sys\n \n-from common import read_group\n+from common import (\n+    pre_edge_with_defaults, read_all_groups, read_group, xftf_with_defaults\n+)\n \n from larch.io import (\n     create_athena,\n@@ -14,7 +16,7 @@\n     set_array_labels,\n )\n from larch.symboltable import Group\n-from larch.xafs import autobk, pre_edge, rebin_xafs, xftf\n+from larch.xafs import rebin_xafs\n \n import matplotlib\n import matplotlib.pyplot as plt\n@@ -27,13 +29,11 @@\n         self,\n         energy_column: str,\n         mu_column: str,\n-        xftf_params: dict,\n         data_format: str,\n-        extract_group: str = None,\n+        extract_group: "dict[str, str]" = None,\n     ):\n         self.energy_column = energy_column\n         self.mu_column = mu_column\n-        self.xftf_params = xftf_params\n         self.data_format = data_format\n         self.extract_group = extract_group\n \n@@ -72,13 +72,24 @@\n         self,\n         filepath: str,\n         is_zipped: bool = False,\n-    ) -> "dict[str,Group]":\n+    ) -> "tuple[dict, bool]":\n         if is_zipped:\n             return self.load_zipped_files()\n \n         print(f"Attempting to read from {filepath}")\n         if self.data_format == "athena":\n-            group = read_group(filepath, self.extract_group, self.xftf_params)\n+            if self.extract_group["extract_group"] == "single":\n+                group = read_group(filepath, self.extract_group["group_name"])\n+                return {"out": group}\n+            elif self.extract_group["extract_group"] == "multiple":\n+                groups = {}\n+                for repeat in self.extract_group["multiple"]:\n+                    name = repeat["group_name"]\n+                    groups[name] = read_group(filepath, name)\n+                return groups\n+            else:\n+                return read_all_groups(filepath)\n+\n         else:\n             # Try ascii anyway\n             try:\n@@ -90,7 +101,9 @@\n             except (UnicodeDecodeError, TypeError):\n                 # Indicates this isn\'t plaintext, try h5\n                 group = self.load_h5(filepath)\n-        return {"out": group}\n+            pre_edge_with_defaults(group)\n+            xftf_with_defaults(group)\n+            return {"out": group}\n \n     def load_ascii(self, dat_file):\n         with open(dat_file) as f:\n@@ -156,27 +169,27 @@\n \n         if "energy" in labels:\n             print("\'energy\' present in column headers")\n-        elif self.energy_column is not None:\n+        elif self.energy_column:\n             if self.energy_column.lower() in labels:\n                 labels[labels.index(self.energy_column.lower())] = "energy"\n             else:\n                 raise ValueError(f"{self.energy_column} not found in {labels}")\n         else:\n             for i, label in enumerate(labels):\n-                if label == "col1" or label.endswith("energy"):\n+                if label in ("col1", "ef") or label.endswith("energy"):\n                     labels[i] = "energy"\n                     break\n \n         if "mu" in labels:\n             print("\'mu\' present in column headers")\n-        elif self.mu_column is not None:\n+        elif self.mu_column:\n             if self.mu_column.lower() in labels:\n                 labels[labels.index(self.mu_column.lower())] = "mu"\n             else:\n                 raise ValueError(f"{self.mu_column} not found in {labels}")\n         else:\n             for i, label in enumerate(labels):\n-                if label in ["col2", "xmu", "lni0it", "ffi0"]:\n+                if label in ["col2", "xmu", "lni0it", "ffi0", "ff/i1"]:\n                     labels[i] = "mu"\n                     break\n \n@@ -189,29 +202,24 @@\n \n def calibrate_energy(\n     xafs_group: Group,\n-    energy_0: float,\n-    energy_min: float,\n-    energy_max: float,\n-    energy_format: str,\n+    calibration_e0: float = None,\n+    energy_min: float = None,\n+    energy_max: float = None,\n ):\n-    if energy_0 is not None:\n-        print(f"Recalibrating energy edge from {xafs_gr'..b'xas_data.mu,\n+            group=xas_data,\n+            **pre_edge_settings,\n+        )\n+        xas_data = xas_data.rebinned\n+        # After re-bin, will need to redo pre-edge\n+        do_pre_edge = True\n \n-    if input_values["rebin"]:\n-        print(xas_data.energy, xas_data.mu)\n-        rebin_xafs(energy=xas_data.energy, mu=xas_data.mu, group=xas_data)\n-        xas_data = xas_data.rebinned\n-        pre_edge(energy=xas_data.energy, mu=xas_data.mu, group=xas_data)\n+    if do_pre_edge:\n+        pre_edge_with_defaults(xas_data, pre_edge_settings)\n \n-    try:\n-        autobk(xas_data)\n-    except ValueError as e:\n-        raise ValueError(\n-            f"autobk failed with energy={xas_data.energy}, mu={xas_data.mu}.\\n"\n-            "This may occur if the edge is not included in the above ranges."\n-        ) from e\n-    xftf(xas_data, **xftf_params)\n+    if do_xftf:\n+        xftf_with_defaults(xas_data, xftf_settings)\n \n-    if input_values["plot_graph"]:\n+    if plot_graph:\n         plot_edge_fits(f"edge/{path_key}.png", xas_data)\n         plot_flattened(f"flat/{path_key}.png", xas_data)\n         plot_derivative(f"derivative/{path_key}.png", xas_data)\n \n     xas_project = create_athena(f"prj/{path_key}.prj")\n     xas_project.add_group(xas_data)\n-    if input_values["annotation"]:\n+    if annotation:\n         group = next(iter(xas_project.groups.values()))\n-        group.args["annotation"] = input_values["annotation"]\n+        group.args["annotation"] = annotation\n     xas_project.save()\n \n     # Ensure that we do not run out of memory when running on large zips\n     gc.collect()\n \n \n-def validate_pre(pre, energy_0, energy_format):\n-    if pre is not None and energy_format == "absolute":\n-        if energy_0 is None:\n-            raise ValueError(\n-                "Edge energy must be set manually or be present in the "\n-                "existing Athena project if using absolute format."\n-            )\n-        pre -= energy_0\n-\n-    return pre\n-\n-\n def plot_derivative(plot_path: str, xafs_group: Group):\n     plt.figure()\n     plt.plot(xafs_group.energy, xafs_group.dmude)\n@@ -363,9 +347,8 @@\n         )\n     else:\n         is_zipped = False\n-    xftf_params = input_values["variables"]["xftf"]\n+\n     extract_group = None\n-\n     if "extract_group" in input_values["merge_inputs"]["format"]:\n         extract_group = input_values["merge_inputs"]["format"]["extract_group"]\n \n@@ -379,7 +362,6 @@\n     reader = Reader(\n         energy_column=energy_column,\n         mu_column=mu_column,\n-        xftf_params=xftf_params,\n         data_format=data_format,\n         extract_group=extract_group,\n     )\n@@ -388,9 +370,35 @@\n         merge_inputs=merge_inputs,\n         is_zipped=is_zipped,\n     )\n+\n+    calibrate_items = input_values["processing"]["calibrate"].items()\n+    calibrate_settings = {k: v for k, v in calibrate_items if v is not None}\n+    do_calibrate = calibrate_settings.pop("calibrate") == "true"\n+\n+    do_rebin = input_values["processing"].pop("rebin")\n+\n+    pre_edge_items = input_values["processing"]["pre_edge"].items()\n+    pre_edge_settings = {k: v for k, v in pre_edge_items if v is not None}\n+    do_pre_edge = pre_edge_settings.pop("pre_edge") == "true"\n+\n+    xftf_items = input_values["processing"]["xftf"].items()\n+    xftf_settings = {k: v for k, v in xftf_items if v is not None}\n+    do_xftf = xftf_settings.pop("xftf") == "true"\n+\n+    plot_graph = input_values["plot_graph"]\n+    annotation = input_values["annotation"]\n+\n     for key, group in keyed_data.items():\n         main(\n             group,\n-            input_values=input_values,\n+            do_calibrate=do_calibrate,\n+            calibrate_settings=calibrate_settings,\n+            do_rebin=do_rebin,\n+            do_pre_edge=do_pre_edge,\n+            pre_edge_settings=pre_edge_settings,\n+            do_xftf=do_xftf,\n+            xftf_settings=xftf_settings,\n+            plot_graph=plot_graph,\n+            annotation=annotation,\n             path_key=key,\n         )\n'
b
diff -r ae2f265ecf8e -r 2b3115342fef larch_athena.xml
--- a/larch_athena.xml Tue Nov 14 15:34:40 2023 +0000
+++ b/larch_athena.xml Wed Dec 06 13:03:55 2023 +0000
[
b'@@ -4,7 +4,7 @@\n         <!-- version of underlying tool (PEP 440) -->\n         <token name="@TOOL_VERSION@">0.9.71</token>\n         <!-- version of this tool wrapper (integer) -->\n-        <token name="@WRAPPER_VERSION@">0</token>\n+        <token name="@WRAPPER_VERSION@">1</token>\n         <!-- citation should be updated with every underlying tool version -->\n         <!-- typical fields to update are version, month, year, and doi -->\n         <token name="@TOOL_CITATION@">10.1088/1742-6596/430/1/012007</token>\n@@ -15,11 +15,26 @@\n             </param> \n         </xml>\n         <xml name="extract_group">\n-            <param name="extract_group" type="text" optional="true" label="Extract group" help="Which group to extract and process from the Athena project (will use first group in file if unset)"/>\n+            <conditional name="extract_group">\n+                <param name="extract_group" type="select" label="Group extraction" help="Method of handling group extraction. Extracting all or multiple named groups will result in multiple outputs, unless merging groups is also true.">\n+                    <option value="single" selected="true">Extract single</option>\n+                    <option value="multiple">Extract multiple</option>\n+                    <option value="all">Extract all</option>\n+                </param>\n+                <when value="single">\n+                    <param name="group_name" type="text" optional="true" label="Group label" help="Which group to extract and process from the Athena project (will use first group in file if unset)"/>\n+                </when>\n+                <when value="multiple">\n+                    <repeat name="multiple" min="1" default="1" title="Groups">\n+                        <param name="group_name" type="text" label="Group label" help="Which group to extract and process from the Athena project (will use first group in file if unset)"/>\n+                    </repeat>\n+                </when>\n+                <when value="all"/>\n+            </conditional>\n         </xml>\n         <xml name="columns">\n-            <param name="energy_column" type="text" optional="true" label="Energy column" help="If set, this column we be used as \'energy\'. Otherwise, will identify columns ending with \'energy\' or labelled \'col1\'."/>\n-            <param name="mu_column" type="text" optional="true" label="\xce\xbc column" help="If set, this column we be used as \'mu\'. Otherwise, will identify the first column labelled as either \'col2\', \'xmu\', \'lni0it\' or \'FFI0\'."/>\n+            <param name="energy_column" type="text" optional="true" label="Energy column" help="If set, this column we be used as \'energy\'. Otherwise, will identify the first column ending with \'energy\' or labelled \'col1\' \'Ef\'."/>\n+            <param name="mu_column" type="text" optional="true" label="\xce\xbc column" help="If set, this column we be used as \'mu\'. Otherwise, will identify the first column labelled as either \'col2\', \'xmu\', \'lni0it\', \'FFI0\' or \'FF/I1\'."/>\n         </xml>\n         <xml name="is_zipped">\n             <param name="is_zipped" type="select" display="radio" label="Inputs Zipped" help="Whether plaintext input files are zipped together into one directory, or not.">\n@@ -40,6 +55,7 @@\n     </requirements>\n     <required_files>\n         <include type="literal" path="larch_athena.py"/>\n+        <include type="literal" path="common.py"/>\n     </required_files>\n     <command detect_errors="exit_code"><![CDATA[\n         mkdir prj edge flat derivative\n@@ -111,16 +127,55 @@\n             </when>\n         </conditional>\n         <param name="annotation" type="text" label="Annotation" optional="true" help="If set, will annotate the output project(s) with this string. This will be used to generate legends when plotting data."/>\n-        <section name="variables" title="Processing Options">\n-            <param name="energy_0" type="float" label="Edge energy (eV)" optional="true" help="If set, data will be calibrated so that the edge occur'..b'"4">\n             <param name="dat_file" value="test.xmu"/>\n-            <param name="energy_format" value="absolute"/>\n+            <param name="calibrate" value="true"/>\n             <param name="energy_min" value="7000"/>\n             <param name="energy_max" value="7200"/>\n             <param name="plot_graph" value="true"/>\n@@ -259,32 +329,34 @@\n             </output>\n             <output name="edge_plot">\n                 <assert_contents>\n-                    <has_size value="44430" delta="10"/>\n+                    <has_size value="44900" delta="100"/>\n                 </assert_contents>\n             </output>\n             <output name="flat_plot">\n                 <assert_contents>\n-                    <has_size value="37310" delta="10"/>\n+                    <has_size value="39400" delta="100"/>\n                 </assert_contents>\n             </output>\n             <output name="derivative_plot">\n                 <assert_contents>\n-                    <has_size value="46390" delta="10"/>\n+                    <has_size value="45900" delta="100"/>\n                 </assert_contents>\n             </output>\n         </test>\n+        <!-- 9 -->\n         <test expect_num_outputs="1">\n             <param name="dat_file" value="test.xmu"/>\n-            <param name="energy_format" value="absolute"/>\n-            <param name="energy_0" value="7050"/>\n+            <param name="calibrate" value="true"/>\n+            <param name="calibration_e0" value="7050"/>\n             <param name="energy_min" value="7000"/>\n             <param name="energy_max" value="7200"/>\n             <output name="athena_project_file">\n                 <assert_contents>\n-                    <has_size value="3300" delta="50"/>\n+                    <has_size value="3600" delta="100"/>\n                 </assert_contents>\n             </output>\n         </test>\n+        <!-- 10 -->\n         <test expect_num_outputs="1">\n             <param name="dat_file" value="test.xmu"/>\n             <param name="rebin" value="true"/>\n@@ -294,6 +366,7 @@\n                 </assert_contents>\n             </output>\n         </test>\n+        <!-- 11 -->\n         <test expect_num_outputs="1">\n             <param name="merge_inputs" value="true"/>\n             <param name="dat_file" value="262875_PtSn_OCO_Abu_1.nxs,262876_PtSn_OCO_Abu_2.nxs"/>\n@@ -303,6 +376,7 @@\n                 </assert_contents>\n             </output>\n         </test>\n+        <!-- 12 -->\n         <test expect_num_outputs="1">\n             <param name="merge_inputs" value="true"/>\n             <param name="is_zipped" value="true"/>\n@@ -313,6 +387,7 @@\n                 </assert_contents>\n             </output>\n         </test>\n+        <!-- 13 -->\n         <test expect_num_outputs="1">\n             <param name="format" value="athena"/>\n             <param name="dat_file" value="test.prj"/>\n@@ -322,6 +397,22 @@\n                 </assert_contents>\n             </output>\n         </test>\n+        <!-- 14: Extract multiple groups from Athena .prj -->\n+        <test expect_num_outputs="1">\n+            <param name="format" value="athena"/>\n+            <param name="extract_group" value="multiple"/>\n+            <param name="group_name" value="merge"/>\n+            <param name="group_name" value="d__Ref_PtSn_OC_MERGE_CALIBRATE"/>\n+            <param name="dat_file" value="multiple.prj"/>\n+            <output_collection name="athena_project_file_collection" type="list" count="2"/>\n+        </test>\n+        <!-- 15: Extract all groups from Athena .prj -->\n+        <test expect_num_outputs="1">\n+            <param name="format" value="athena"/>\n+            <param name="extract_group" value="all"/>\n+            <param name="dat_file" value="multiple.prj"/>\n+            <output_collection name="athena_project_file_collection" type="list" count="9"/>\n+        </test>\n     </tests>\n     <help><![CDATA[\n         Using Larch, create an Athena project file from the input X-ray Absorption Fine Structure (XAFS) data file.\n'
b
diff -r ae2f265ecf8e -r 2b3115342fef macros.xml
--- a/macros.xml Tue Nov 14 15:34:40 2023 +0000
+++ b/macros.xml Wed Dec 06 13:03:55 2023 +0000
b
@@ -1,26 +1,6 @@
 <macros>
-    <xml name="energy_limits">
-        <param name="energy_format" type="select" display="radio" label="Energy limits" help="Whether to limit the energy relative to the absorption edge or with absolute values.">
-            <option value="relative" selected="true">Relative</option>
-            <option value="absolute">Absolute</option>
-        </param>
-        <param name="energy_min" type="float" label="Minimum energy (eV)" optional="true" help="If set, data will be cropped below this value in electron volts."/>
-        <param name="energy_max" type="float" label="Maximum energy (eV)" optional="true" help="If set, data will be cropped above this value in electron volts."/>
-    </xml>
-    <xml name="xftf_params">
-        <param argument="kmin" type="float" value="0" min="0.0" help="Minimum k value."/>
-        <param argument="kmax" type="float" value="20" min="0.0" help="Maximum k value."/>
-        <param argument="kweight" type="float" value="2" help="Exponent for weighting spectra by raising k to this power."/>
-        <param argument="dk" type="float" value="4" help="Tapering parameter for Fourier Transform window."/>
-        <param argument="window" type="select" help="Fourier Transform window type.">
-            <option value="hanning">Hanning (cosine-squared taper)</option>
-            <option value="parzen">Parzen (linear taper)</option>
-            <option value="welch">Welch (quadratic taper)</option>
-            <option value="gaussian">Gaussian function window</option>
-            <option value="sine">Sine function window</option>
-            <option value="kaiser" selected="true">Kaiser-Bessel function-derived window</option>
-        </param>
-        <param argument="rmin" type="float" value="0.0" min="0.0" help="Minimum radial distance."/>
-        <param argument="rmax" type="float" value="10.0" min="0.0" help="Maximum radial distance."/>
+    <xml name="plot_limits_energy">
+        <param name="x_limit_min" type="float" label="Minimum plot energy (eV)" optional="true" help="If set, plot will be limited to this value on the x axis."/>
+        <param name="x_limit_max" type="float" label="Maximum plot energy (eV)" optional="true" help="If set, plot will be limited to this value on the x axis."/>
     </xml>
 </macros>
\ No newline at end of file
b
diff -r ae2f265ecf8e -r 2b3115342fef test-data/ffi1.tabular
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/ffi1.tabular Wed Dec 06 13:03:55 2023 +0000
b
b'@@ -0,0 +1,355 @@\n+# Energy        \tFF/I1       \tTime\n+  6911.8277       0.80926541        272002.00\n+  6916.9236       0.80418730        270032.00\n+  6921.7638       0.79959074        268827.00\n+  6926.8750       0.79459529        267514.00\n+  6931.7907       0.79004613        255214.00\n+\n+  6962.0000       0.78791063        305150.00\n+  6972.0000       0.77475191        306445.00\n+  6982.0000       0.76169076        306446.00\n+  6992.0000       0.74992551        306744.00\n+  7002.0000       0.73660315        306246.00\n+  7012.0000       0.72423404        306358.00\n+  7022.0000       0.71196509        306309.00\n+  7032.0000       0.70002723        306019.00\n+  7042.0000       0.68735767        306529.00\n+  7052.0000       0.67439453        306124.00\n+  7062.0000       0.66235517        306188.00\n+  7072.0000       0.65022361        306119.00\n+  7082.0000       0.63942705        306143.00\n+  7092.0000       0.62824650        306098.00\n+  7092.5000       0.62753795        305825.00\n+  7093.0000       0.62748380        305756.00\n+  7093.5000       0.62785219        305745.00\n+  7094.0000       0.62636441        305717.00\n+  7094.5000       0.62575793        305670.00\n+  7095.0000       0.62551244        305666.00\n+  7095.5000       0.62515947        305631.00\n+  7096.0000       0.62492947        305585.00\n+  7096.5000       0.62367544        305536.00\n+  7097.0000       0.62332504        305539.00\n+  7097.5000       0.62259547        305510.00\n+  7098.0000       0.62252464        305466.00\n+  7098.5000       0.62240279        305494.00\n+  7099.0000       0.62172416        305432.00\n+  7099.5000       0.62098768        305503.00\n+  7100.0000       0.62118707        305402.00\n+  7100.5000       0.62045272        305414.00\n+  7101.0000       0.62040785        305391.00\n+  7101.5000       0.62002332        305400.00\n+  7102.0000       0.61932445        305952.00\n+  7102.5000       0.61954721        305420.00\n+  7103.0000       0.61934375        304860.00\n+  7103.5000       0.61907141        305180.00\n+  7104.0000       0.61843263        305180.00\n+  7104.5000       0.61879967        305435.00\n+  7105.0000       0.61854579        305144.00\n+  7105.5000       0.61837948        305045.00\n+  7106.0000       0.61887282        304943.00\n+  7106.5000       0.61837848        305015.00\n+  7107.0000       0.61844121        305023.00\n+  7107.5000       0.61908174        304990.00\n+  7108.0000       0.62025344        305117.00\n+  7108.5000       0.62083284        305305.00\n+  7109.0000       0.62279082        304852.00\n+  7109.5000       0.62484776        304938.00\n+  7110.0000       0.63029578        305214.00\n+  7110.5000       0.63827614        304831.00\n+  7111.0000       0.65354125        304668.00\n+  7111.5000       0.67171017        304489.00\n+  7112.0000       0.68465719        304804.00\n+  7112.5000       0.68977450        304821.00\n+  7113.0000       0.68982223        304700.00\n+  7113.5000       0.68880150        304652.00\n+  7114.0000       0.68631667        304907.00\n+  7114.5000       0.68636382        304536.00\n+  7115.0000       0.69345881        305540.00\n+  7115.5000       0.71368054        306249.00\n+  7116.0000       0.75470012        306100.00\n+  7116.5000       0.82334644        305917.00\n+  7117.0000       0.91897755        306536.00\n+  7117.5000        1.0048919        306925.00\n+  7118.0000        1.0613446        306741.00\n+  7118.5000        1.1171460        306475.00\n+  7119.0000        1.1598287        306428.00\n+  7119.5000        1.1845153        306460.00\n+  7120.0000        1.1839175        306450.00\n+  7120.5000        1.1705836        306582.00\n+  7121.0000        1.1532435        306359.00\n+  7121.5000        1.1455536        306364.00\n+  7122.0000        1.1474359        306349.00\n+  7122.5000        1.1522733        306255.00\n+  7123.0000        1.1570854        306266.00\n+  7123.5000        1.1609012        306230.00\n+  7124.0000        1.1633654        306227.00\n+  7124.5000        1.1626865        30637'..b'93523        305560.00\n+  7560.2820       0.74539760        305668.00\n+  7564.4270       0.74088376        305785.00\n+  7568.5910       0.73831944        305684.00\n+  7572.7740       0.73529922        305582.00\n+  7576.9770       0.73187551        305523.00\n+  7581.1980       0.72922440        305558.00\n+  7585.4390       0.72676436        305647.00\n+  7589.6980       0.72359612        305208.00\n+  7593.9770       0.71807714        306038.00\n+  7598.2750       0.71252104        305315.00\n+  7602.5920       0.70549579        305573.00\n+  7606.9280       0.69954396        305378.00\n+  7611.2830       0.69265029        305425.00\n+  7615.6570       0.68689223        305488.00\n+  7620.0500       0.68092659        305297.00\n+  7624.4620       0.67499882        305001.00\n+  7628.8940       0.66889046        305246.00\n+  7633.3440       0.66341014        305391.00\n+  7637.8130       0.65798296        305277.00\n+  7642.3020       0.65352747        305129.00\n+  7646.8100       0.64842668        305185.00\n+  7651.3360       0.64433064        305107.00\n+  7655.8820       0.64130624        304968.00\n+  7660.4470       0.63726602        303292.00\n+  7665.0300       0.63282645        306701.00\n+  7669.6340       0.62771419        304931.00\n+  7674.2550       0.62136047        304917.00\n+  7678.8960       0.61572914        304978.00\n+  7683.5570       0.61094428        305007.00\n+  7688.2360       0.60604922        304909.00\n+  7692.9350       0.60062272        304867.00\n+  7697.6520       0.59482509        304843.00\n+  7702.3890       0.58954937        304732.00\n+  7707.1440       0.58505148        304761.00\n+  7711.9190       0.58034243        304780.00\n+  7716.7120       0.57641028        304730.00\n+  7721.5250       0.57240859        304752.00\n+  7726.3570       0.56757710        304652.00\n+  7731.2080       0.56298530        304949.00\n+  7736.0780       0.55790407        301749.00\n+  7740.9670       0.55415072        309843.00\n+  7745.8750       0.55025596        306494.00\n+  7750.8030       0.54458907        306086.00\n+  7755.7500       0.53968840        306137.00\n+  7760.7150       0.53400917        306150.00\n+  7765.6990       0.52848485        306231.00\n+  7770.7030       0.52243506        306178.00\n+  7775.7260       0.51730921        305604.00\n+  7780.7670       0.51119667        306396.00\n+  7785.8280       0.50502129        306122.00\n+  7790.9080       0.49915279        306044.00\n+  7796.0070       0.49353357        305959.00\n+  7801.1250       0.48866156        305944.00\n+  7806.2620       0.48323724        305753.00\n+  7811.4180       0.47782882        305897.00\n+  7816.5940       0.47305934        305849.00\n+  7821.7880       0.46837192        305834.00\n+  7827.0010       0.46392860        305216.00\n+  7832.2340       0.45913400        306347.00\n+  7837.4850       0.45441121        305718.00\n+  7842.7560       0.44961359        305672.00\n+  7848.0460       0.44433501        305591.00\n+  7853.3540       0.43874661        305721.00\n+  7858.6830       0.43362602        305761.00\n+  7864.0300       0.42833655        305543.00\n+  7869.3960       0.42287776        305580.00\n+  7874.7810       0.41790268        305561.00\n+  7880.1850       0.41331540        305567.00\n+  7885.6080       0.40736809        305548.00\n+  7891.0510       0.40162419        305485.00\n+  7896.5120       0.39641156        305410.00\n+  7901.9920       0.39158402        305454.00\n+  7907.4920       0.38664929        305471.00\n+  7913.0110       0.38183248        305389.00\n+  7918.5480       0.37664824        305311.00\n+  7924.1050       0.37186542        305383.00\n+  7929.6810       0.36622348        305224.00\n+  7935.2760       0.36059857        305309.00\n+  7940.8900       0.35529935        304801.00\n+  7946.5230       0.34983333        305709.00\n+  7952.1750       0.34434706        305185.00\n+  7957.8470       0.33897801        305134.00\n+  7963.5370       0.33392445        305037.00\n+  7969.2470       0.32835579        305340.00\n\\ No newline at end of file\n'
b
diff -r ae2f265ecf8e -r 2b3115342fef test-data/multiple.prj
b
Binary file test-data/multiple.prj has changed