chore: sync project state and current artifacts

This commit is contained in:
Sepehr
2026-02-22 23:27:31 +01:00
parent 1b6415776e
commit dd77089b22
232 changed files with 37056 additions and 4296 deletions

View File

@@ -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)?;
```