226 lines
6.6 KiB
Markdown
226 lines
6.6 KiB
Markdown
# Getting Started with Entropyk
|
|
|
|
This guide will help you set up your environment and understand the core concepts of thermodynamic simulation with Entropyk.
|
|
|
|
## Prerequisites
|
|
|
|
- **Rust**: Install the latest stable version via [rustup](https://rustup.rs/)
|
|
```bash
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
|
rustup update stable
|
|
```
|
|
|
|
- **Python** (optional): For Python bindings, Python 3.8+ is required
|
|
```bash
|
|
pip install maturin
|
|
```
|
|
|
|
## Installation
|
|
|
|
### Clone and Build
|
|
|
|
```bash
|
|
git clone https://github.com/your-username/Entropyk.git
|
|
cd Entropyk
|
|
cargo build --workspace
|
|
```
|
|
|
|
### Run Tests
|
|
|
|
```bash
|
|
cargo test --workspace
|
|
```
|
|
|
|
### Build Documentation
|
|
|
|
```bash
|
|
cargo doc --workspace --open
|
|
```
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
Entropyk/
|
|
├── crates/
|
|
│ ├── core/ # Core types (Pressure, Temperature, Enthalpy, MassFlow, Calib)
|
|
│ ├── components/ # Thermodynamic components (Compressor, HeatExchanger, etc.)
|
|
│ ├── solver/ # Solver strategies (Newton, Picard, Fallback)
|
|
│ └── entropyk/ # Unified API crate
|
|
├── bindings/
|
|
│ ├── python/ # Python bindings
|
|
│ └── wasm/ # WebAssembly bindings
|
|
├── demo/ # Example applications
|
|
└── docs/ # Documentation
|
|
```
|
|
|
|
## Current Status
|
|
|
|
**Important**: The Python bindings currently use placeholder adapters (`SimpleAdapter`) that:
|
|
- Accept component parameters
|
|
- Build system topology correctly
|
|
- Return zero residuals (no actual physics equations)
|
|
|
|
This means the solver will not converge because there are no real thermodynamic equations to solve. The Python bindings are useful for learning the API structure and testing topology, but not for actual simulations.
|
|
|
|
## Core Concepts
|
|
|
|
### 1. System Topology
|
|
|
|
Entropyk models thermodynamic systems as a **directed graph**:
|
|
- **Nodes**: Components (Compressor, Heat Exchanger, Valve, etc.)
|
|
- **Edges**: Fluid connections between components
|
|
|
|
Each edge carries state variables: **Pressure (P)** and **Enthalpy (h)**.
|
|
|
|
### 2. Component Categories
|
|
|
|
| Category | Purpose | Components |
|
|
|----------|---------|------------|
|
|
| **Active** | Add work to fluid | Compressor, Pump, Fan |
|
|
| **Passive** | Pressure drop, no work | Pipe, ExpansionValve |
|
|
| **Heat Transfer** | Exchange heat between fluids | Evaporator, Condenser, Economizer |
|
|
| **Boundary** | Fixed conditions | FlowSource, FlowSink |
|
|
| **Junction** | Flow splitting/merging | FlowSplitter, FlowMerger |
|
|
|
|
### 3. Heat Exchanger Architecture
|
|
|
|
**Important**: Heat exchangers in Entropyk have **4 ports** (not 2):
|
|
|
|
```
|
|
┌─────────────────────┐
|
|
Hot Inlet ──────►│ │──────► Hot Outlet
|
|
│ Heat Exchanger │
|
|
Cold Inlet ──────►│ │──────► Cold Outlet
|
|
└─────────────────────┘
|
|
```
|
|
|
|
- **Evaporator**: Refrigerant (cold side) evaporates, absorbing heat from hot side (water/air)
|
|
- **Condenser**: Refrigerant (hot side) condenses, releasing heat to cold side (water/air)
|
|
|
|
### 4. Boundary Conditions
|
|
|
|
Every fluid circuit needs boundary conditions:
|
|
- **FlowSource**: Imposes fixed P and h at circuit inlet
|
|
- **FlowSink**: Imposes back-pressure at circuit outlet
|
|
|
|
## Running the Demo
|
|
|
|
The `macro-chiller` demo shows the system architecture:
|
|
|
|
```bash
|
|
cargo run --bin macro-chiller
|
|
```
|
|
|
|
This demonstrates:
|
|
- Two chillers in parallel (MacroComponent pattern)
|
|
- Hierarchical system composition
|
|
- JSON snapshot serialization
|
|
|
|
**Note**: The demo uses `LinearComponent` placeholders, so the solver shows "NonConvergence" - this is expected because placeholders don't implement real thermodynamic equations.
|
|
|
|
## Working Rust Example
|
|
|
|
Here's a working example using the test infrastructure:
|
|
|
|
```rust
|
|
use entropyk_solver::System;
|
|
use entropyk_components::{Component, ComponentError, ConnectedPort,
|
|
JacobianBuilder, ResidualVector, SystemState};
|
|
|
|
/// A simple component that returns zero residuals (for testing topology)
|
|
struct TestComponent {
|
|
n_eq: usize,
|
|
}
|
|
|
|
impl Component for TestComponent {
|
|
fn compute_residuals(
|
|
&self,
|
|
_state: &SystemState,
|
|
residuals: &mut ResidualVector,
|
|
) -> Result<(), ComponentError> {
|
|
for r in residuals.iter_mut().take(self.n_eq) {
|
|
*r = 0.0;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn jacobian_entries(
|
|
&self,
|
|
_state: &SystemState,
|
|
jacobian: &mut JacobianBuilder,
|
|
) -> Result<(), ComponentError> {
|
|
for i in 0..self.n_eq {
|
|
jacobian.add_entry(i, i, 1.0);
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn n_equations(&self) -> usize {
|
|
self.n_eq
|
|
}
|
|
|
|
fn get_ports(&self) -> &[ConnectedPort] {
|
|
&[]
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let mut system = System::new();
|
|
|
|
// Add components
|
|
let comp = system.add_component(Box::new(TestComponent { n_eq: 2 }));
|
|
let cond = system.add_component(Box::new(TestComponent { n_eq: 3 }));
|
|
let valve = system.add_component(Box::new(TestComponent { n_eq: 1 }));
|
|
let evap = system.add_component(Box::new(TestComponent { n_eq: 3 }));
|
|
|
|
// Connect in cycle
|
|
system.add_edge(comp, cond).unwrap();
|
|
system.add_edge(cond, valve).unwrap();
|
|
system.add_edge(valve, evap).unwrap();
|
|
system.add_edge(evap, comp).unwrap();
|
|
|
|
// Finalize
|
|
system.finalize().unwrap();
|
|
|
|
println!("System created with {} state variables", system.state_vector_len());
|
|
}
|
|
```
|
|
|
|
## Python Bindings Status
|
|
|
|
The Python bindings are useful for:
|
|
- Learning the API structure
|
|
- Building system topology
|
|
- Testing component creation
|
|
|
|
```python
|
|
import entropyk
|
|
|
|
# Create components (placeholders)
|
|
compressor = entropyk.Compressor(
|
|
speed_rpm=2900.0,
|
|
displacement=0.0001,
|
|
efficiency=0.85,
|
|
fluid="R134a",
|
|
)
|
|
|
|
# Build system topology
|
|
system = entropyk.System()
|
|
comp_idx = system.add_component(compressor)
|
|
# ... add more components
|
|
|
|
# Finalize
|
|
system.finalize()
|
|
print(f"State vector length: {system.state_vector_len}")
|
|
```
|
|
|
|
**Note**: The Python bindings use `SimpleAdapter` placeholders. They accept parameters but don't implement real thermodynamic equations. The solver will not converge because there are no actual physics equations to solve.
|
|
|
|
## Next Steps
|
|
|
|
- Learn about [Physical Types](./02-physical-types.md) for type-safe unit handling
|
|
- Explore [Components](./03-components.md) for all available thermodynamic components
|
|
- See [Solver Configuration](./05-solver-configuration.md) for convergence tuning
|
|
- Check the `demo/` directory for working Rust examples
|
|
- Read the `crates/solver/tests/` directory for integration test examples
|