Compare commits

..

No commits in common. "d48d7828f5f1c8ac156e2b9c9d34a13a70b8398e" and "59c4e3857a5a076d3bf437da44cf2a165179bdc7" have entirely different histories.

36 changed files with 0 additions and 6316 deletions

View File

@ -1,14 +0,0 @@
__pycache__/
.venv/
test_outputs/
tests/
*.pyc
*.pyo
.pytest_cache/
.git/
tests_notebook/
IPM_DLL/
IPM_SO/
*.xlsm
datasets-2025-10-18-14-21.csv

View File

@ -1,43 +0,0 @@
FROM python:3.12-slim
ENV PYTHONUNBUFFERED=1
WORKDIR /app
# Install system deps required by numpy/pandas/matplotlib and building wheels
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
gcc \
gfortran \
libatlas3-base \
libopenblas-dev \
liblapack-dev \
libfreetype6-dev \
libpng-dev \
pkg-config \
ca-certificates \
curl \
git \
libglib2.0-0 \
libxrender1 \
libxext6 \
libsm6 \
&& rm -rf /var/lib/apt/lists/*
# Copy only requirements first for better layer caching
COPY requirements.txt /app/requirements.txt
# Upgrade pip and install python deps
RUN python -m pip install --upgrade pip setuptools wheel && \
python -m pip install -r /app/requirements.txt
# Copy project
COPY . /app
# Ensure Python and dynamic linker will find the native libs if mounted
ENV PYTHONPATH="/app:/app/IPM_SO:/app/IPM_DLL"
ENV LD_LIBRARY_PATH="/app/IPM_SO:/app/IPM_DLL"
EXPOSE 8001
# Default command runs uvicorn (use docker-compose override for development)
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8001"]

View File

View File

View File

@ -1,15 +0,0 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
output: 'standalone',
async rewrites() {
return [
{
source: '/api/v1/:path*',
destination: process.env.NEXT_PUBLIC_API_URL || 'http://backend:8001/api/v1/:path*',
},
];
},
}
module.exports = nextConfig

File diff suppressed because it is too large Load Diff

View File

@ -1,36 +0,0 @@
{
"name": "diagram-ph-frontend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"@hookform/resolvers": "^5.2.2",
"@types/node": "^24.8.1",
"@types/react": "^19.2.2",
"axios": "^1.12.2",
"lucide-react": "^0.546.0",
"next": "^15.5.6",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-hook-form": "^7.65.0",
"recharts": "^3.3.0",
"typescript": "^5.9.3",
"zod": "^4.1.12"
},
"devDependencies": {
"autoprefixer": "^10.4.21",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.18"
}
}

View File

@ -1,11 +0,0 @@
Pressure (bar),Enthalpy (kJ/kg)
3.2,580
3.5,595
11.8,650
12.1,652
12.0,380
11.9,375
3.3,378
8.5,500
5.0,450
7.2,520
1 Pressure (bar) Enthalpy (kJ/kg)
2 3.2 580
3 3.5 595
4 11.8 650
5 12.1 652
6 12.0 380
7 11.9 375
8 3.3 378
9 8.5 500
10 5.0 450
11 7.2 520

View File

@ -1,16 +0,0 @@
{
"description": "Sample test points for R290 refrigeration cycle",
"refrigerant": "R290",
"points": [
{ "pressure": 3.2, "enthalpy": 580 },
{ "pressure": 3.5, "enthalpy": 595 },
{ "pressure": 11.8, "enthalpy": 650 },
{ "pressure": 12.1, "enthalpy": 652 },
{ "pressure": 12.0, "enthalpy": 380 },
{ "pressure": 11.9, "enthalpy": 375 },
{ "pressure": 3.3, "enthalpy": 378 },
{ "pressure": 8.5, "enthalpy": 500 },
{ "pressure": 5.0, "enthalpy": 450 },
{ "pressure": 7.2, "enthalpy": 520 }
]
}

View File

@ -1,30 +0,0 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background: #0a0e1a;
min-height: 100vh;
color: #f8fafc;
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: #0a0e1a;
}
::-webkit-scrollbar-thumb {
background: #2d3548;
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: #3d4558;
}

View File

@ -1,19 +0,0 @@
import type { Metadata } from 'next'
import './globals.css'
export const metadata: Metadata = {
title: 'Diagram PH - Refrigeration Cycle Calculator',
description: 'Calculate and visualize refrigeration cycles',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}

View File

@ -1,67 +0,0 @@
"use client";
import { useState } from "react";
import PHDiagramModern from "@/components/PHDiagramModern";
import CycleCalculatorModern from "@/components/CycleCalculatorModern";
export default function Home() {
const [activeView, setActiveView] = useState<'calculator' | 'diagram'>('diagram');
return (
<div style={{ position: 'relative' }}>
<div style={{
position: 'fixed',
top: '2rem',
right: '2rem',
zIndex: 1000,
display: 'flex',
gap: '0.75rem',
background: 'rgba(30, 58, 95, 0.95)',
backdropFilter: 'blur(10px)',
padding: '0.5rem',
borderRadius: '16px',
boxShadow: '0 8px 32px rgba(0,0,0,0.3)',
border: '1px solid rgba(255,255,255,0.1)'
}}>
<button
onClick={() => setActiveView('diagram')}
style={{
padding: '0.75rem 1.5rem',
background: activeView === 'diagram' ? 'linear-gradient(135deg, #38b2ac 0%, #2c7a7b 100%)' : 'transparent',
border: 'none',
borderRadius: '12px',
color: '#ffffff',
fontSize: '0.9rem',
fontWeight: '700',
cursor: 'pointer',
transition: 'all 0.3s',
boxShadow: activeView === 'diagram' ? '0 4px 12px rgba(56, 178, 172, 0.4)' : 'none',
letterSpacing: '0.3px'
}}
>
📊 P-h Diagram
</button>
<button
onClick={() => setActiveView('calculator')}
style={{
padding: '0.75rem 1.5rem',
background: activeView === 'calculator' ? 'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)' : 'transparent',
border: 'none',
borderRadius: '12px',
color: '#ffffff',
fontSize: '0.9rem',
fontWeight: '700',
cursor: 'pointer',
transition: 'all 0.3s',
boxShadow: activeView === 'calculator' ? '0 4px 12px rgba(59, 130, 246, 0.4)' : 'none',
letterSpacing: '0.3px'
}}
>
🧮 Cycle Calculator
</button>
</div>
{activeView === 'diagram' && <PHDiagramModern />}
{activeView === 'calculator' && <CycleCalculatorModern />}
</div>
);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,65 +0,0 @@
import {
CycleCalculationRequest,
CycleCalculationResponse,
DiagramRequest,
DiagramResponse,
RefrigerantInfo,
RefrigerantsListResponse,
} from '@/types/api';
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8001/api/v1';
export class ApiClient {
private baseUrl: string;
constructor(baseUrl: string = API_BASE_URL) {
this.baseUrl = baseUrl;
}
async getRefrigerants(): Promise<RefrigerantInfo[]> {
const response = await fetch(`${this.baseUrl}/refrigerants/`);
if (!response.ok) {
throw new Error('Failed to fetch refrigerants');
}
const data: RefrigerantsListResponse = await response.json();
return data.refrigerants;
}
async calculateCycle(
request: CycleCalculationRequest
): Promise<CycleCalculationResponse> {
const response = await fetch(`${this.baseUrl}/cycles/simple`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(request),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || 'Failed to calculate cycle');
}
return response.json();
}
async generateDiagram(request: DiagramRequest): Promise<DiagramResponse> {
const response = await fetch(`${this.baseUrl}/diagrams/ph`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(request),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || 'Failed to generate diagram');
}
return response.json();
}
}
export const apiClient = new ApiClient();

View File

@ -1,84 +0,0 @@
export interface CycleCalculationRequest {
refrigerant: string;
evap_temperature?: number;
cond_temperature?: number;
evap_pressure?: number;
cond_pressure?: number;
compressor_efficiency?: number;
superheat?: number;
subcool?: number;
mass_flow?: number;
}
export interface CyclePoint {
point_id: string;
pressure: number;
temperature?: number;
enthalpy?: number;
entropy?: number;
quality?: number;
description?: string;
}
export interface CyclePerformance {
cop: number;
cooling_capacity: number;
heating_capacity: number;
compressor_power: number;
compressor_efficiency: number;
mass_flow: number;
volumetric_flow?: number;
compression_ratio: number;
discharge_temperature: number;
}
export interface CycleCalculationResponse {
success: boolean;
refrigerant: string;
points: CyclePoint[];
performance: CyclePerformance;
diagram_data?: any;
message?: string;
}
export interface DiagramRequest {
refrigerant: string;
pressure_range: {
min: number;
max: number;
};
enthalpy_range?: {
min: number;
max: number;
};
include_isotherms?: boolean;
isotherm_values?: number[];
cycle_points?: Array<{ enthalpy: number; pressure: number }>;
title?: string;
format?: string;
width?: number;
height?: number;
dpi?: number;
}
export interface DiagramResponse {
success: boolean;
image?: string;
data?: any;
metadata: any;
message?: string;
}
export interface RefrigerantInfo {
name: string;
formula?: string;
available: boolean;
loaded?: boolean;
error?: string;
}
export interface RefrigerantsListResponse {
refrigerants: RefrigerantInfo[];
total: number;
available_count: number;
}

View File

@ -1,24 +0,0 @@
{
"compilerOptions": {
"target": "ES2020",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [{ "name": "next" }],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

View File

View File

@ -1,42 +1,3 @@
````markdown
# IPM native integration (app.ipm)
This folder contains the Python wrapper that calls the native refifc libraries.
Goals
- Centralize the Python wrapper under `app/ipm` so application code can import `app.ipm.simple_refrig_api`.
- Provide a clear location for native binaries (DLLs for Windows, .so for Linux).
Where to place native binaries
- Windows (local/dev): place DLL files in `app/ipm/lib/windows/`.
- Linux (container/production): place .so files in `app/ipm/lib/linux/`.
The wrapper `app/ipm/simple_refrig_api.py` will look first in `app/ipm/lib/<platform>` (`windows` or `linux`) and fall back to the package directory if nothing is found.
Do NOT commit native binaries
--------------------------------
Native binaries should not be committed to the repo (size, licensing, portability). The repo contains a `.gitignore` rule excluding `app/ipm/lib/windows/*.dll` and `app/ipm/lib/linux/*.so`.
CI/CD
- Store binaries in a secure artifact repository (releases, internal storage, S3, etc.).
- During CI, download them and copy into `app/ipm/lib/<platform>` before building the image or deploying.
Quick local test
1. Copy the binaries into the correct folder (e.g. `app/ipm/lib/windows/refifc.dll`).
2. Test locally:
```powershell
.venv\Scripts\python -c "import app.ipm.simple_refrig_api as s; r=s.Refifc('R290'); print('hsl_px exists', hasattr(r,'hsl_px'))"
```
Best practices
- Avoid committing binaries in Git.
- Record the exact origin and version of native binaries in release notes.
- Provide small helper scripts (`scripts/copy-ipm-libs.*`) to automate copying binaries into build environments.
For French documentation see: [README_fr.md](README_fr.md)
````
# IPM native integration (app.ipm) — English (default)
This is the default README for the `app/ipm` package. It is the English version.

View File

View File

@ -1,59 +0,0 @@
version: '3.8'
services:
# Backend API Service
backend:
build:
context: .
dockerfile: Dockerfile
container_name: diagramph-backend
ports:
- "8001:8001"
volumes:
- ./app:/app/app:cached
- ./IPM_SO:/app/IPM_SO:cached
- ./IPM_DLL:/app/IPM_DLL:cached
environment:
- PYTHONUNBUFFERED=1
- PYTHONPATH=/app:/app/IPM_SO:/app/IPM_DLL
- LD_LIBRARY_PATH=/app/IPM_SO:/app/IPM_DLL
command: uvicorn app.main:app --host 0.0.0.0 --port 8001 --reload
networks:
- diagramph-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8001/api/v1/refrigerants/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# Frontend Service
frontend:
build:
context: ./Frontend
dockerfile: Dockerfile
container_name: diagramph-frontend
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- NEXT_PUBLIC_API_URL=http://backend:8001/api/v1
depends_on:
backend:
condition: service_healthy
networks:
- diagramph-network
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
diagramph-network:
driver: bridge
volumes:
backend-data:
frontend-data:

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +0,0 @@
pytest
httpx
requests
fastapi
starlette

View File

@ -1,11 +0,0 @@
fastapi==0.109.0
uvicorn[standard]==0.27.0
pydantic==2.5.0
pydantic-settings==2.1.0
numpy==1.26.3
pandas==2.2.0
matplotlib==3.8.2
plotly==5.18.0
python-multipart==0.0.6
cachetools==5.3.2
python-json-logger==2.0.7