Skip to content

Conversation

@sscini
Copy link
Contributor

@sscini sscini commented Nov 20, 2025

Fixes # .

Summary/Motivation:

_Q_opt, the main model building and solving function within parmest, is still heavily dependent on MSISPPY, and the code is becoming outdated and difficult to interpret. The goal of this PR is to redesign _Q_opt to work without this dependence, retaining all the current functionality

Changes proposed in this PR:

-_Q_opt redesign, using a block structure, with minimal changes needed to functions that utilize it.

Legal Acknowledgement

By contributing to this software project, I have read the contribution guide and agree to the following terms and conditions for my contribution:

  1. I agree my contributions are submitted under the BSD license.
  2. I represent I am authorized to make the contributions and grant the license. If my employer has rights to intellectual property that includes these contributions, I represent that I have received permission to make contributions and grant the required license on behalf of that employer.

@sscini
Copy link
Contributor Author

sscini commented Nov 20, 2025

@djlaky @adowling2 Here are my initial thoughts on the redesign. Please provide feedback on code layout to this point.

@sscini
Copy link
Contributor Author

sscini commented Nov 20, 2025

Dan and I had a good conversation today about the functional things needed in the redesign, and how to go about adding components to the overall block and sub-models. Working to implement changes, closely related to what is done currently in doe's _generate_scenario_blocks.

Copy link
Member

@adowling2 adowling2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice progress

@sscini
Copy link
Contributor Author

sscini commented Nov 25, 2025

@adowling2 @djlaky Added case for bootstrap, now works with theta_est, theta_est_bootstrap, and theta_est_leaveNout if I replace _Q_opt with _Q_opt_blocks. Please review.

I am aware of the duplicated code, but when I attempted to unify them using n_scenarios = len(self.exp_list) or len(bootlist), I am getting an error for bootstrap I am still working out.

Would we want to fully transition to using theta_est for obj and theta, and cov_est for covariance and add an error/warning? Or should I make it work to calculate cov if calc_cov=True?

Thanks!

@codecov
Copy link

codecov bot commented Nov 30, 2025

Codecov Report

❌ Patch coverage is 4.76190% with 100 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.31%. Comparing base (13facca) to head (d91ce3f).
⚠️ Report is 21 commits behind head on main.

Files with missing lines Patch % Lines
pyomo/contrib/parmest/parmest.py 4.76% 100 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3789      +/-   ##
==========================================
- Coverage   89.40%   89.31%   -0.10%     
==========================================
  Files         909      909              
  Lines      105541   105646     +105     
==========================================
- Hits        94364    94360       -4     
- Misses      11177    11286     +109     
Flag Coverage Δ
builders 29.07% <4.76%> (-0.04%) ⬇️
default 85.94% <4.76%> (?)
expensive 35.73% <4.76%> (?)
linux 86.63% <4.76%> (-2.55%) ⬇️
linux_other 86.63% <4.76%> (-0.10%) ⬇️
osx 82.78% <4.76%> (-0.09%) ⬇️
win 84.88% <4.76%> (-0.09%) ⬇️
win_other 84.88% <4.76%> (-0.09%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@sscini
Copy link
Contributor Author

sscini commented Dec 9, 2025

@adowling2 @djlaky Should I tag larger team on this? Please review when available. Thanks!

@sscini
Copy link
Contributor Author

sscini commented Jan 27, 2026

@adowling2 @slilonfe5 @blnicho Ready for design review.

Still adjusting tests to fix final remaining issues. Current tests had Params for experimental outputs, which I am switching to Vars and adding a Constraint instead of Expression.

Planning to restructure reaction kinetics example in a separate PR.

@sscini sscini moved this from Development to Ready for design review in ParmEst & Pyomo.DoE Development Jan 27, 2026
@sscini sscini requested review from adowling2 and slilonfe5 January 27, 2026 19:47
@sscini
Copy link
Contributor Author

sscini commented Feb 5, 2026

@adowling2 @blnicho All checks passing as of last run. Please review when available. If possible to make it for this release it would be greatly appreciated, but there are many design changes. Thank you!

@sscini
Copy link
Contributor Author

sscini commented Feb 6, 2026

For reviewers: All feedback appreciated, some key areas:

  • Potentially missing or needed tests for modified _Q_opt implement
  • I left in "initialize_parmest_model" option in objective_at_theta, but it currently does nothing. Does it still need to be tested until fully removed?
  • Measurement error is required for using cov_est, or parmest with calc_cov = True. This is a new constraint on the user. Can this requirement be added, and if not provided, use deprecatedEstimator? Or what is best approach? Other idea is adding helper functions to Experiment class, but not sure if needed in this PR.
  • Recommended way to clean up imports at top of parmest.py

Copy link
Member

@adowling2 adowling2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see the comments below. There are a few places where I think we want to double check the math. @slilonfe5 and @smondal13, can you also please take a look.

@@ -55,21 +55,21 @@ def simple_reaction_model(data):
model.k.fix()

# ===================================================================
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can all of this commented-out code just get deleted?

) # min^-1
model.k3 = pyo.Param(
initialize=1.0 / 6000.0, within=pyo.PositiveReals, mutable=True
# Rate constants, make unknown parameters variables
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This question still stands.

from pyomo.contrib.parmest.experiment import Experiment


def reactor_design_model():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this inherit from the Experiment class?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example working normally. Intention was to update the examples in a separate PR. Following recommendation, I will complete now in this PR.

columns=["hour", "y"],
)

# Updated models to use Vars for experiment output, and Constraints
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this fit in with @smondal13 's effort to consolidate all of the copies of the RB examples?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(@smondal13 please confirm) The rooney_biegler example consolidation was primarily to remove copies of the model used normally. The purpose of this test is to change the model definition (unknown parameters are provided in six different ways) to make sure these options are supported, primarily in objective_at_theta.

Please let me know if you recommend the removal or simplification of this test.

# Check cov_n argument is set correctly
# Needs to be provided
assert cov_n is not NOTSET, (
"The number of data points 'cov_n' must be provided to calculate "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this something we can infer from the provided data?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we do infer it from the provided data (see _count_total_experiments()), but from the previous implementation it was required for the user to provide both calc_cov = True, and a value for cov_n. The value provided for cov_n is not currently being used, other than to check length in comparison to number of parameters.

Goal was to not modify current user experience. Is the recommendation to remove the requirement?

@@ -1186,11 +1314,18 @@ def _cov_at_theta(self, method, solver, step):
if method == CovarianceMethod.reduced_hessian.value:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this method implicitly assume? I think it assumes the user has specified the objective as the log-likelihood function plus a constant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All methods within _cov_at_theta only support the provided weighted SSE and SSE objectives. A user specified method is currently not supported, and causes an error.

)

self.inv_red_hes = inv_red_hes
else:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are the other covariance methods that correspond with this else?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(@slilonfe5 confirm please) inv_red_hessian uses the ef_nonants, or the unknown parameter variables from the extended form model, and needs to be run after parameter estimation. _k_aug and finite difference use the model directly from the Experiment class.

'automatic_differentiation_k_aug' and 'finite_difference' are after the else.

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

Labels

Projects

Status: Ready for design review

Development

Successfully merging this pull request may close these issues.

6 participants