Skip to content

ACE reader fails on denormal floats under numpy 2, existing missing-E recovery never runs #20

Description

@shimwell

Summary

_read_ascii in src/endf/ace.py cannot read any ACE file containing a denormal value, because the existing recovery for NJOY's missing-E floats never runs under numpy 2.

The code already knows about this class of malformed float. The guard at ace.py:414 handles it:

xss = np.fromstring(datastr, sep=' ')          # line 406

# When NJOY writes an ACE file, any values less than 1e-100 actually
# get written without the 'e'. ...
if xss.size != nxs[1] + 1:                      # line 414
    datastr = ENDF_FLOAT_RE.sub(r'\1e\2\3', datastr)
    xss = np.fromstring(datastr, sep=' ')

That check keys off a short array, which is what numpy 1 produced: np.fromstring(..., sep=' ') stopped at the first token it could not parse and returned what it had. numpy 2 raises instead, so line 406 throws and line 414 is never reached.

File "endf/ace.py", line 406, in _read_ascii
    xss = np.fromstring(datastr, sep=' ')
ValueError: string or file could not be read to its end due to unmatched data

Reproduction

Any TENDL-2025 evaluation whose ACE output contains a denormal. Five do:

import endf
endf.IncidentNeutron.from_njoy("n-Db262.tendl", njoy_exec="njoy")

Also fails for n-Db263, n-Db264, n-Sg272 and n-Sg273. NJOY 2016.79, numpy 2.5.1, Python 3.13.

The source ENDF is fine, endf.Material() reads all five without complaint. The malformed floats are in the ACE file ACER writes. In Db262 exactly 2 of the 772031 XSS tokens are affected:

idx 350955: '6.10562372605-318'
idx 350983: '5.34601261754-318'

Denormals near 1e-318, where the three-digit negative exponent overflows the Fortran field width and the E is dropped. ENDF_FLOAT_RE already handles these correctly once it gets the chance:

>>> ENDF_FLOAT_RE.sub(r'\1e\2\3', '6.10562372605-318')
'6.10562372605e-318'

Fix

Give the existing recovery the short array it expects rather than letting the read fail:

try:
    xss = np.fromstring(datastr, sep=' ')
except ValueError:
    xss = np.empty(0)

With that, all five convert (Db262 gives 60 reactions, Sg272 gives 62).

Related

ace.py:156, in ascii_to_binary, has the same bare np.fromstring(..., sep=' ') and no size check to fall back on, so it will fail the same way on these files. Not on the from_njoy path, so it did not surface here.

Worth sending upstream too: nothing about this is specific to this fork or to TENDL, it affects any ACE file with a denormal on numpy 2.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions