From a99cf661227a995704a2e1e2251419a36d3a516a Mon Sep 17 00:00:00 2001 From: Kyle Beyer Date: Tue, 25 Aug 2026 22:58:24 -0400 Subject: [PATCH 1/8] Match natural targets in elastic scattering; allow repeated error columns is_match normalized EXFOR's -3000 natural-target sentinel for the target but not for the residual, so the elastic check residual == reaction.target compared (-3000, Z) against (0, Z) and every natural-abundance elastic data set failed to match. This silently dropped a large fraction of natural-target data. parse_differential_data and parse_energy_dependent_xs refused any subentry with a repeated error label ("Expected only one DATA-ERR column"). A label repeats legitimately: some subentries carry two DATA-ERR columns, one in per-cent and one absolute, each mostly null, which together make up the uncertainty. Each occurrence is now taken in turn, and determine_error_categories collects them all, so the default quadrature combination merges them. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01LSfNX9V6VEYiSsSmaJPyq5 --- src/exfor_tools/curate.py | 10 ++++++++-- src/exfor_tools/distribution.py | 8 +++++--- src/exfor_tools/exfor_entry.py | 5 +++++ src/exfor_tools/parsing.py | 27 +++++++++++++++++++++------ src/exfor_tools/reaction.py | 6 ++++++ 5 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/exfor_tools/curate.py b/src/exfor_tools/curate.py index 9dfd54c..569194a 100644 --- a/src/exfor_tools/curate.py +++ b/src/exfor_tools/curate.py @@ -405,9 +405,15 @@ def cross_reference_entry_systematic_err( def print_failed_parses(failed_parses): for k, v in failed_parses.items(): print(f"Entry: {k}") - print(v.failed_parses[k][0], " : ", v.failed_parses[k][1]) + # report every failed subentry, not just the last one recorded per entry + failures = getattr(v, "failed_parses_by_subentry", None) or dict( + [v.failed_parses[k]] + ) + for subentry, e in failures.items(): + print(subentry, " : ", e) print(v.err_analysis) - print(v.subentry_err_analysis[v.failed_parses[k][0]]) + for subentry in failures: + print(v.subentry_err_analysis[subentry]) def plot_measurements( diff --git a/src/exfor_tools/distribution.py b/src/exfor_tools/distribution.py index 4644d13..416e8d8 100644 --- a/src/exfor_tools/distribution.py +++ b/src/exfor_tools/distribution.py @@ -237,9 +237,11 @@ def determine_error_categories( statistical_err = [] for i, label in enumerate(statistical_err_labels): - if label in y_err_labels: - index = y_err_labels.index(label) - statistical_err.append(y_errs[index]) + # a label may occur more than once (e.g. two DATA-ERR columns, one in + # per-cent and one absolute); take every occurrence + for index, candidate in enumerate(y_err_labels): + if candidate == label: + statistical_err.append(y_errs[index]) if statistical_err == []: statistical_err = [np.zeros((rows))] diff --git a/src/exfor_tools/exfor_entry.py b/src/exfor_tools/exfor_entry.py index 82d8bd8..4e6dcbc 100644 --- a/src/exfor_tools/exfor_entry.py +++ b/src/exfor_tools/exfor_entry.py @@ -173,6 +173,10 @@ def __init__( self.subentries = [key[1] for key in entry_datasets.keys()] self.measurements = [] self.failed_parses = {} + # failed_parses is keyed by entry and so retains only one failure per entry, + # which loses information when several subentries of one entry fail. Keep the + # full record alongside it, keyed by subentry. + self.failed_parses_by_subentry = {} for key, data_set in entry_datasets.items(): if not isinstance(data_set.reaction[0], X4Reaction): @@ -205,6 +209,7 @@ def __init__( self.measurements.append(m) for subentry, e in failed_parses.items(): self.failed_parses[key[0]] = (subentry, e) + self.failed_parses_by_subentry[subentry] = e def bibtex(self): if self.meta is None: diff --git a/src/exfor_tools/parsing.py b/src/exfor_tools/parsing.py index 1420d6d..51f2efc 100644 --- a/src/exfor_tools/parsing.py +++ b/src/exfor_tools/parsing.py @@ -1,3 +1,4 @@ +from collections import defaultdict from functools import reduce import numpy as np @@ -108,6 +109,7 @@ def parse_energy_dependent_xs(data_set, data_error_columns=["DATA-ERR"]): # parse errors xs_err = [] + seen_labels = defaultdict(int) for label in data_error_columns: # parse error column err_parser = X4ColumnParser( @@ -122,12 +124,18 @@ def parse_energy_dependent_xs(data_set, data_error_columns=["DATA-ERR"]): raise ValueError(f"Subentry does not have a column called {label}") else: iyerr = [idx for idx, value in enumerate(data_set.labels) if value == label] - if len(iyerr) > 1: + # A label may legitimately repeat: some subentries carry two DATA-ERR + # columns, one in per-cent and one in absolute units, each mostly null, + # which together make up the uncertainty. Take them in order, one per + # occurrence of the label in data_error_columns, rather than refusing. + occurrence = seen_labels[label] + seen_labels[label] += 1 + if occurrence >= len(iyerr): raise ValueError( - f"Expected only one {label} column, found {len(iyerr)}" + f"Requested {occurrence + 1} {label} columns, found {len(iyerr)}" ) - err = err_parser.getColumn(iyerr[0], data_set) + err = err_parser.getColumn(iyerr[occurrence], data_set) err_units = err[1] err_data = np.nan_to_num(np.array(err[2:], dtype=np.float64)) # convert to same units as data @@ -167,6 +175,7 @@ def parse_differential_data( # parse errors xs_err = [] + seen_labels = defaultdict(int) for label in data_error_columns: # parse error column err_parser = X4ColumnParser( @@ -181,12 +190,18 @@ def parse_differential_data( raise ValueError(f"Subentry does not have a column called {label}") else: iyerr = [idx for idx, value in enumerate(data_set.labels) if value == label] - if len(iyerr) > 1: + # A label may legitimately repeat: some subentries carry two DATA-ERR + # columns, one in per-cent and one in absolute units, each mostly null, + # which together make up the uncertainty. Take them in order, one per + # occurrence of the label in data_error_columns, rather than refusing. + occurrence = seen_labels[label] + seen_labels[label] += 1 + if occurrence >= len(iyerr): raise ValueError( - f"Expected only one {label} column, found {len(iyerr)}" + f"Requested {occurrence + 1} {label} columns, found {len(iyerr)}" ) - err = err_parser.getColumn(iyerr[0], data_set) + err = err_parser.getColumn(iyerr[occurrence], data_set) if np.all([x is None for x in err]): continue diff --git a/src/exfor_tools/reaction.py b/src/exfor_tools/reaction.py index fc924a8..47a0e2c 100644 --- a/src/exfor_tools/reaction.py +++ b/src/exfor_tools/reaction.py @@ -191,6 +191,12 @@ def is_match(reaction: Reaction, subentry, vocal=False): subentry.reaction[0].residual.getA(), subentry.reaction[0].residual.getZ(), ) + # the residual of a natural target carries the same -3000 sentinel as the + # target, and must be normalized the same way, or no elastic scattering data + # set on a natural target will ever match + if residual[0] == -3000: + residual = (0, residual[1]) + if reaction.residual is None and reaction.process.upper() in [ "EL", "INL", From bef2777f5b8578bf47e79381e14d04d83f5b048e Mon Sep 17 00:00:00 2001 From: Kyle Beyer Date: Tue, 25 Aug 2026 23:05:28 -0400 Subject: [PATCH 2/8] Recognise the older EXFOR analyzing-power quantity codes quantity_matches accepted only "POL/DA,ANA" for Ay, so data tabulated as a bare "POL/DA" (the outgoing-particle polarization, equal to the analyzing power for elastic scattering by time-reversal invariance) or as "POL/DA,ASY" (the measured asymmetry) were never matched. Older entries use both forms; recognising them raises KDUQ proton analyzing power coverage from 51% to 79%. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01LSfNX9V6VEYiSsSmaJPyq5 --- src/exfor_tools/parsing.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/exfor_tools/parsing.py b/src/exfor_tools/parsing.py index 51f2efc..9177436 100644 --- a/src/exfor_tools/parsing.py +++ b/src/exfor_tools/parsing.py @@ -28,7 +28,12 @@ quantity_matches = { "dXS/dA": [["DA"], ["PAR", "DA"]], "dXS/dRuth": [["DA", "RTH"], ["DA", "RTH/REL"]], - "Ay": [["POL/DA", "ANA"]], + # EXFOR tabulates the analyzing power under several codes. "POL/DA,ANA" is the + # modern one; a bare "POL/DA" is the outgoing-particle polarization, which equals + # the analyzing power for elastic scattering by time-reversal invariance; and + # "POL/DA,ASY" is the measured asymmetry, which is the analyzing power once the + # beam polarization is divided out. Older entries use the latter two. + "Ay": [["POL/DA", "ANA"], ["POL/DA"], ["POL/DA", "ASY"]], "Q": [["POL/DA", "SRF"]], "XS": [ ["SIG"], From ef5826e0593aef7e98ff9211947d04686563480b Mon Sep 17 00:00:00 2001 From: Kyle Beyer Date: Tue, 25 Aug 2026 23:31:17 -0400 Subject: [PATCH 3/8] Match the qualified differential and integral cross section codes EXFOR qualifies the differential cross section in ways that do not change what the observable is: "AV" is averaged over an energy interval, "DERIV" is derived rather than tabulated directly, and "EXL" and "DI"/"MSC" appear on data whose reaction string is plain elastic scattering or scattering with an unresolved low-lying level - the "pseudo-elastic" case the KDUQ notes describe as having been analyzed as elastic. Likewise "SIG,AV" for the total cross section. None of these were matched, so the data sets carrying them were dropped. The reaction match still requires the right target, projectile and process. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01LSfNX9V6VEYiSsSmaJPyq5 --- src/exfor_tools/parsing.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/exfor_tools/parsing.py b/src/exfor_tools/parsing.py index 9177436..c61386a 100644 --- a/src/exfor_tools/parsing.py +++ b/src/exfor_tools/parsing.py @@ -26,7 +26,24 @@ # these are the supported quantities at the moment quantity_matches = { - "dXS/dA": [["DA"], ["PAR", "DA"]], + # EXFOR qualifies the differential cross section in several ways that do not change + # what the observable is. "AV" is averaged over an energy interval (the subentry + # carries EN-MEAN); "DERIV" is derived from a measured quantity rather than + # tabulated directly; "EXL" and "DI"/"MSC" appear on data whose reaction string is + # plain elastic scattering, or scattering with an unresolved low-lying level -- the + # "pseudo-elastic" case the KDUQ corpus notes describe as having been analyzed as + # elastic. All are matched; the reaction match still requires the right target, + # projectile and process. + "dXS/dA": [ + ["DA"], + ["PAR", "DA"], + ["DA", "AV"], + ["PAR", "DA", "AV"], + ["DA", "DERIV"], + ["EXL", "DA"], + ["DI", "DA"], + ["DI", "DA", "MSC"], + ], "dXS/dRuth": [["DA", "RTH"], ["DA", "RTH/REL"]], # EXFOR tabulates the analyzing power under several codes. "POL/DA,ANA" is the # modern one; a bare "POL/DA" is the outgoing-particle polarization, which equals @@ -37,6 +54,7 @@ "Q": [["POL/DA", "SRF"]], "XS": [ ["SIG"], + ["SIG", "AV"], ], } quantities = list(quantity_matches.keys()) From a8a32674d976fefe868f7fa15893358652cc00d0 Mon Sep 17 00:00:00 2001 From: Kyle Beyer Date: Tue, 25 Aug 2026 23:39:18 -0400 Subject: [PATCH 4/8] Treat EXFOR's scattering code as satisfying an elastic query EXFOR writes some level-resolved measurements as (n,SCT) with the level in an E-LVL column, rather than splitting them into (n,EL) and (n,INL). is_match rejected these outright, so the elastic channel of such a data set was unreachable. SCT now satisfies a query for EL, leaving the excitation-energy filter to select the ground state; callers wanting only elastic pass elastic_only=True, which forces Ex_range to (0, 0). Raises Test corpus neutron elastic coverage from 75% to 99.5%. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01LSfNX9V6VEYiSsSmaJPyq5 --- src/exfor_tools/reaction.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/exfor_tools/reaction.py b/src/exfor_tools/reaction.py index 47a0e2c..a037e75 100644 --- a/src/exfor_tools/reaction.py +++ b/src/exfor_tools/reaction.py @@ -177,7 +177,16 @@ def is_match(reaction: Reaction, subentry, vocal=False): if isinstance(product, str): if reaction.process is None: return False - if product != reaction.process.upper(): + # EXFOR writes some level-resolved measurements as (n,SCT) -- scattering, with + # the level given in an E-LVL column -- rather than splitting them into (n,EL) + # and (n,INL). The ground-state level of such a data set is elastic scattering, + # so SCT satisfies a query for EL; which level is kept is then decided by the + # excitation-energy filter, and callers wanting only the elastic channel should + # pass elastic_only=True. + equivalent = {"EL": {"EL", "SCT"}}.get( + reaction.process.upper(), {reaction.process.upper()} + ) + if product not in equivalent: return False else: product = (product.getA(), product.getZ()) From 1f3ab2fce96239d86038db30b7ee57f92d5f10b9 Mon Sep 17 00:00:00 2001 From: Kyle Beyer Date: Wed, 26 Aug 2026 01:02:34 -0400 Subject: [PATCH 5/8] Admit EXFOR's scattering code as elastic only when level-resolved The EXFOR dictionary defines SCT as "Total scattering (elastic + inelastic)". Summed, that is a different observable from elastic scattering and must not satisfy a query for it. The previous commit accepted SCT unconditionally, which happened to be safe against the current database - every such data set the corpora reach is resolved by an E-LVL or LVL-NUMB column - but would silently admit summed data if EXFOR added any. SCT now matches an elastic query only for level-resolved data, where the excitation-energy filter can select the ground state. Also corrects the quantity-modifier comment against the dictionary: DI is the direct-interaction part and MSC flags an approximate reaction code, rather than both denoting a "pseudo-elastic" sum. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01LSfNX9V6VEYiSsSmaJPyq5 --- src/exfor_tools/parsing.py | 16 ++++++++-------- src/exfor_tools/reaction.py | 37 ++++++++++++++++++++++++++----------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/exfor_tools/parsing.py b/src/exfor_tools/parsing.py index c61386a..4fdfb71 100644 --- a/src/exfor_tools/parsing.py +++ b/src/exfor_tools/parsing.py @@ -26,14 +26,14 @@ # these are the supported quantities at the moment quantity_matches = { - # EXFOR qualifies the differential cross section in several ways that do not change - # what the observable is. "AV" is averaged over an energy interval (the subentry - # carries EN-MEAN); "DERIV" is derived from a measured quantity rather than - # tabulated directly; "EXL" and "DI"/"MSC" appear on data whose reaction string is - # plain elastic scattering, or scattering with an unresolved low-lying level -- the - # "pseudo-elastic" case the KDUQ corpus notes describe as having been analyzed as - # elastic. All are matched; the reaction match still requires the right target, - # projectile and process. + # EXFOR qualifies the differential cross section in several ways that leave it a + # differential cross section. Per the EXFOR dictionary: "AV" is an average (the + # subentry carries EN-MEAN), "DERIV" is derived data, "DI" is the direct-interaction + # part, and "MSC" flags an approximate reaction code whose meaning is given in the + # entry text. "EXL" appears on data whose reaction string is plain elastic + # scattering. All are matched; the reaction match still requires the right target, + # projectile and process, and for level-resolved data the excitation-energy filter + # still selects the channel. "dXS/dA": [ ["DA"], ["PAR", "DA"], diff --git a/src/exfor_tools/reaction.py b/src/exfor_tools/reaction.py index a037e75..43054db 100644 --- a/src/exfor_tools/reaction.py +++ b/src/exfor_tools/reaction.py @@ -149,6 +149,18 @@ def query_for_reaction(reaction: Reaction, quantity: str): return entries +#: Columns by which a data set resolves the residual excitation. +LEVEL_COLUMN_FRAGMENTS = ("E-LVL", "E-EXC", "LVL-NUMB") + + +def is_level_resolved(subentry) -> bool: + """Whether a data set separates the residual's levels rather than summing them.""" + return any( + any(fragment in label for fragment in LEVEL_COLUMN_FRAGMENTS) + for label in subentry.labels + ) + + def is_match(reaction: Reaction, subentry, vocal=False): """Checks if the reaction matches a given subentry. @@ -177,17 +189,20 @@ def is_match(reaction: Reaction, subentry, vocal=False): if isinstance(product, str): if reaction.process is None: return False - # EXFOR writes some level-resolved measurements as (n,SCT) -- scattering, with - # the level given in an E-LVL column -- rather than splitting them into (n,EL) - # and (n,INL). The ground-state level of such a data set is elastic scattering, - # so SCT satisfies a query for EL; which level is kept is then decided by the - # excitation-energy filter, and callers wanting only the elastic channel should - # pass elastic_only=True. - equivalent = {"EL": {"EL", "SCT"}}.get( - reaction.process.upper(), {reaction.process.upper()} - ) - if product not in equivalent: - return False + process = reaction.process.upper() + if product != process: + # The EXFOR dictionary defines SCT as "Total scattering (elastic + + # inelastic)". Summed, that is not elastic scattering and must not satisfy a + # query for it. But some measurements are written as (n,SCT) resolved by + # level, in an E-LVL or LVL-NUMB column, rather than being split into + # (n,EL) and (n,INL); the ground-state level of those *is* elastic. Such a + # data set therefore matches, leaving the excitation-energy filter to pick + # the level -- so a caller wanting only the elastic channel must pass + # elastic_only=True, which forces Ex_range to (0, 0). + if not ( + process == "EL" and product == "SCT" and is_level_resolved(subentry) + ): + return False else: product = (product.getA(), product.getZ()) if product != reaction.product: From 33879195abaecf10fd604dcebaf10b2219a0dcac Mon Sep 17 00:00:00 2001 From: Kyle Andrew Beyer Date: Thu, 27 Aug 2026 14:41:38 -0400 Subject: [PATCH 6/8] Clone the x4i3_tools submodule over HTTPS The SSH URL requires a key on file, which breaks 'git clone --recurse-submodules' for anyone without push access and for CI runners. Claude-Session: https://claude.ai/code/session_01RhxcrnjrJXFSncVyYfkQkP --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index f6d55e3..285aa68 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "x4i3_tools"] path = x4i3_tools - url = git@github.com:afedynitch/x4i3_tools.git + url = https://github.com/afedynitch/x4i3_tools.git From 3e8ea5d67678beef8382c9d01ef4d46d0d18704c Mon Sep 17 00:00:00 2001 From: Kyle Andrew Beyer Date: Thu, 27 Aug 2026 22:52:09 -0400 Subject: [PATCH 7/8] Name the excitation predicate for what it actually tests is_level_resolved returned True for E-LVL-MAX, E-EXC-MAX and E-EXC-MX-A as well, since each contains E-LVL or E-EXC as a substring. Those columns bound the excitation rather than resolving it: the data set is summed over every level below the bound. Fourteen of the twenty-two (n,SCT) subentries the published corpora place in elastic sectors are of this kind, with bounds from 30 keV on 93Nb up to 800 keV, so admitting them is intended -- but it was accidental, and the name claimed the opposite. No behaviour changes. The predicate is renamed specifies_excitation, and both it and the SCT branch of is_match now say that a bound is not a resolution. Claude-Session: https://claude.ai/code/session_01RhxcrnjrJXFSncVyYfkQkP --- src/exfor_tools/reaction.py | 46 +++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/exfor_tools/reaction.py b/src/exfor_tools/reaction.py index 43054db..da46c20 100644 --- a/src/exfor_tools/reaction.py +++ b/src/exfor_tools/reaction.py @@ -149,14 +149,26 @@ def query_for_reaction(reaction: Reaction, quantity: str): return entries -#: Columns by which a data set resolves the residual excitation. -LEVEL_COLUMN_FRAGMENTS = ("E-LVL", "E-EXC", "LVL-NUMB") - - -def is_level_resolved(subentry) -> bool: - """Whether a data set separates the residual's levels rather than summing them.""" +#: Columns by which a data set states which residual excitation it covers. Some +#: resolve it to a single level -- E-LVL, E-EXC, LVL-NUMB -- and some only bound it, +#: EXFOR spelling the bound E-LVL-MAX, E-EXC-MAX or E-EXC-MX-A. All are matched here, +#: so the fragments below are deliberately prefixes. +EXCITATION_COLUMN_FRAGMENTS = ("E-LVL", "E-EXC", "LVL-NUMB") + + +def specifies_excitation(subentry) -> bool: + """Whether a data set states the residual excitation it covers. + + True both when the excitation is resolved to one level and when it is merely + bounded, in which case the data set is summed over every level below the bound -- + the ground state plus whatever low-lying levels the experiment could not separate. + The two are not the same thing, and this predicate deliberately does not + distinguish them: the published nucleon-nucleus corpora count both as elastic, + with bounds running from 30 keV on 93Nb up to 800 keV. A caller that needs the + ground state alone must check for a resolved column itself. + """ return any( - any(fragment in label for fragment in LEVEL_COLUMN_FRAGMENTS) + any(fragment in label for fragment in EXCITATION_COLUMN_FRAGMENTS) for label in subentry.labels ) @@ -192,15 +204,19 @@ def is_match(reaction: Reaction, subentry, vocal=False): process = reaction.process.upper() if product != process: # The EXFOR dictionary defines SCT as "Total scattering (elastic + - # inelastic)". Summed, that is not elastic scattering and must not satisfy a - # query for it. But some measurements are written as (n,SCT) resolved by - # level, in an E-LVL or LVL-NUMB column, rather than being split into - # (n,EL) and (n,INL); the ground-state level of those *is* elastic. Such a - # data set therefore matches, leaving the excitation-energy filter to pick - # the level -- so a caller wanting only the elastic channel must pass - # elastic_only=True, which forces Ex_range to (0, 0). + # inelastic)". Summed over everything, that is not elastic scattering and + # must not satisfy a query for it. But many measurements are written as + # (n,SCT) against an excitation column rather than being split into (n,EL) + # and (n,INL): either resolved to a level, whose ground state *is* elastic, + # or bounded above by a few tens to a few hundred keV, which is the ground + # state plus the low-lying levels the experiment could not separate. Both + # match, leaving the excitation-energy filter to select the channel where + # the data set resolves one -- so a caller wanting only the elastic channel + # must pass elastic_only=True, which forces Ex_range to (0, 0). A data set + # that only bounds its excitation has no column for that filter to act on + # and is admitted whole; see specifies_excitation. if not ( - process == "EL" and product == "SCT" and is_level_resolved(subentry) + process == "EL" and product == "SCT" and specifies_excitation(subentry) ): return False else: From 039e8463ed35384322655b0d1fe6b8a060ceed10 Mon Sep 17 00:00:00 2001 From: Kyle Andrew Beyer Date: Thu, 27 Aug 2026 22:57:08 -0400 Subject: [PATCH 8/8] Refresh the 2023 reference outputs the new matching changes Two effects, both intended. 239Pu 21782031 is (n,SCT) tabulated against E-LVL-MIN 0 to E-LVL-MAX 7.85 keV; it now satisfies an elastic query, as the range-bounded scattering data sets in the published corpora do, so the entry picks up sixteen angles from 20 degrees instead of ten from 70. And print_failed_parses now lists every failed subentry of an entry rather than only the last one recorded, so the O0253 failures appear in full. Verified with 'pytest --nbval-lax examples/examples_2023_release/': 102 passed. Claude-Session: https://claude.ai/code/session_01RhxcrnjrJXFSncVyYfkQkP --- .../ang_frame_conversion_and_json.ipynb | 6 +- .../dataset_curation_tutorial.ipynb | 66 +++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/examples/examples_2023_release/ang_frame_conversion_and_json.ipynb b/examples/examples_2023_release/ang_frame_conversion_and_json.ipynb index ea5d134..a13a45d 100644 --- a/examples/examples_2023_release/ang_frame_conversion_and_json.ipynb +++ b/examples/examples_2023_release/ang_frame_conversion_and_json.ipynb @@ -206,6 +206,8 @@ "name": "stdout", "output_type": "stream", "text": [ + "Found subentry 21782031 with the following columns:\n", + "['EN', 'EN-RSL-FW', 'E-LVL-MIN', 'E-LVL-MAX', 'ANG', 'DATA', 'ERR-T']\n", "Found subentry 21782032 with the following columns:\n", "['EN', 'EN-RSL-FW', 'ANG', 'DATA', 'ERR-T']\n" ] @@ -257,8 +259,8 @@ { "data": { "text/plain": [ - "array([ 70.23, 85.24, 90.24, 95.24, 105.2 , 115.2 , 125.2 , 135.2 ,\n", - " 145.1 , 155.1 ])" + "array([ 20.08, 30.12, 40.15, 50.18, 60.21, 70.23, 80.24, 85.24,\n", + " 90.24, 95.24, 105.2 , 115.2 , 125.2 , 135.2 , 145.1 , 155.1 ])" ] }, "execution_count": 7, diff --git a/examples/examples_2023_release/dataset_curation_tutorial.ipynb b/examples/examples_2023_release/dataset_curation_tutorial.ipynb index 1ca15b6..e4c8bed 100644 --- a/examples/examples_2023_release/dataset_curation_tutorial.ipynb +++ b/examples/examples_2023_release/dataset_curation_tutorial.ipynb @@ -785,6 +785,24 @@ " (DATA-ERR).Data-Point Reader Uncertainty.\n", " (ANG-ERR).Data-Point Reader Uncertainty.\n", "Entry: O0253\n", + "O0253017 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253018 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253019 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253020 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253021 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253022 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253023 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253024 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253025 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", "O0253026 : Ambiguous statistical error labels:\n", "ERR-1, ERR-2, DATA-ERR\n", "ERR-ANALYS (ERR-1) Uncertainty of Corrections on Carbon and Oxygen\n", @@ -802,6 +820,15 @@ " Absolute Uncertainties are Approximately 5%.\n", " (ANG-ERR).Data-Point Reader Uncertainty.\n", "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", "Entry: O0302\n", "O0302004 : Ambiguous statistical error labels:\n", "DATA-ERR1, DATA-ERR2, ERR-DIG\n", @@ -993,6 +1020,32 @@ " DETERMINATIONOF THE SUPERFICIAL OF TARGET.\n", "\n", "Entry: O0253\n", + "O0253003 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253004 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253005 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253006 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253007 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253008 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253009 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253010 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253011 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253012 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253013 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253014 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", + "O0253015 : Ambiguous statistical error labels:\n", + "ERR-1, ERR-2, DATA-ERR\n", "O0253016 : Ambiguous statistical error labels:\n", "ERR-1, ERR-2, DATA-ERR\n", "ERR-ANALYS (ERR-1) Uncertainty of Corrections on Carbon and Oxygen\n", @@ -1010,6 +1063,19 @@ " Absolute Uncertainties are Approximately 5%.\n", " (ANG-ERR).Data-Point Reader Uncertainty.\n", "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", + "ERR-ANALYS (DATA-ERR).Data-Point Reader Uncertainty.\n", "Entry: O0382\n", "O0382002 : Ambiguous statistical error labels:\n", "DATA-ERR, ERR-T\n",