/**
* Graphique montrant l'évolution du nombre de clients pour identifier le régime permanent
*/
import { useMemo } from 'react';
import {
Box,
Paper,
Typography,
Alert,
AlertTitle,
} from '@mui/material';
import { TrendingUp as TrendingUpIcon, MenuBook as MenuBookIcon } from '@mui/icons-material';
import { Line } from 'react-chartjs-2';
import { useSimulationStore } from '../../store/simulationStore';
import { formatTime } from '../../utils/timeFormat';
interface SteadyStateChartProps {
warmupTime?: number;
}
export default function SteadyStateChart({ warmupTime }: SteadyStateChartProps) {
const { simulationResults, config, timeUnit } = useSimulationStore();
const { chartData, stats } = useMemo(() => {
if (!simulationResults?.time_series) {
return { chartData: null, stats: null };
}
const { timestamps, customers_in_system } = simulationResults.time_series;
if (!timestamps || timestamps.length === 0) {
return { chartData: null, stats: null };
}
const warmup = warmupTime || config?.warmup_time || 0;
// Séparer période de chauffe et régime permanent
const warmupData = timestamps
.map((time, i) => ({ time, clients: customers_in_system[i] }))
.filter(d => d.time < warmup);
const steadyStateData = timestamps
.map((time, i) => ({ time, clients: customers_in_system[i] }))
.filter(d => d.time >= warmup);
// Calculer statistiques du régime permanent
let steadyStats = null;
if (steadyStateData.length > 0) {
const steadyStateClients = steadyStateData.map(d => d.clients);
const mean = steadyStateClients.reduce((a, b) => a + b, 0) / steadyStateClients.length;
const variance = steadyStateClients.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / steadyStateClients.length;
const stdDev = Math.sqrt(variance);
const min = Math.min(...steadyStateClients);
const max = Math.max(...steadyStateClients);
const cv = (stdDev / mean) * 100;
steadyStats = {
warmup,
mean,
stdDev,
min,
max,
cv,
warmupPoints: warmupData.length,
steadyStatePoints: steadyStateData.length,
};
}
// Préparer les données pour Chart.js
const data = {
labels: timestamps.map(t => formatTime(t, timeUnit)),
datasets: [
{
label: 'Nombre de clients',
data: customers_in_system,
borderColor: 'rgb(25, 118, 210)',
backgroundColor: 'rgba(25, 118, 210, 0.1)',
borderWidth: 2,
fill: true,
tension: 0.1,
pointRadius: 0,
pointHoverRadius: 4,
segment: {
borderColor: (ctx: any) => {
const idx = ctx.p0DataIndex;
const time = timestamps[idx];
return time < warmup ? 'rgba(237, 108, 2, 0.6)' : 'rgb(25, 118, 210)';
},
backgroundColor: (ctx: any) => {
const idx = ctx.p0DataIndex;
const time = timestamps[idx];
return time < warmup ? 'rgba(237, 108, 2, 0.1)' : 'rgba(25, 118, 210, 0.1)';
},
},
},
],
};
return { chartData: data, stats: steadyStats };
}, [simulationResults, timeUnit, warmupTime, config]);
if (!simulationResults) {
return null;
}
if (!chartData || !stats) {
return (
Séries temporelles non disponibles
Les données de séries temporelles n'ont pas été collectées pour cette simulation.
);
}
const options = {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'index' as const,
intersect: false,
},
plugins: {
legend: {
position: 'top' as const,
},
tooltip: {
callbacks: {
title: (items: any[]) => {
if (items.length > 0) {
return `Temps: ${items[0].label}`;
}
return '';
},
label: (context: any) => {
return `Clients: ${context.parsed.y}`;
},
},
},
},
scales: {
x: {
title: {
display: true,
text: `Temps (${timeUnit})`,
},
ticks: {
maxTicksLimit: 10,
},
},
y: {
title: {
display: true,
text: 'Nombre de clients',
},
beginAtZero: true,
},
},
};
return (
Évolution du Système - Détection du Régime Permanent
{/* Informations sur le régime permanent */}
Période de chauffe
{formatTime(stats.warmup, timeUnit)}
{stats.warmupPoints} points échantillonnés
Régime permanent
{stats.steadyStatePoints} points
L moyen = {stats.mean.toFixed(3)} clients
Coefficient de variation
{stats.cv.toFixed(1)}%
{stats.cv < 10 ? 'Très stable' : stats.cv < 30 ? 'Stable' : 'Variable'}
{/* Statistiques du régime permanent */}
Statistiques du régime permanent:
Moyenne
{stats.mean.toFixed(3)}
Écart-type
{stats.stdDev.toFixed(3)}
Minimum
{stats.min}
Maximum
{stats.max}
{/* Graphique */}
{/* Explications */}
Interprétation:
• Courbe bleue: Nombre de clients dans le système au fil du temps
• Zone orange (gauche): Période de chauffe ({stats.warmupPoints} points) où le système démarre
• Zone bleue (droite): Régime permanent ({stats.steadyStatePoints} points) après {formatTime(stats.warmup, timeUnit)}
• Moyenne en régime permanent: L = {stats.mean.toFixed(3)} clients
• Coefficient de variation: {stats.cv.toFixed(1)}% - Plus il est faible, plus le système est stable
);
}