chore: sync project state and current artifacts
This commit is contained in:
215
EXAMPLES_FULL.md
215
EXAMPLES_FULL.md
@@ -1,106 +1,177 @@
|
||||
# Entropyk: Comprehensive Examples
|
||||
# Entropyk: Comprehensive Examples Suite
|
||||
|
||||
This document provides deep-dive examples for various Entropyk features across different platforms.
|
||||
This document provides advanced modeling scenarios for Entropyk across its multi-platform ecosystem.
|
||||
|
||||
## 1. Simple Refrigeration Cycle (Rust)
|
||||
The "Hello World" of thermodynamics.
|
||||
---
|
||||
|
||||
## 1. Multi-Circuit Industrial Chiller (Rust)
|
||||
Modeling a water-cooled chiller where a refrigerant loop (R134a) and a water loop are coupled via an evaporator (bridge).
|
||||
|
||||
### 1.1 System Architecture
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph Circuit_0 [Circuit 0: Refrigerant]
|
||||
comp[Compressor] --> cond[Condenser]
|
||||
cond --> valve[Expansion Valve]
|
||||
valve --> evap_a[Evaporator Side A]
|
||||
evap_a --> comp
|
||||
end
|
||||
|
||||
subgraph Circuit_1 [Circuit 1: Water Loop]
|
||||
pump[Pump] --> evap_b[Evaporator Side B]
|
||||
evap_b --> building[Building Load]
|
||||
building --> pump
|
||||
end
|
||||
|
||||
evap_a <-.->|Thermal Coupling| evap_b
|
||||
```
|
||||
|
||||
### 1.2 Implementation Detail
|
||||
```rust
|
||||
use entropyk_components::compressor::{Compressor, Ahri540Coefficients};
|
||||
use entropyk_components::heat_exchanger::{Condenser, Evaporator};
|
||||
use entropyk_components::expansion_valve::ExpansionValve;
|
||||
use entropyk_solver::{System, FallbackConfig};
|
||||
use entropyk_components::{Compressor, HeatExchanger, Pump};
|
||||
use entropyk_solver::{System, NewtonConfig, ThermalCoupling};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut system = System::new();
|
||||
|
||||
// 1. Create Components
|
||||
let comp = Compressor::new(Ahri540Coefficients::typical(), ...)?;
|
||||
let cond = Condenser::new(5000.0);
|
||||
let valve = ExpansionValve::new(...)?;
|
||||
let evap = Evaporator::new(3000.0);
|
||||
// Circuit 0: Refrigerant Loop
|
||||
let comp = system.add_component(Compressor::new(coeffs, ...));
|
||||
let cond = system.add_component(HeatExchanger::new_condenser(ua_air));
|
||||
let valve = system.add_component(ExpansionValve::new(cv));
|
||||
let evap = system.add_component(HeatExchanger::new_bridge(ua_water)); // COUPLING POINT
|
||||
|
||||
// 2. Add to System & Connect
|
||||
let n1 = system.add_component(Box::new(comp));
|
||||
let n2 = system.add_component(Box::new(cond));
|
||||
let n3 = system.add_component(Box::new(valve));
|
||||
let n4 = system.add_component(Box::new(evap));
|
||||
system.add_edge_in_circuit(comp, cond, 0)?;
|
||||
system.add_edge_in_circuit(cond, valve, 0)?;
|
||||
system.add_edge_in_circuit(valve, evap.side_a, 0)?;
|
||||
system.add_edge_in_circuit(evap.side_a, comp, 0)?;
|
||||
|
||||
system.add_edge(n1, n2)?; // Comp -> Cond
|
||||
system.add_edge(n2, n3)?; // Cond -> Valve
|
||||
system.add_edge(n3, n4)?; // Valve -> Evap
|
||||
system.add_edge(n4, n1)?; // Evap -> Comp
|
||||
// Circuit 1: Water loop
|
||||
let pump = system.add_component(Pump::new(curve));
|
||||
let building = system.add_component(HeatExchanger::new_load(50_000.0)); // 50kW Load
|
||||
|
||||
system.add_edge_in_circuit(pump, evap.side_b, 1)?;
|
||||
system.add_edge_in_circuit(evap.side_b, building, 1)?;
|
||||
system.add_edge_in_circuit(building, pump, 1)?;
|
||||
|
||||
// 3. Finalize & Solve
|
||||
system.finalize()?;
|
||||
let config = FallbackConfig::default();
|
||||
let result = config.solve(&system)?;
|
||||
|
||||
println!("Cycle COP: {}", result.cop());
|
||||
// Simultaneous Multi-Circuit Solve
|
||||
let solver = NewtonConfig::default().with_line_search(true);
|
||||
let state = solver.solve(&mut system)?;
|
||||
|
||||
println!("Chiller System COP: {}", state.cop());
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Parameter Estimation in Python
|
||||
Estimating fouling (UA reduction) from sensor data.
|
||||
### 1.3 Control & Coupling Logic
|
||||
The solver treats both circuits as a unified graph. The `HeatExchanger` bridge enforces the following boundary conditions:
|
||||
- **Energy Balance**: $\dot{Q}_{refrig} = \dot{Q}_{water}$ (assuming no ambient loss).
|
||||
- **Temperature Coupling**: The effectiveness-NTU model internally calculates the heat transfer based on the inlet temperatures of *both* circuits.
|
||||
- **Unified Jacobian**: The solver constructs a single Jacobian matrix where off-diagonal blocks represent the thermal coupling, allowing for simultaneous convergence of both loops.
|
||||
|
||||
---
|
||||
|
||||
## 2. Inverse Control & Parameter Estimation (Python)
|
||||
Finding the Heat Exchanger Fouling (UA) by matching simulation to sensor data.
|
||||
|
||||
### 2.1 Control Flow Diagram
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant U as User (Script)
|
||||
participant S as System Solver
|
||||
participant P as Physical Model
|
||||
participant C as Constraint Engine
|
||||
|
||||
U->>S: Define Architecture & Constraints
|
||||
Note over S,C: Link Constraint (Temp) to Control (UA)
|
||||
loop Iterations (Newton-Raphson)
|
||||
S->>P: Compute Residuals F(x)
|
||||
P->>S: Physical Violations
|
||||
S->>C: Compute Constraint Gradients (dC/dua)
|
||||
C->>S: Jacobian Block
|
||||
S->>S: Solve Augmented System [J | G]
|
||||
S->>S: Update State (x) & Control (ua)
|
||||
end
|
||||
S->>U: Converged Parameters (UA)
|
||||
```
|
||||
|
||||
### 2.2 Implementation Breakdown
|
||||
```python
|
||||
import entropyk as ek
|
||||
|
||||
# Setup system with experimental targets
|
||||
system = ek.System()
|
||||
comp = system.add_component(ek.Compressor(...))
|
||||
cond = system.add_component(ek.Condenser(ua=5000.0)) # Initial guess
|
||||
# 1. Define physical system
|
||||
sys = ek.System()
|
||||
hx = sys.add_component(ek.HeatExchanger(ua=5000.0)) # Initial guess
|
||||
|
||||
# Add Inverse Control target: Discharge temperature must match sensor
|
||||
system.add_constraint(target_node=cond, target_value=325.15, ... )
|
||||
# 2. Add Constraint: We KNOW the exit temperature from a sensor
|
||||
# Target: Exit port of HX must be 280.15 K
|
||||
sys.add_constraint(
|
||||
node_id=hx,
|
||||
variable="exit_temp",
|
||||
target=280.15,
|
||||
tolerance=0.01
|
||||
)
|
||||
|
||||
# Solve for the UA that makes the physics match the sensor
|
||||
# 3. Designate UA as a "Calibration Variable" (Solver will tune this)
|
||||
sys.link_constraint_to_control(hx, "ua", bounds=(1000.0, 10000.0))
|
||||
|
||||
# 4. Solve Sparse Inverse Problem
|
||||
solver = ek.NewtonConfig(inverse_mode=True)
|
||||
result = solver.solve(system)
|
||||
result = solver.solve(sys)
|
||||
|
||||
print(f"Calculated UA: {result.component_params[cond].ua} W/K")
|
||||
print(f"Estimated UA based on sensor: {hx.ua:.2f} W/K")
|
||||
```
|
||||
|
||||
## 3. Custom Component Implementation
|
||||
How to add a new physical model.
|
||||
### 2.3 Logic Breakdown: The Augmented Matrix
|
||||
In standard "Forward" mode, the solver solves $F(x) = 0$. In "Inverse" mode, we add a constraint $C(x, u) = 0$ (where $u$ is our control, e.g., UA). The solver internally solves:
|
||||
|
||||
```rust
|
||||
use entropyk_components::{Component, SystemState, ResidualVector, JacobianBuilder, ConnectedPort};
|
||||
$$
|
||||
\begin{bmatrix}
|
||||
\mathcal{J}_x & \mathcal{G}_u \\
|
||||
\mathcal{C}_x & 0
|
||||
\end{bmatrix}
|
||||
\begin{bmatrix} \Delta x \\ \Delta u \end{bmatrix} =
|
||||
-\begin{bmatrix} F(x) \\ C(x, u) \end{bmatrix}
|
||||
$$
|
||||
|
||||
struct BypassValve {
|
||||
opening: f64,
|
||||
}
|
||||
- $\mathcal{J}_x$: Standard physical Jacobian.
|
||||
- $\mathcal{G}_u$: Sensitivity of physics to the control variable (how a change in UA affects mass/energy residuals).
|
||||
- $\mathcal{C}_x$: Sensitivity of the constraint to state variables.
|
||||
- $\Delta u$: The correction to our estimated parameter (UA) to satisfy the sensor target.
|
||||
|
||||
impl Component for BypassValve {
|
||||
fn compute_residuals(&self, state: &SystemState, residuals: &mut ResidualVector) -> Result<(), ComponentError> {
|
||||
// P_out = P_in - (k * opening^2 * flow^2)
|
||||
residuals[0] = state[1] - (state[0] - self.calc_dp(state));
|
||||
Ok(())
|
||||
---
|
||||
|
||||
## 3. Real-Time HIL Integration (C FFI)
|
||||
Zero-allocation solving for embedded controllers at 100Hz.
|
||||
|
||||
```c
|
||||
#include "entropyk.h"
|
||||
|
||||
int main() {
|
||||
// 1. Initialize system once (pre-allocate hooks)
|
||||
ek_system_t* sys = ek_system_create();
|
||||
ek_compressor_t* comp = ek_compressor_create(coeffs);
|
||||
ek_system_add_component(sys, comp);
|
||||
// ... connections ...
|
||||
ek_system_finalize(sys);
|
||||
|
||||
// 2. Control Loop (10ms steps)
|
||||
while (running) {
|
||||
// Update boundary conditions (e.g. ambient T)
|
||||
ek_system_set_source_temp(sys, source_node, get_sensor_t());
|
||||
|
||||
// Solve using previous state as hot-start
|
||||
ek_converged_state_t* res = ek_solve(sys, PICARD_STRATEGY);
|
||||
|
||||
if (ek_converged_state_is_ok(res)) {
|
||||
float p_disch = ek_converged_state_get_p(res, discharge_port);
|
||||
apply_to_plc(p_disch);
|
||||
}
|
||||
|
||||
ek_converged_state_free(res);
|
||||
}
|
||||
|
||||
fn jacobian_entries(&self, state: &SystemState, jacobian: &mut JacobianBuilder) -> Result<(), ComponentError> {
|
||||
// Provide partial derivatives for fast convergence
|
||||
jacobian.add_entry(0, 0, self.dp_dm(state));
|
||||
jacobian.add_entry(0, 1, 1.0);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn n_equations(&self) -> usize { 1 }
|
||||
fn get_ports(&self) -> &[ConnectedPort] { &self.ports }
|
||||
ek_system_free(sys);
|
||||
}
|
||||
```
|
||||
|
||||
## 4. Multi-Circuit Coupling
|
||||
Bridging a Chiller to a Water loop.
|
||||
|
||||
```rust
|
||||
// Evaporator acts as a bridge
|
||||
let evaporator = HeatExchanger::new_bridge(ua);
|
||||
|
||||
system.add_edge(refrigerant_valve, evaporator.side_a_in)?;
|
||||
system.add_edge(evaporator.side_a_out, refrigerant_comp)?;
|
||||
|
||||
system.add_edge(water_pump, evaporator.side_b_in)?;
|
||||
system.add_edge(evaporator.side_b_out, water_building)?;
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user