Skip to content

High: [ParamEstim/Calibration] IPOPT result assembly crashes and PCR predict recenters on new data #78

Description

@sergey-gusev94

Maintainer triage (June 29, 2026)

  • Status: Verified bug against the current master source in this fork.
  • Severity: High.
  • Area labels: area:param-estimation, area:calibration.
  • Tackle batch: P3 - documented-mode crashes and tooling breakages.

The source review confirmed that the cited code path and failure mode are still present. The original audit details are preserved below for reproduction notes and suggested fixes.


Original audit details

Severity: High · Category: API misuse (crash) + logic · Part of #67

Two defects in the model-fitting tooling. Grouped as the "fit/predict produces no usable result" cluster (parameter estimation + calibration); the two fixes are small and live in adjacent fitting modules.


1. (High) ParameterEstimation IPOPT branch crashes: get_objective called with non-existent update_self keyword

Location: PharmaPy/ParamEstim.py:641-642

After IPOPT converges, resid_multidim = self.get_objective(opt_par, out_array=True, update_self=False). The base signature is get_objective(self, params, out_array=False, set_self=True) (460) — there is no update_self parameter (only the MultipleCurveResolution subclass override at 1297 has it). For a plain ParameterEstimation, this raises TypeError immediately after the solve.

  • Trigger: paramest.optimize_fn(method='IPOPT') (with cyipopt installed) — the documented alternative solver.
  • Wrong result: TypeError: get_objective() got an unexpected keyword argument 'update_self'; the converged parameters, covariance, and confidence intervals are lost even though optimization succeeded.
  • Fix: use the base keyword — self.get_objective(opt_par, out_array=True, set_self=False).

2. (High) PCR_calibration.predict re-centers new inputs with their own mean/std instead of training statistics

Location: PharmaPy/Calibration.py:190-220

predict() centers via self.__center_data(inputs) in both branches (194-197) without passing mean/std, so __center_data recomputes mean/std from the new prediction inputs (49-57). The model was fit with the training stats (self.data_mean/self.data_std), so projection onto the stored PCs (self.svd_dict['V'], 207) and the regression np.dot(new_projections, coeff) + self.y_means (220) are inconsistent. standardize defaults True, so 1/std executes.

  • Trigger: fit a PCR_calibration, then predict(new_spectra) on new measurements — the model's primary use.
  • Wrong result: for a single new sample, std=0 over that row → divide-by-zero → NaN/inf predictions; for multi-row batches, scores and predicted y are systematically offset/scaled wrong. The in-fit self-prediction predict(self.data) happens to match, masking the bug.
  • Fix: pass the training stats — self.__center_data(inputs, self.data_mean, self.data_std) in the non-snv branch.

Related (not duplicates): No existing issue references Calibration.py/PCR_calibration or the ParamEstim IPOPT signature.

Metadata

Metadata

Assignees

Labels

area:calibrationCalibration and statistical model predictionarea:param-estimationParameter estimation, gradients, and optimization plumbingbugSomething isn't workingcorrectnessModel/numerical correctness defectseverity:highConfirmed bug with major correctness impact or broken documented workflowstatus:verifiedSource-reviewed against the current codebase

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions