Skip to content

LEAPR discre: idone flag reuse drops all but the first in-range discrete-oscillator delta line (twt = 0) #402

Open

Description

@ramic-k

In src/leapr.f90, the delta-function block of discre (the twt <= 0
branch, lines ~1549–1585 in NJOY2016.78) reuses the idone flag for two
different loops — the outer loop over discrete lines and the inner
nearest-beta grid search:

      !--add the delta functions to the scattering law
      !--delta(0.) is saved for the incoherent elastic
      if (twt.le.zero) then
         m=0
         idone=0
         do while (m.lt.n.and.idone.eq.0)      ! outer: lines
            m=m+1
            ...
               if (bes(m).lt.zero) then
                  be=-bes(m)
                  if (be.le.betan(nbeta-1)) then
                     db=1000
                     idone=0
                     j=0
                     do while (j.lt.nbeta.and.idone.eq.0)   ! inner: grid search
                        j=j+1
                        jj=j
                        if (abs(be-betan(j)).gt.db) then
                           idone=1                          ! <-- also exits the OUTER loop
                        else
                           db=abs(be-betan(j))
                        endif
                     enddo
                     ...
                     if (add.ge.tiny) sexpb(jj-1)=sexpb(jj-1)+add
                  endif
               endif
         enddo
      endif

When the inner search finds the nearest grid point it sets idone = 1,
which also terminates the outer do while (m.lt.n.and.idone.eq.0)
loop. The net behavior: only the first in-range negative delta line is
added to the scattering law, and every subsequent line is silently skipped.
Because the lines were weight-sorted just above (the "sort the discrete
lines" block), "first" means the largest-weight in-range line — the rest of
the oscillator delta weight never reaches S(α,β).

Trigger: any deck with twt = 0 and discrete oscillators whose line
spectrum has two or more in-range downscatter lines — e.g. an
Einstein-solid-style hydride evaluated without a translational component.
Decks with twt > 0 never enter this branch (the lines are convolved
through the translational path instead), which is presumably why the
standard evaluation suite never exposed it.

Reproduction sketch: a minimal one-temperature deck with a small
continuous spectrum (tbeta = 0.5), twt = 0, and two oscillators
(nd = 2, e.g. 0.137 eV and 0.250 eV with weights 0.3/0.2) on a beta grid
reaching past both lines. The resulting S(α,β) carries a delta spike only
at the first oscillator's beta; the second line (and the
oscillator-combination lines) are absent. Note the iprint >= 2
"norm check" printout still reports the full line-weight sum, because it is
computed before this block — so the lost weight is not visible in the
diagnostic output.

Suggested fix: use a separate flag for the inner grid search, e.g.

                     jdone=0
                     j=0
                     do while (j.lt.nbeta.and.jdone.eq.0)
                        ...
                           jdone=1
                        ...
                     enddo

so the outer loop runs over all n lines. (The early exit on
dwf.lt.vsmall is unaffected and can stay on the outer flag.)

We found this by cross-checking against an independent reimplementation
that convolves every in-range line: on the two-oscillator deck above it
produces distinct delta spikes at both oscillator betas, while NJOY2016.78
produces only the first.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions