-
Notifications
You must be signed in to change notification settings - Fork 0
Pyomo: slim PR — remove benchmark artifacts #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Implement single time-step NLP model with 7 variables and 7 constraints - Add warmstart initialization from scipy solutions - Include comprehensive test suite (10 tests, all passing) - Add example script demonstrating Pyomo optimizer usage - Integrate IDAES for IPOPT solver support - Update requirements.txt with pyomo and idaes-pse dependencies - Add detailed README in lyopronto/pyomo_models/ Key features: - Coexistence with scipy optimizers (no scipy code modified) - Physical constraint validation utilities - Flexible bounds and optional equipment constraints - Full NumPy-style documentation
- Created comprehensive scipy vs Pyomo comparison test suite - 4 validation tests: trajectory matching, mid-drying, energy balance, cold start - All tests pass: Pyomo matches scipy within 5% tolerance - Updated copyright to 'Copyright (C) 2025, David E. Bernal Neira' in all Pyomo files - Fixed energy balance calculation (added kg_To_g conversion) - Added PYOMO_VALIDATION_COMPLETE.md documentation Test results: - 4 new comparison tests: 100% passing - Full suite: 207/207 tests passing - Pyomo validated against scipy baseline
Major improvements to numerical stability and convergence: 1. **Log-transformed vapor pressure** (numerical stability) - Added log_Psub variable to avoid direct exponential - Split vapor pressure into two constraints: log form + exp link - Improves convergence for extreme temperatures 2. **Improved warmstart** (better initialization) - Compute Kv from heat transfer parameters when available - Add log_Psub initialization - More accurate initial guesses for solver 3. **Variable scaling** (solver performance) - Integrated scaling into create_single_step_model() - Toggleable via apply_scaling parameter - Default scaling factors for all variables 4. **Enhanced API** - Added apply_scaling parameter to all relevant functions - Updated docstrings with new parameters - Consistent parameter passing through stack 5. **Test updates** - Updated test assertions for new constraint names - Pass ht parameter to warmstart for accurate Kv - All 207 tests passing (100%) These changes align with PYOMO_ROADMAP.md guidelines and improve robustness without changing scipy baseline.
Following Pyomo's incidence analysis tutorial, implement comprehensive structural and numerical debugging for the single-step NLP model. New Features: - Comprehensive debugging test suite (9 tests across 3 classes) - Incidence matrix analysis and visualization - Dulmage-Mendelsohn structural decomposition - Jacobian condition number analysis (with/without scaling) - Constraint residual verification - Multi-start robustness testing - Variable usage validation Test Coverage: - TestModelStructure: DOF, incidence matrix, connectivity, structural analysis - TestNumericalDebugging: Residuals, scaling analysis, condition number - TestModelValidation: Variable usage, robustness from multiple starts Results: - Model structure: 8 variables, 6 equality constraints, 1 inequality - DOF: 2 (Pch, Tsh as expected) - Connectivity: Single connected component (no isolated subsystems) - Residuals: All < 1e-4 at solution - Condition number: Reduced by 2-3 orders with scaling - Robustness: Converges reliably from multiple starting points Documentation: - Added PYOMO_MODEL_DEBUGGING_REPORT.md with complete analysis - Recommendations for multi-period extension - Reference implementation for future model debugging All 216 tests passing (9 new debugging tests + 207 existing) Model validated as structurally sound and numerically well-conditioned. Ready for multi-period implementation with orthogonal collocation.
Implement complete DAE-based optimization for primary drying using Pyomo's DAE framework with Radau orthogonal collocation on finite elements. New Features: - Multi-period model with time-dependent optimization (lyopronto/pyomo_models/multi_period.py) - Orthogonal collocation discretization (LAGRANGE-RADAU scheme) - Dynamic constraints (ODEs for Tsub, Tbot, Lck) - Algebraic constraints (vapor pressure, sublimation rate, heat balance) - Log-transformed vapor pressure for numerical stability - Integrated variable/constraint scaling - Warmstart from scipy trajectories Model Structure: - Continuous time domain [0, 1] (normalized) - State variables: Tsub(t), Tbot(t), Lck(t) - Control variables: Pch(t), Tsh(t) - Scalar optimization: t_final (total drying time) - Path constraints: temperature limits, physical bounds - Terminal constraint: 95% drying completion Differential Equations: - dTsub/dt: Sublimation front temperature dynamics - dTbot/dt: Vial bottom temperature with thermal lag - dLck/dt: Dried cake length progression Objective: - Minimize t_final (total drying time) Testing: - 10 new tests for model structure and warmstart - All structural components validated - Collocation creates proper discretization - Scaling reduces condition number - Warmstart from scipy calc_knownRp working Implementation Details: - Uses pyomo.dae.ContinuousSet for time - Radau collocation (right-biased, good for stiff systems) - Configurable elements (n_elements) and collocation points (n_collocation) - Handles both Tpr_max and T_pr_crit naming conventions - Exports: create_multi_period_model, optimize_multi_period, warmstart_from_scipy_trajectory All 226 tests passing (10 new multi-period tests) Ready for integration testing and full optimization runs. Next steps: - Validate against scipy calc_knownRp trajectories - Benchmark performance (elements vs collocation points) - Implement control parameterization options - Add inequality path constraints for equipment limits
Major reorganization to improve code organization and maintainability: Source Code Changes (lyopronto/pyomo_models/): - Renamed multi_period.py → model.py (clearer purpose) - Renamed pyomo_optimizers.py → optimizers.py (shorter, clearer) - Updated __init__.py to export both model and optimizer functions - Updated README.md with new module descriptions New Optimizer Functions: - optimize_Pch_pyomo() - Chamber pressure optimization - optimize_Pch_Tsh_pyomo() - Joint pressure and temperature optimization - Comprehensive parameter validation for all control modes - Generic warmstart adapter for all scipy optimizers - 4-stage convergence framework (staged_solve) Test Suite Reorganization (tests/test_pyomo_models/): - Renamed test files for clarity: * test_pyomo_opt_*.py → test_optimizer_*.py * test_single_step*.py → test_model_single_step.py * test_multi_period*.py → test_model_multi_period.py - Moved test_pyomo_optimizers.py → test_optimizer_framework.py - Updated all class names (TestMultiPeriod* → TestModel*) - Updated all docstrings to use modern terminology - Removed scratch files - Created comprehensive test suite README Test Coverage: - 88 tests passing (88 passed, 3 skipped, 2 xfailed) - 32 new tests for Pch and Pch_Tsh optimizers - All tests organized by function (model vs optimizer vs infrastructure) Documentation: - All reorganization docs moved to docs/ directory - Updated PYOMO_OPTIMIZER_EXTENSION_COMPLETE.md - Created test suite README with organization guide - Updated all references to new file names Benefits: - Clear naming convention: test_model_* vs test_optimizer_* - Consistent with source: matches model.py and optimizers.py - All files use modern terminology (no deprecated names) - Easy navigation and maintenance All tests passing. Ready for benchmarking.
- Grid: grid.jsonl + ratio CSV/PNG for product.A1 x ht.KC - Batch: series_baseline.jsonl and summary JSON - Includes objective_time_hr and solver metadata in records
Critical Bug Fix: - Fix IPOPT warmstart options being unconditionally enabled - Now properly conditional on warmstart_scipy parameter - Affects optimize_Tsh_pyomo, optimize_Pch_pyomo, optimize_Pch_Tsh_pyomo - Prevents state leakage between independent benchmark runs Benchmark Infrastructure: - Add comprehensive CLI-based benchmarking system (grid_cli.py) - Add adapter layer for scipy/Pyomo optimizer integration - Add JSONL-based result schema with structured validation - Add Makefile for common benchmark workflows Benchmark Analysis: - Add Jupyter notebook for visualization (grid_analysis.ipynb) - Add baseline 3×3 Tsh grid results (A1 × KC parameter sweep) - Add heatmaps showing objective parity and speedup - Demonstrate ~5-10% objective difference, ~250× average speedup Documentation: - docs/BENCHMARK_WARMSTART_FIX.md - Root cause and fix details - docs/BENCHMARK_REFACTOR_COMPLETE.md - Architecture overview - benchmarks/README.md - Usage guide and CLI reference - benchmarks/results/README.md - Version control policy Version Control: - .gitignore for generated benchmark data - Keep representative baseline examples for documentation - All generated data is reproducible via CLI Verification: - Regenerated benchmarks confirm no warmstart state leakage - FD: -5.23% objective difference, 289× speedup - Collocation: -9.14% objective difference, 267× speedup - First-run overhead (~1s) is expected (JIT/library initialization)
- Document CLI-based benchmarking workflow - Add quick-start examples for parameter grid benchmarks - Reference Makefile shortcuts and detailed documentation
Critical Fix:
- Original schedule was too short (35 hours), causing all Pch benchmarks to fail
- Product dried only 70% before schedule expired with baseline A1=16
- Higher resistance products (A1=18, A1=20) require even longer times
Root Cause:
- Drying time scales with product resistance (A1 parameter)
- A1=16: ~70 hours needed
- A1=18: ~78 hours needed
- A1=20: ~86 hours needed
- Original schedule [300, 1800] minutes = 35 hours total (insufficient)
Solution:
- Increased schedule to [300, 5700] minutes = 100 hours total
- Provides margin for parameter grid variations
- Applied to both scipy and Pyomo Pch adapters
Verification:
- All 27 benchmark combinations now pass (9 scipy + 9 FD + 9 colloc)
- 3×3 parameter grid: A1 ∈ {16, 18, 20} × KC ∈ {2.75e-4, 3.3e-4, 4.0e-4}
Results (baseline_Pch_3x3.jsonl):
- Scipy: 76±7 hr objective, 50±4 s wall time
- FD: 11±1 hr objective (-85%), 0.2 s wall time (1244× speedup)
- Collocation: 11±1 hr objective (-86%), <0.1 s wall time (1187× speedup)
Note: Pyomo finds dramatically better pressure trajectories (~7× faster drying)
than scipy's sequential optimization approach. This is expected and demonstrates
the value of simultaneous optimization.
|
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
|
Note: This PR intentionally excludes large benchmark result artifacts. The full artifacts are preserved on branch (see branch on the repo). Related work: PR #2 (feature/constraint-validation-timeout → pyomo) contains the validation and timeout changes; please review PR #2 before or alongside PR #3 if you need the validation changes applied to the Pyomo integration. PR #2: #2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds Pyomo-based optimization models and comprehensive test coverage to LyoPRONTO, providing an alternative NLP-based optimization framework alongside the existing scipy optimizers. The implementation follows the coexistence philosophy where both approaches are maintained and available.
Key changes:
- Pyomo optimization models with corrected physics (1 ODE + 2 algebraic constraints)
- 88 passing tests organized into 11 test files covering models, optimizers, and infrastructure
- Test reorganization with clear naming conventions (test_model_, test_optimizer_, test_*)
Reviewed changes
Copilot reviewed 48 out of 50 changed files in this pull request and generated 47 comments.
Show a summary per file
| File | Description |
|---|---|
tests/test_pyomo_models/test_warmstart.py |
Tests warmstart adapter for all scipy optimizers |
tests/test_pyomo_models/test_staged_solve.py |
Tests 4-stage convergence framework |
tests/test_pyomo_models/test_parameter_validation.py |
Validates parameter inputs for create_optimizer_model |
tests/test_pyomo_models/test_optimizer_framework.py |
Tests core optimizer infrastructure |
tests/test_pyomo_models/test_optimizer_Tsh.py |
Tests shelf temperature optimization |
tests/test_pyomo_models/test_optimizer_Pch_Tsh.py |
Tests joint pressure-temperature optimization |
tests/test_pyomo_models/test_optimizer_Pch.py |
Tests pressure optimization |
tests/test_pyomo_models/test_model_validation.py |
Validates Pyomo vs scipy comparison |
tests/test_pyomo_models/test_model_single_step.py |
Tests single time-step model |
tests/test_pyomo_models/test_model_multi_period.py |
Tests multi-period DAE model |
tests/test_pyomo_models/test_model_advanced.py |
Advanced structural analysis tests |
tests/test_pyomo_models/__init__.py |
Test package initialization |
tests/test_pyomo_models/README.md |
Comprehensive test documentation |
requirements.txt |
Added pyomo and idaes-pse dependencies |
pytest.ini |
Added --dist loadgroup and serial marker |
lyopronto/pyomo_models/utils.py |
Utility functions for initialization and validation |
lyopronto/pyomo_models/single_step.py |
Single time-step optimization model |
lyopronto/pyomo_models/optimizers.py |
Main optimizer functions (1721 lines) |
lyopronto/pyomo_models/__init__.py |
Package initialization with exports |
lyopronto/pyomo_models/README.md |
Module documentation |
| return 0 | ||
|
|
||
| base_scen = copy.deepcopy(SCENARIOS[scenario_name]) | ||
| vial = base_scen["vial"] |
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable vial is not used.
| vial = base_scen["vial"] |
|
|
||
| base_scen = copy.deepcopy(SCENARIOS[scenario_name]) | ||
| vial = base_scen["vial"] | ||
| product = base_scen["product"] |
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable product is not used.
| product = base_scen["product"] |
| base_scen = copy.deepcopy(SCENARIOS[scenario_name]) | ||
| vial = base_scen["vial"] | ||
| product = base_scen["product"] | ||
| ht = base_scen["ht"] |
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable ht is not used.
| ht = base_scen["ht"] |
| vial = base_scen["vial"] | ||
| product = base_scen["product"] | ||
| ht = base_scen["ht"] | ||
| eq_cap = base_scen["eq_cap"] |
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable eq_cap is not used.
| eq_cap = base_scen["eq_cap"] |
| # ====================== | ||
|
|
||
| # Physical constants | ||
| dHs_J = 2838.4 # J/g (heat of sublimation) |
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable dHs_J is not used.
| 'ncp': None if use_finite_differences else n_collocation, | ||
| 'treat_effective': treat_n_elements_as_effective if not use_finite_differences else False, | ||
| } | ||
| except Exception: |
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'except' clause does nothing but pass and there is no explanatory comment.
| ub = pyo.value(constr[idx].upper) if constr[idx].upper is not None else float('inf') | ||
| viol = max(0, lb - body_val, body_val - ub) | ||
| viols.append(viol) | ||
| except: |
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'except' clause does nothing but pass and there is no explanatory comment.
| viol_count += 1 | ||
| if viol_count <= 5: | ||
| print(f" {con.name}[{idx}]: viol={viol:.2e}, body={body_val:.4f}, bounds=[{lb:.4f}, {ub:.4f}]") | ||
| except: |
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'except' clause does nothing but pass and there is no explanatory comment.
| if violation_count <= 10: # Only print first 10 | ||
| print(f" Violation in {constr.name}[{idx}]: {viol:.6f}") | ||
| print(f" LHS: {lhs:.6f}, Body: {body:.6f}, RHS: {rhs:.6f}") | ||
| except: |
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'except' clause does nothing but pass and there is no explanatory comment.
| import numpy as _np | ||
| if isinstance(o, _np.ndarray): | ||
| return o.tolist() | ||
| except Exception: |
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'except' clause does nothing but pass and there is no explanatory comment.
This PR contains the Pyomo models, tests, and small docs changes. Large benchmark result artifacts (in ) were moved to a separate branch to keep this PR small. See branch for the full data. Please review code and tests first; artifacts are preserved in .