Entropyk/docs/tutorial/01-getting-started.md

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