ResultsDisplay.tsx 14,7 ko
Newer Older
 * Results display component with Material-UI - shows simulation results, analytical results, and comparison.
import { useState } from 'react';
import {
  Box,
  Tabs,
  Tab,
  Typography,
  CircularProgress,
  Alert,
  AlertTitle,
  Stack,
} from '@mui/material';
import {
  Assessment as AssessmentIcon,
  BarChart as BarChartIcon,
  CompareArrows as CompareArrowsIcon,
} from '@mui/icons-material';
import { useSimulationStore } from '../../store/simulationStore';
import MetricsCard from './MetricsCard';
import ComparisonTable from './ComparisonTable';
import NetworkDiagram from '../visualization/NetworkDiagram';
import UtilizationChart from '../visualization/UtilizationChart';
import MetricsComparisonChart from '../visualization/MetricsComparisonChart';
import TimeSeriesChart from '../visualization/TimeSeriesChart';
import ProcessingTimeHistogram from '../visualization/ProcessingTimeHistogram';
import SteadyStateChart from '../visualization/SteadyStateChart';
Hamadou Ba's avatar
Hamadou Ba a validé
import QueueEvolutionChart from '../visualization/QueueEvolutionChart';

export default function ResultsDisplay() {
  const {
    simulationResults,
    analyticalResults,
    comparisonResults,
    isLoading,
  const [activeTab, setActiveTab] = useState<number>(0);
      <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', py: 8 }}>
        <CircularProgress size={50} sx={{ mb: 2 }} />
        <Typography variant="body1" color="text.secondary">
          Calcul en cours...
        </Typography>
      </Box>
    );
  }

  if (!simulationResults && !analyticalResults) {
    return (
      <Box sx={{ textAlign: 'center', py: 8 }}>
        <AssessmentIcon sx={{ fontSize: 64, color: 'text.disabled', mb: 2 }} />
        <Typography variant="h6" gutterBottom>
          Aucun résultat disponible
        </Typography>
        <Typography variant="body2" color="text.secondary">
          Lancez une simulation pour voir les résultats
      <Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 3 }}>
        <Tabs value={activeTab} onChange={(_, newValue) => setActiveTab(newValue)}>
          <Tab icon={<AssessmentIcon />} iconPosition="start" label="Métriques" />
          <Tab icon={<BarChartIcon />} iconPosition="start" label="Visualisations" />
          <Tab icon={<CompareArrowsIcon />} iconPosition="start" label="Comparaison" />
        </Tabs>
      </Box>
      {/* Stability indicator */}
      {(simulationResults || analyticalResults) && (
            (simulationResults?.is_stable ?? analyticalResults?.is_stable)
              ? 'success'
              : 'error'
          }
          sx={{ mb: 3 }}
          <AlertTitle>
            {(simulationResults?.is_stable ?? analyticalResults?.is_stable)
              ? 'Système stable'
              : 'Système instable'}
          </AlertTitle>
          {!simulationResults?.is_stable && simulationResults?.stability_notes && (
            <Typography variant="body2">
              {simulationResults.stability_notes}
            </Typography>
          )}
          {!analyticalResults?.is_stable && analyticalResults?.instability_reason && (
            <Typography variant="body2">
              {analyticalResults.instability_reason}
            </Typography>
          )}
        </Alert>
      {/* Metrics Tab */}
      {activeTab === 0 && (
        <Stack spacing={4}>
          {/* Simulation results */}
          {simulationResults && (
            <Box>
              <Typography variant="h6" gutterBottom sx={{ fontWeight: 600 }}>
                Résultats de simulation
              </Typography>
              <Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' }, gap: 2, mb: 3 }}>
                  title="Total requêtes"
                  value={simulationResults.total_requests_completed}
                  unit="requêtes"
                  title="Temps moyen dans le système"
                  value={simulationResults.average_system_time}
                  unit={timeUnit}
                  decimals={timeUnit === 's' ? 3 : 2}
              {/* Coordinator stats */}
              <Box sx={{ mb: 3 }}>
                <Typography variant="subtitle2" color="text.secondary" gutterBottom sx={{ fontWeight: 600 }}>
                  Coordinateur
                </Typography>
                <Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr 1fr', md: 'repeat(4, 1fr)' }, gap: 1.5 }}>
                  <MetricsCard
                    title="Utilisation (ρ)"
                    value={simulationResults.coordinator_stats.utilization}
                    decimals={4}
                    compact
                  />
                  <MetricsCard
                    title="Temps d'attente"
                    value={simulationResults.coordinator_stats.average_wait_time}
                    unit={timeUnit}
                    decimals={timeUnit === 's' ? 3 : 2}
                    compact
                  />
                  <MetricsCard
                    title="Temps de service"
                    value={simulationResults.coordinator_stats.average_service_time}
                    unit={timeUnit}
                    decimals={timeUnit === 's' ? 3 : 2}
                    compact
                  />
                  <MetricsCard
                    title="Temps système"
                    value={simulationResults.coordinator_stats.average_system_time}
                    unit={timeUnit}
                    decimals={timeUnit === 's' ? 3 : 2}
              {/* Server stats */}
              {Object.entries(simulationResults.server_stats).map(([serverId, stats]) => (
                <Box key={serverId} sx={{ mb: 3 }}>
                  <Typography variant="subtitle2" color="text.secondary" gutterBottom sx={{ fontWeight: 600 }}>
                    {serverId.replace('_', ' ').charAt(0).toUpperCase() +
                      serverId.replace('_', ' ').slice(1)}
                  </Typography>
                  <Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr 1fr', md: 'repeat(4, 1fr)' }, gap: 1.5 }}>
                    <MetricsCard
                      title="Utilisation (ρ)"
                      value={stats.utilization}
                      decimals={4}
                      compact
                    />
                    <MetricsCard
                      title="Temps d'attente"
                      value={stats.average_wait_time}
                      unit={timeUnit}
                      decimals={timeUnit === 's' ? 3 : 2}
                      compact
                    />
                    <MetricsCard
                      title="Temps de service"
                      value={stats.average_service_time}
                      unit={timeUnit}
                      decimals={timeUnit === 's' ? 3 : 2}
                      compact
                    />
                    <MetricsCard
                      title="Temps système"
                      value={stats.average_system_time}
                      unit={timeUnit}
                      decimals={timeUnit === 's' ? 3 : 2}
          {/* Analytical results */}
          {analyticalResults && (
            <Box>
              <Typography variant="h6" gutterBottom sx={{ fontWeight: 600 }}>
                Résultats analytiques (Théorème de Jackson)
              </Typography>
              <Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' }, gap: 2, mb: 3 }}>
                  title="Nombre moyen de clients (L)"
                  value={analyticalResults.total_average_customers}
                  title="Temps moyen (W)"
                  value={analyticalResults.total_average_time}
                  decimals={timeUnit === 's' ? 3 : 2}
                  unit={timeUnit}
              </Box>

              {/* Coordinator analytics */}
              <Box sx={{ mb: 3 }}>
                <Typography variant="subtitle2" color="text.secondary" gutterBottom sx={{ fontWeight: 600 }}>
                  Coordinateur
                </Typography>
                <Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr 1fr', md: 'repeat(4, 1fr)' }, gap: 1.5 }}>
                  <MetricsCard
                    title="Utilisation (ρ)"
                    value={analyticalResults.coordinator.utilization}
                    decimals={4}
                    compact
                  />
                  <MetricsCard
                    title="L"
                    value={analyticalResults.coordinator.average_customers ?? 0}
                    decimals={4}
                    compact
                  />
                  <MetricsCard
                    title="W"
                    value={analyticalResults.coordinator.average_time ?? 0}
                    unit={timeUnit}
                    decimals={timeUnit === 's' ? 3 : 2}
                    compact
                  />
                  <MetricsCard
                    title="Wq"
                    value={analyticalResults.coordinator.average_wait_time ?? 0}
                    unit={timeUnit}
                    decimals={timeUnit === 's' ? 3 : 2}
                    compact
                  />
                </Box>
              </Box>

              {/* Server analytics */}
              {Object.entries(analyticalResults.servers).map(([serverId, analytics]) => (
                <Box key={serverId} sx={{ mb: 3 }}>
                  <Typography variant="subtitle2" color="text.secondary" gutterBottom sx={{ fontWeight: 600 }}>
                    {serverId.replace('_', ' ').charAt(0).toUpperCase() +
                      serverId.replace('_', ' ').slice(1)}
                  </Typography>
                  <Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr 1fr', md: 'repeat(4, 1fr)' }, gap: 1.5 }}>
                    <MetricsCard
                      title="Utilisation (ρ)"
                      value={analytics.utilization}
                      decimals={4}
                      compact
                    />
                    <MetricsCard
                      title="L"
                      value={analytics.average_customers ?? 0}
                      decimals={4}
                      compact
                    />
                    <MetricsCard
                      title="W"
                      value={analytics.average_time ?? 0}
                      unit={timeUnit}
                      decimals={timeUnit === 's' ? 3 : 2}
                      compact
                    />
                    <MetricsCard
                      title="Wq"
                      value={analytics.average_wait_time ?? 0}
                      unit={timeUnit}
                      decimals={timeUnit === 's' ? 3 : 2}
      )}

      {/* Visualizations Tab */}
      {activeTab === 1 && (
        <Stack spacing={4}>
Hamadou Ba's avatar
Hamadou Ba a validé
          {/* Queue evolution chart - N(t) par file */}
          {simulationResults?.time_series && (
            <Box>
              <QueueEvolutionChart />
            </Box>
          )}

          {/* Steady state detection chart */}
          {simulationResults?.time_series && config && (
            <Box>
              <SteadyStateChart warmupTime={config.warmup_time} />
            </Box>
          )}

          {/* Time series chart */}
          {simulationResults?.time_series && (
            <Box>
              <TimeSeriesChart timeSeriesData={simulationResults.time_series} />
            </Box>
          )}

          {/* Processing time histogram */}
          {simulationResults?.processing_time_histogram && (
            <Box>
              <ProcessingTimeHistogram histogramData={simulationResults.processing_time_histogram} />
            </Box>
          )}

          {/* Network diagram */}
          {config && (
              <NetworkDiagram config={config} />
          )}

          {/* Utilization chart */}
          {(simulationResults || analyticalResults) && (
              <UtilizationChart
                simulationResults={simulationResults}
                analyticalResults={analyticalResults}
              />
          )}

          {/* Metrics charts */}
          <Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', lg: '1fr 1fr' }, gap: 3 }}>
            {analyticalResults && (
              <MetricsComparisonChart
                simulationResults={simulationResults}
                analyticalResults={analyticalResults}
                metric="L"
              />
            )}
            {(simulationResults || analyticalResults) && (
              <MetricsComparisonChart
                simulationResults={simulationResults}
                analyticalResults={analyticalResults}
                metric="W"
              />
            )}
      )}

      {/* Comparison Tab */}
      {activeTab === 2 && (
        <Stack spacing={4}>
          {comparisonResults ? (
            <>
              <Box>
                <Typography variant="h6" gutterBottom sx={{ fontWeight: 600 }}>
                  Comparaison Analytique vs Simulation
                <ComparisonTable comparison={comparisonResults} />

              {/* Visualization of comparison */}
              <Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', lg: '1fr 1fr' }, gap: 3 }}>
                <UtilizationChart
                  simulationResults={simulationResults}
                  analyticalResults={analyticalResults}
                />
                <MetricsComparisonChart
                  simulationResults={simulationResults}
                  analyticalResults={analyticalResults}
                  metric="W"
                />
            <Box sx={{ textAlign: 'center', py: 8 }}>
              <Typography variant="body1" color="text.secondary">
                Lancez une simulation pour voir la comparaison avec les résultats analytiques