EngForge is a sophisticated engineering systems framework that provides tabulation, analysis, and solver capabilities for complex engineering problems. It's built on a component-system architecture with dynamic programming optimizations and integrated reporting.
-
Component-System Architecture: The framework uses a hierarchical design where:
Component: Basic building blocks that encapsulate engineering calculations and propertiesSystem: Orchestrates multiple components, manages data flow, and provides solver capabilities- Both inherit from
SolveableInterfacewhich provides tabulation, configuration, and solving capabilities
-
Configuration-Based Design: Uses the
@forgedecorator (similar to@attrs.define) to automatically configure classes with:- Attribute validation and transformation
- Property change tracking
- Signal and slot management
- Automatic name generation
-
Cached Property System: Implements dynamic programming through cached properties:
@system_property: Basic cached properties@cached_system_property: Only recalculates when dependencies change- Properties automatically track dependencies and invalidate when inputs change
-
Signal-Slot Pattern: Data flow between components is managed via:
Signal.define(source, target, mode): Defines data flow connectionsSlot.define(ComponentType): Defines component mounting points- Supports pre/post execution modes and control signals
@forgedecorator: Main class decorator that configures all EngForge classesConfiguration: Base class providing attribute management and property change callbacks- Automatic name generation using randomized technical terms
- Property change tracking with
property_changedcallback
SolveableInterface: Common base providing tabulation, configuration, and solvingComponent: Basic building block with evaluation and caching capabilitiesDynamicsMixin: Provides time-based integration capabilities
System: Orchestrates components, manages solver execution, provides plotting- Inherits from
SolverMixin,SolveableInterface,PlottingMixin,GlobalDynamics - Manages component slots and signal routing
- Provides solver execution with constraint handling
SolverMixin: Core solver capabilities using scipy optimizersSolver.define(dependent, independent): Defines solver equations- Constraint system with min/max limits and custom functions
- Supports multiple solver combos and variable sets
ATTR_BASE: Base attribute system with dependency trackingTime: Time integration attributes for dynamicsSignal: Data flow attributesSlot: Component mounting attributesPlot/Trace: Plotting and visualization attributes- All attributes support instance-level customization and caching
The framework implements sophisticated caching through several property decorators:
@system_property
def calculated_value(self) -> float:
"""Basic cached property"""
return expensive_calculation()
@cached_system_property
def dynamic_value(self) -> float:
"""Only recalculates when dependencies change"""
return self.input_a * self.input_bProperties automatically:
- Cache results until dependencies change
- Track inter-property dependencies
- Support type validation and conversion
- Integrate with the solver system for constraint handling
The framework provides comprehensive data capture through:
- System References (
engforge/system_reference.py): Lightweight references to nested attributes - DataframeMixin (
engforge/dataframe.py): Automatic pandas DataFrame generation - TabulationMixin (
engforge/tabulation.py): Data collection and organization
All component attributes and system properties are automatically captured into structured DataFrames suitable for analysis and reporting.
FluidMaterial: Base class for fluid property calculationsCoolPropMaterial: Integration with CoolProp thermodynamic database- Built-in materials: Air, Water, Steam, Hydrogen, Oxygen
- Support for mixtures and ideal gas approximations
SolidMaterial: Material property definitions- Standard materials: Steel (SS_316, ANSI_4130/4340), Aluminum, Carbon Fiber, Concrete
- Stress/strain calculations and safety factors
- Component models: Compressor, Turbine, Heat Exchanger, Pump
- Cycle analysis capabilities
- Heat transfer and pressure drop correlations
- Beam analysis with PyNite FEA integration
- Cross-sectional property calculations
- Geometric primitives and section properties
- Flow network modeling with pressure drop calculations
- Pump and fitting models
- System-level flow analysis
- Engineering economics with time value of money
- Cost categorization and breakdown analysis
- Integration with system design parameters
The project uses Python's built-in unittest framework:
- Tests located in
engforge/test/directory - Import tests in
test_modules.pyverify all modules load correctly - Domain-specific tests for components, solver, dynamics, etc.
# Install package in development mode
pip install -e .
# Run all tests
python -m unittest discover -s engforge/test -p "test_*.py" -v
# Run specific test module
python -m unittest engforge.test.test_modules -vThe full test suite requires all optional dependencies. Core functionality can be tested with:
attrs>=23.2.0- Core attribute systemnumpy>=1.24.3- Numerical computationsscipy- Solver algorithmsmatplotlib>=3.8.1- Plottingpandas- Data handling
Located in examples/air_filter.py, demonstrates:
- Component definition with
@forgedecorator - System assembly with slots and signals
- Solver configuration for flow balancing
- Plotting integration and data analysis
Shows dynamic system analysis with:
- Time integration using
Time.integrate() - Solver constraints and variable handling
- Multi-parameter studies with
run()method
The Analysis class provides:
- System wrapping with additional post-processing
- Multiple reporter integration (CSV, Excel, plots)
- Automated data collection and storage
- Only modify non-scientific code: Algorithmic and engineering calculations should not be altered
- Follow existing patterns: Use
@forge, inherit from appropriate base classes - Maintain property caching: Ensure expensive calculations are properly cached
- Preserve signal-slot architecture: Data flow should use defined patterns
The project uses a comprehensive CI/CD pipeline that can be validated locally:
-
Create clean test environment:
cd /tmp && python -m venv test_engforge_env source test_engforge_env/bin/activate pip install --upgrade pip
-
Install package and dependencies:
cd <project_root> source /tmp/test_engforge_env/bin/activate pip install -e . # Core dependencies only pip install -e .[all] # All optional dependencies pip install -e .[database] # Database functionality only pip install -e .[google,cloud] # Specific optional groups
-
Test version extraction (CI compatibility):
python -c " try: import tomllib except ImportError: import tomli as tomllib with open('pyproject.toml', 'rb') as f: print('✅ Version:', tomllib.load(f)['project']['version']) "
-
Run tests:
python -m unittest discover -s engforge/test -p "test_*.py" -v -
Check code formatting:
black --check --verbose ./engforge
- tomllib ImportError: Fixed with
tomli>=1.2.0;python_version<'3.11'dependency - SQLAlchemy missing: Auto-installation will prompt when importing datastores, or install manually with
pip install engforge[database] - Black formatting: All files should pass formatting checks; use
black ./engforgeto auto-format
The project uses modern pyproject.toml optional dependencies with intelligent auto-installation:
Dependency Groups:
[database]: SQLAlchemy, PostgreSQL, disk caching[google]: Google Sheets and Drive integration[cloud]: AWS boto3 integration[distributed]: Ray distributed computing[all]: All optional dependencies combined
Auto-Installation Behavior:
- When importing
engforge.datastores, missing dependencies trigger an auto-install prompt - Reads pyproject.toml directly to determine required packages
- Works in development mode (editable installs) by detecting project root
- Graceful fallback to manual installation instructions
Manual Installation:
pip install engforge[database,cloud] # Specific groups
pip install engforge[all] # All optional dependencies
pip install -e .[all] # Development mode with all depsconfiguration.py- Core class configuration systemcomponents.py- Component base classessystem.py- System orchestrationproperties.py- Property and caching decoratorsattributes.py- Attribute system foundation
@forge # Always use this decorator
class MyComponent(Component):
# Use attrs.field for inputs
input_value: float = attrs.field(default=1.0)
# Use system_property for calculated outputs
@system_property
def output_value(self) -> float:
return self.input_value * 2.0
@forge
class MySystem(System):
# Define component slots
comp: MyComponent = Slot.define(MyComponent)
# Define data flow
set_input = Signal.define('external_param', 'comp.input_value')
# Define solver if needed
solver = Solver.define('constraint_equation', 'control_variable')The framework emphasizes declarative configuration over imperative programming, extensive use of caching for performance, and clear separation between data flow definition and execution.