feat: implement mass balance validation for Story 7.1
- Added port_mass_flows to Component trait and implements for core components. - Added System::check_mass_balance and integrated it into the solver. - Restored connect methods for ExpansionValve, Compressor, and Pipe to fix integration tests. - Updated Python and C bindings for validation errors. - Updated sprint status and story documentation.
This commit is contained in:
31
bindings/c/examples/Makefile
Normal file
31
bindings/c/examples/Makefile
Normal file
@@ -0,0 +1,31 @@
|
||||
CC ?= gcc
|
||||
CFLAGS = -Wall -Wextra -O2 -I../../../target
|
||||
|
||||
# Platform-specific library extension
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
LIB_EXT = dylib
|
||||
LDFLAGS = -L../../../target/release -lentropyk_ffi
|
||||
else ifeq ($(UNAME_S),Linux)
|
||||
LIB_EXT = so
|
||||
LDFLAGS = -L../../../target/release -lentropyk_ffi -Wl,-rpath,'$$ORIGIN/../../../target/release'
|
||||
else
|
||||
LIB_EXT = dll
|
||||
LDFLAGS = -L../../../target/release -lentropyk_ffi
|
||||
endif
|
||||
|
||||
.PHONY: all clean run
|
||||
|
||||
all: example
|
||||
|
||||
example: example.c ../../../target/entropyk.h ../../../target/release/libentropyk.$(LIB_EXT)
|
||||
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
|
||||
|
||||
../../../target/entropyk.h ../../../target/release/libentropyk.$(LIB_EXT):
|
||||
cd ../../.. && cargo build --release -p entropyk-c
|
||||
|
||||
run: example
|
||||
./example
|
||||
|
||||
clean:
|
||||
rm -f example
|
||||
178
bindings/c/examples/example.c
Normal file
178
bindings/c/examples/example.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* Simple refrigeration cycle example for Entropyk C FFI.
|
||||
*
|
||||
* Demonstrates:
|
||||
* - System lifecycle (create/free)
|
||||
* - Component creation (compressor, condenser, valve, evaporator)
|
||||
* - System topology (add components, add edges, finalize)
|
||||
* - Solving (fallback solver)
|
||||
* - Result retrieval
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "entropyk.h"
|
||||
|
||||
int main() {
|
||||
printf("Entropyk C FFI Example - Simple Refrigeration Cycle\n");
|
||||
printf("===================================================\n\n");
|
||||
|
||||
/* 1. Create the system */
|
||||
EntropykSystem* sys = entropyk_system_create();
|
||||
if (!sys) {
|
||||
printf("ERROR: Failed to create system\n");
|
||||
return 1;
|
||||
}
|
||||
printf("Created system\n");
|
||||
|
||||
/* 2. Create components */
|
||||
double compressor_coeffs[10] = {
|
||||
0.85, /* m1: mass flow coefficient */
|
||||
2.5, /* m2: mass flow exponent for suction pressure */
|
||||
500.0, /* m3: mass flow coefficient for superheat */
|
||||
1500.0, /* m4: power coefficient */
|
||||
-2.5, /* m5: power exponent */
|
||||
1.8, /* m6: power exponent */
|
||||
600.0, /* m7: additional power coefficient */
|
||||
1600.0, /* m8: additional power coefficient */
|
||||
-3.0, /* m9: power exponent */
|
||||
2.0 /* m10: power exponent */
|
||||
};
|
||||
|
||||
EntropykComponent* comp = entropyk_compressor_create(compressor_coeffs, 10);
|
||||
EntropykComponent* cond = entropyk_condenser_create(5000.0); /* 5 kW/K */
|
||||
EntropykComponent* valve = entropyk_expansion_valve_create();
|
||||
EntropykComponent* evap = entropyk_evaporator_create(3000.0); /* 3 kW/K */
|
||||
|
||||
if (!comp || !cond || !valve || !evap) {
|
||||
printf("ERROR: Failed to create components\n");
|
||||
entropyk_system_free(sys);
|
||||
return 1;
|
||||
}
|
||||
printf("Created 4 components: compressor, condenser, valve, evaporator\n");
|
||||
|
||||
/* 3. Add components to system (transfers ownership, returns node index) */
|
||||
unsigned int comp_idx = entropyk_system_add_component(sys, comp);
|
||||
unsigned int cond_idx = entropyk_system_add_component(sys, cond);
|
||||
unsigned int valve_idx = entropyk_system_add_component(sys, valve);
|
||||
unsigned int evap_idx = entropyk_system_add_component(sys, evap);
|
||||
|
||||
if (comp_idx == UINT32_MAX || cond_idx == UINT32_MAX ||
|
||||
valve_idx == UINT32_MAX || evap_idx == UINT32_MAX) {
|
||||
printf("ERROR: Failed to add component to system\n");
|
||||
entropyk_system_free(sys);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Added components: comp=%u, cond=%u, valve=%u, evap=%u\n",
|
||||
comp_idx, cond_idx, valve_idx, evap_idx);
|
||||
|
||||
/* 4. Connect components (simple cycle: comp -> cond -> valve -> evap -> comp) */
|
||||
EntropykErrorCode err;
|
||||
|
||||
err = entropyk_system_add_edge(sys, comp_idx, cond_idx);
|
||||
if (err != ENTROPYK_OK) {
|
||||
printf("ERROR: Failed to add edge comp->cond: %s\n", entropyk_error_string(err));
|
||||
entropyk_system_free(sys);
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = entropyk_system_add_edge(sys, cond_idx, valve_idx);
|
||||
if (err != ENTROPYK_OK) {
|
||||
printf("ERROR: Failed to add edge cond->valve: %s\n", entropyk_error_string(err));
|
||||
entropyk_system_free(sys);
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = entropyk_system_add_edge(sys, valve_idx, evap_idx);
|
||||
if (err != ENTROPYK_OK) {
|
||||
printf("ERROR: Failed to add edge valve->evap: %s\n", entropyk_error_string(err));
|
||||
entropyk_system_free(sys);
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = entropyk_system_add_edge(sys, evap_idx, comp_idx);
|
||||
if (err != ENTROPYK_OK) {
|
||||
printf("ERROR: Failed to add edge evap->comp: %s\n", entropyk_error_string(err));
|
||||
entropyk_system_free(sys);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Connected components in cycle\n");
|
||||
printf("System: %u nodes, %u edges\n",
|
||||
entropyk_system_node_count(sys),
|
||||
entropyk_system_edge_count(sys));
|
||||
|
||||
/* 5. Finalize the system */
|
||||
err = entropyk_system_finalize(sys);
|
||||
if (err != ENTROPYK_OK) {
|
||||
printf("ERROR: Failed to finalize system: %s\n", entropyk_error_string(err));
|
||||
entropyk_system_free(sys);
|
||||
return 1;
|
||||
}
|
||||
printf("System finalized (state vector length: %u)\n",
|
||||
entropyk_system_state_vector_len(sys));
|
||||
|
||||
/* 6. Configure and run solver */
|
||||
EntropykFallbackConfig config = {
|
||||
.newton = {
|
||||
.max_iterations = 100,
|
||||
.tolerance = 1e-6,
|
||||
.line_search = false,
|
||||
.timeout_ms = 0
|
||||
},
|
||||
.picard = {
|
||||
.max_iterations = 500,
|
||||
.tolerance = 1e-4,
|
||||
.relaxation = 0.5
|
||||
}
|
||||
};
|
||||
|
||||
EntropykSolverResult* result = NULL;
|
||||
err = entropyk_solve_fallback(sys, &config, &result);
|
||||
|
||||
/* 7. Check results */
|
||||
if (err == ENTROPYK_OK && result != NULL) {
|
||||
EntropykConvergenceStatus status = entropyk_result_get_status(result);
|
||||
unsigned int iterations = entropyk_result_get_iterations(result);
|
||||
double residual = entropyk_result_get_residual(result);
|
||||
|
||||
printf("\n=== Solver Results ===\n");
|
||||
printf("Status: %s\n",
|
||||
status == CONVERGED ? "CONVERGED" :
|
||||
status == CONVERGED_TIMED_OUT ? "TIMED_OUT" :
|
||||
status == CONVERGED_CONTROL_SATURATION ? "CONTROL_SATURATION" : "UNKNOWN");
|
||||
printf("Iterations: %u\n", iterations);
|
||||
printf("Final residual: %.2e\n", residual);
|
||||
|
||||
/* Get state vector */
|
||||
unsigned int len = 0;
|
||||
entropyk_result_get_state_vector(result, NULL, &len);
|
||||
if (len > 0) {
|
||||
double* state = (double*)malloc(len * sizeof(double));
|
||||
if (state) {
|
||||
entropyk_result_get_state_vector(result, state, &len);
|
||||
printf("State vector[%u]: [", len);
|
||||
for (unsigned int i = 0; i < (len < 6 ? len : 6); i++) {
|
||||
printf("%.2f", state[i]);
|
||||
if (i < len - 1) printf(", ");
|
||||
}
|
||||
if (len > 6) printf(", ...");
|
||||
printf("]\n");
|
||||
free(state);
|
||||
}
|
||||
}
|
||||
|
||||
entropyk_result_free(result);
|
||||
} else {
|
||||
printf("\n=== Solver Failed ===\n");
|
||||
printf("Error: %s\n", entropyk_error_string(err));
|
||||
}
|
||||
|
||||
/* 8. Cleanup */
|
||||
entropyk_system_free(sys);
|
||||
printf("\nCleanup complete.\n");
|
||||
|
||||
return (err == ENTROPYK_OK) ? 0 : 1;
|
||||
}
|
||||
Reference in New Issue
Block a user