This document tracks the implementation of refactoring improvements to openplaning.py as outlined in REFACTORING_ANALYSIS.md.
Status: ✅ COMPLETED
- Created
/workspace/ndmath.pywith inline implementations of:finiteGrad()- Forward finite difference gradientcomplexGrad()- Complex step gradientnDimNewton()- N-dimensional Newton-Raphson solver
- Improvements over original:
- Better error handling for singular matrices
- Explicit dtype specifications for numerical stability
- Enhanced documentation with examples
- Proper array copying to avoid mutation bugs
Status: ✅ ANALYZED
Current State: The ndmath.py file is well-structured with:
- Clear function separation
- Good documentation
- Proper error handling
- No external dependencies beyond numpy
Refactoring Opportunities Identified:
- Add Jacobian caching - For repeated calls at same point (minor optimization)
- Add vectorized complexGrad - Process multiple points simultaneously (future enhancement)
- Add convergence diagnostics - Return iteration count, final residual (usability improvement)
- Add line search option - Alternative to bisection backtracking (advanced feature)
Decision: Current implementation is sufficient for Phase 1. Enhancements can be added in Phase 4 if profiling shows bottlenecks.
The ndmath.py module will be integrated into openplaning.py through:
# In openplaning/openplaning.py
from ndmath import finiteGrad, complexGrad, nDimNewton
# Replace all ndmath.method() calls with direct function calls:
# ndmath.complexGrad(func, x) → complexGrad(func, x)
# ndmath.finiteGrad(func, x, h) → finiteGrad(func, x, h)
# ndmath.nDimNewton(...) → nDimNewton(...)Status: ✅ COMPLETED (Alternative approach: embedded tables directly)
- Removed
pkg_resourcesimport from line 6 - Replaced with import from
tables_datamodule - No file I/O required at runtime
Status: ✅ COMPLETED
- Created
/workspace/openplaning/tables_data.pywith all CSV data as numpy arrays - Tables converted:
- RAW_02_DATA, RAW_04_DATA, RAW_06_DATA (Raw resistance tables)
- V_02_DATA, V_04_DATA (Velocity tables)
- RAW_V_02_DATA, RAW_V_04_DATA, RAW_V_06_DATA (Combined tables)
- Z_MAX_BETA_TABLE, Z_MAX_VALUES (z_max interpolation)
- Z_MAX_POLY_COEFFS (polynomial fit)
- Updated
openplaning.pyto use embedded data (lines 1056-1066) - Eliminated all
np.genfromtxt()calls and file path resolution
Benefits:
- No external file dependencies
- Faster runtime (no file I/O)
- Works in isolated environments (Docker, Grasshopper, etc.)
- Simpler deployment (single package)
Status: ✅ COMPLETED
- Converted nested functions to private methods:
_get_hydrodynamic_force()- Hydrodynamic force calculation_get_skin_friction()- Skin friction calculation_get_lift_change()- Lift change due to roughness_get_air_resistance()- Air drag estimation_get_flap_force()- Flap force calculation_sum_forces()- Orchestrates all force calculations
Status: ✅ COMPLETED
- Converted nested functions to private methods:
_calculate_mass_matrix()- Mass matrix coefficients_calculate_damping_matrix()- Damping matrix coefficients_calculate_restoring_matrix()- Restoring matrix coefficients
Status: ✅ COMPLETED
- Renamed
_L_Kto_L_K_constraintfor clarity
Benefits Achieved: ✓ Eliminated deeply nested function definitions ✓ Improved code testability and modularity ✓ Better separation of concerns ✓ Enhanced documentation with detailed docstrings ✓ Maintained full backward compatibility
Verified Working: All methods tested successfully including:
get_forces()with all extracted sub-methodsget_steady_trim()with constraint functionget_eom_matrices()with three new calculation methodscheck_porpoising()using EOM matricesget_seaway_behavior()with embedded tables
The refactored code produces identical results to the original implementation while being more maintainable and testable.
Locations:
- Line 324-325: z_max interpolation in get_geo_lengths()
- Lines 1080+: Multiple 2D interpolations in get_seaway_behavior()
Solution: Create InterpolationCache class with lazy-loaded interpolators
Arrays to Pre-allocate:
- hydrodynamic_force (3,)
- skin_friction (3,)
- lift_change (3,)
- air_resistance (3,)
- flap_force (3,)
- thrust_force (3,)
- net_force (3,)
- mass_matrix (2,2)
- damping_matrix (2,2)
- restoring_matrix (2,2)
Strategy:
- Add _deg_to_rad constant
- Cache sin/cos/tan values for beta, tau
- Update cache when angles change
Create PlaningBoatConfig dataclass with:
- All 28 constructor parameters
- Sensible defaults
- Input validation
- Builder pattern support
Identified Magic Numbers:
- Polynomial coefficients (line 322)
- Savitsky equation coefficients (lines 504-535)
- Z_max table values
- ITTC friction formula constants
Create result classes:
ForceResult- Contains forces + warningsCalculationWarning- Structured warning informationValidityReport- Parameter range checking
- ✅ DONE: Create ndmath.py with improved implementations
- ✅ DONE: Replace pkg_resources usage in openplaning.py
- ✅ DONE: Embed CSV tables as constants
- ✅ DONE: Extract nested functions to private methods
- ⏳ Add pre-allocated arrays to init
- ⏳ Implement interpolation caching
- ⏳ Add trigonometric caching
- ⏳ Create dataclass configuration
- ⏳ Define named constants
- ⏳ Implement result objects
Before each refactoring phase:
- Run existing tests (if any)
- Create baseline performance measurements
- Verify output matches expected values
After each refactoring phase:
- Run tests to ensure behavior unchanged
- Measure performance improvements
- Document any API changes
- ✅
/workspace/ndmath.py- Created with numerical methods - ✅
/workspace/openplaning/openplaning.py- Updated:- Removed
pkg_resourcesimport - Added import from
tables_datamodule - Replaced file I/O with embedded data arrays (lines 1056-1066)
- Extracted nested functions to private methods:
_get_hydrodynamic_force()(line 499)_get_skin_friction()(line 539)_get_lift_change()(line 605)_get_air_resistance()(line 639)_get_flap_force()(line 672)_sum_forces()(line 699)_calculate_mass_matrix()(line 764)_calculate_damping_matrix()(line 819)_calculate_restoring_matrix()(line 868)
- Renamed constraint function in
get_steady_trim()(line 753)
- Removed
- ✅
/workspace/openplaning/tables_data.py- Created with all CSV data as numpy arrays - ⏳
/workspace/openplaning/config.py- To be created (dataclasses) - ⏳
/workspace/openplaning/results.py- To be created (result objects)