Compare commits
No commits in common. "d48d7828f5f1c8ac156e2b9c9d34a13a70b8398e" and "59c4e3857a5a076d3bf437da44cf2a165179bdc7" have entirely different histories.
d48d7828f5
...
59c4e3857a
@ -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
|
||||
|
||||
43
Dockerfile
43
Dockerfile
@ -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"]
|
||||
@ -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
|
||||
3213
Frontend/package-lock.json
generated
3213
Frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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"
|
||||
}
|
||||
}
|
||||
@ -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,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 }
|
||||
]
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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>
|
||||
)
|
||||
}
|
||||
@ -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
@ -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();
|
||||
@ -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;
|
||||
}
|
||||
@ -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"]
|
||||
}
|
||||
@ -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.
|
||||
|
||||
@ -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.
@ -1,5 +0,0 @@
|
||||
pytest
|
||||
httpx
|
||||
requests
|
||||
fastapi
|
||||
starlette
|
||||
@ -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
|
||||
Loading…
x
Reference in New Issue
Block a user