Summary
TrendFit.make_1dfits() is meant to remove failed 1D fits from self.ffuncs
(moving them to self.bad_fits), so that every fit object remaining in
self.ffuncs afterward has had make_fit() succeed on it. In practice, some
fit objects survive in self.ffuncs without a successful fit ever having
completed on them — they lack _popt/_TeX_info — which crashes any code
that assumes make_1dfits()'s filtering is exhaustive.
Environment
- solarwindpy
0.3.1.dev22+gb4fff2e2 (commit b4fff2e, master, 2026-07-23)
- pandas 2.2.2, Python 3.12.2, macOS
Observed behavior (verified)
Running a per-heliocentric-distance-bin trend-fit loop (fitting a Gaussian
per solar-wind-speed bin, then a HingeSaturation trend across those bins)
against real New Horizons/SWAP PUI data:
tf.make_ffunc1ds(**fit_1d_kwargs)
tf.make_1dfits(return_exception=True)
for kk, v in tf.ffuncs.items():
v.TeX_info.set_TeX_argnames(mu=r"\mu", sigma=r"\sigma") # <-- AttributeError here
...
raises:
AttributeError: 'Gaussian' object has no attribute '_TeX_info'
Adding a defensive check confirmed the same objects also lack _popt:
AttributeError: 'Gaussian' object has no attribute '_popt'
Inserting a diagnostic filter directly after make_1dfits():
_unfit = [k for k, v in tf.ffuncs.items() if not hasattr(v, '_popt')]
if _unfit:
print(f"Dropping {len(_unfit)} fits that never populated _popt: {_unfit}")
tf.ffuncs.drop(_unfit, inplace=True)
confirmed, per r-bin, that 2-4 Gaussian objects out of ~20 vsw-bin fits were
left in tf.ffuncs in this broken state, and dropping them let the rest of
the pipeline (trend fit, plotting) complete normally. This is a reliable,
reproducible workaround, applied locally (not upstreamed here) at
https://github.com/blalterman/nh/commit/c4a6fc1.
What I verified vs. what I believe
- Verified:
TrendFit.make_1dfits's own filtering logic (fit_success.dropna()
isolating None-returning fits from exception-returning fits in an
object-dtype pandas Series) behaves correctly in isolation — a small
standalone pd.Series([None, ValueError('x'), None]) test drops exactly
the exception entry.
- Verified: with real data, some fits that are not caught by that
filtering nonetheless never call build_TeX_info()/set _popt (i.e.
make_fit() did not complete its success path for them), yet they are not
present in tf.bad_fits either.
- I believe (not confirmed) this points to a fit failure mode that isn't
routed through either of make_fit()'s two guarded try/except blocks
(around _run_least_squares and around the initial sufficient_data
check) — e.g. an exception raised during
_calc_popt_pcov_psigma_chisq(res, p0), which sits outside both guarded
blocks. I was not able to isolate a minimal synthetic reproduction in the
time available (a synthetic sparse-bin TrendFit with 2/40-point columns
did not reproduce the issue), so this is an unconfirmed theory, not a
diagnosed root cause.
Suggested next step
Instrument make_fit()'s success path (or TrendFit.make_1dfits) to catch
and record any exception (not just the two currently-guarded exception
tuples) into bad_fits, so self.ffuncs is guaranteed self-consistent
(every remaining entry has _popt/_TeX_info) regardless of which stage of
fitting failed.
Reproduction path
I don't yet have a minimal standalone repro, but the failure is fully
reproducible against real PUI data via ahe_vsw.ipynb's per-r-bin trend fit
cell in https://github.com/blalterman/nh (commit prior to
c4a6fc1 reproduces it; that commit adds the local workaround). Happy to share
the specific data file/bin if useful for reproduction.
Summary
TrendFit.make_1dfits()is meant to remove failed 1D fits fromself.ffuncs(moving them to
self.bad_fits), so that every fit object remaining inself.ffuncsafterward has hadmake_fit()succeed on it. In practice, somefit objects survive in
self.ffuncswithout a successful fit ever havingcompleted on them — they lack
_popt/_TeX_info— which crashes any codethat assumes
make_1dfits()'s filtering is exhaustive.Environment
0.3.1.dev22+gb4fff2e2(commitb4fff2e,master, 2026-07-23)Observed behavior (verified)
Running a per-heliocentric-distance-bin trend-fit loop (fitting a
Gaussianper solar-wind-speed bin, then a
HingeSaturationtrend across those bins)against real New Horizons/SWAP PUI data:
raises:
Adding a defensive check confirmed the same objects also lack
_popt:Inserting a diagnostic filter directly after
make_1dfits():confirmed, per r-bin, that 2-4
Gaussianobjects out of ~20 vsw-bin fits wereleft in
tf.ffuncsin this broken state, and dropping them let the rest ofthe pipeline (trend fit, plotting) complete normally. This is a reliable,
reproducible workaround, applied locally (not upstreamed here) at
https://github.com/blalterman/nh/commit/c4a6fc1.
What I verified vs. what I believe
TrendFit.make_1dfits's own filtering logic (fit_success.dropna()isolating
None-returning fits from exception-returning fits in anobject-dtype pandas Series) behaves correctly in isolation — a small
standalone
pd.Series([None, ValueError('x'), None])test drops exactlythe exception entry.
filtering nonetheless never call
build_TeX_info()/set_popt(i.e.make_fit()did not complete its success path for them), yet they are notpresent in
tf.bad_fitseither.routed through either of
make_fit()'s two guardedtry/exceptblocks(around
_run_least_squaresand around the initialsufficient_datacheck) — e.g. an exception raised during
_calc_popt_pcov_psigma_chisq(res, p0), which sits outside both guardedblocks. I was not able to isolate a minimal synthetic reproduction in the
time available (a synthetic sparse-bin
TrendFitwith 2/40-point columnsdid not reproduce the issue), so this is an unconfirmed theory, not a
diagnosed root cause.
Suggested next step
Instrument
make_fit()'s success path (orTrendFit.make_1dfits) to catchand record any exception (not just the two currently-guarded exception
tuples) into
bad_fits, soself.ffuncsis guaranteed self-consistent(every remaining entry has
_popt/_TeX_info) regardless of which stage offitting failed.
Reproduction path
I don't yet have a minimal standalone repro, but the failure is fully
reproducible against real PUI data via
ahe_vsw.ipynb's per-r-bin trend fitcell in https://github.com/blalterman/nh (commit prior to
c4a6fc1 reproduces it; that commit adds the local workaround). Happy to share
the specific data file/bin if useful for reproduction.