|
a |
|
b/src/pages/Simulations/Simulations.tsx |
|
|
1 |
import React, { useState, useCallback } from 'react'; |
|
|
2 |
import { |
|
|
3 |
Box, |
|
|
4 |
Typography, |
|
|
5 |
Paper, |
|
|
6 |
Grid, |
|
|
7 |
Card, |
|
|
8 |
CardContent, |
|
|
9 |
LinearProgress, |
|
|
10 |
Button, |
|
|
11 |
Stack, |
|
|
12 |
CircularProgress, |
|
|
13 |
Alert, |
|
|
14 |
} from '@mui/material'; |
|
|
15 |
import { |
|
|
16 |
LineChart, |
|
|
17 |
Line, |
|
|
18 |
XAxis, |
|
|
19 |
YAxis, |
|
|
20 |
CartesianGrid, |
|
|
21 |
Tooltip, |
|
|
22 |
Legend, |
|
|
23 |
ResponsiveContainer, |
|
|
24 |
RadarChart, |
|
|
25 |
PolarGrid, |
|
|
26 |
PolarAngleAxis, |
|
|
27 |
PolarRadiusAxis, |
|
|
28 |
Radar, |
|
|
29 |
} from 'recharts'; |
|
|
30 |
import { usePipeline, useSimulationResults } from '../../hooks/usePipeline'; |
|
|
31 |
import { mockGeneAssemblies, getRandomColor } from '../../data/mockData'; |
|
|
32 |
|
|
|
33 |
const Simulations: React.FC = () => { |
|
|
34 |
const [isSimulating, setIsSimulating] = useState(false); |
|
|
35 |
const [progress, setProgress] = useState(0); |
|
|
36 |
const { startPipeline, isProcessing, error, clearError } = usePipeline(); |
|
|
37 |
const simulationResults = useSimulationResults(); |
|
|
38 |
|
|
|
39 |
const startSimulation = useCallback(async () => { |
|
|
40 |
setIsSimulating(true); |
|
|
41 |
setProgress(0); |
|
|
42 |
|
|
|
43 |
const mockConfig = { |
|
|
44 |
id: Math.random().toString(36).substr(2, 9), |
|
|
45 |
name: 'Quantum Simulation', |
|
|
46 |
environmentalParams: { |
|
|
47 |
temperature: 25, |
|
|
48 |
humidity: 60, |
|
|
49 |
soilConditions: 'Controlled', |
|
|
50 |
}, |
|
|
51 |
duration: 96, |
|
|
52 |
samplingFrequency: 24, |
|
|
53 |
baselineGenotypes: ['WT-Col-0'], |
|
|
54 |
targetTraits: ['stress_tolerance', 'growth_rate'], |
|
|
55 |
}; |
|
|
56 |
|
|
|
57 |
// Use first gene assembly for simulation |
|
|
58 |
await startPipeline({ |
|
|
59 |
experimentConfig: mockConfig, |
|
|
60 |
assembly: mockGeneAssemblies[0], |
|
|
61 |
}); |
|
|
62 |
|
|
|
63 |
const interval = setInterval(() => { |
|
|
64 |
setProgress((prev) => { |
|
|
65 |
if (prev >= 100) { |
|
|
66 |
clearInterval(interval); |
|
|
67 |
setIsSimulating(false); |
|
|
68 |
return 100; |
|
|
69 |
} |
|
|
70 |
return prev + 10; |
|
|
71 |
}); |
|
|
72 |
}, 500); |
|
|
73 |
}, [startPipeline]); |
|
|
74 |
|
|
|
75 |
const renderQuantumMetrics = (result: any) => { |
|
|
76 |
const data = [ |
|
|
77 |
{ name: 'Coherence', value: result.quantumMetrics.coherenceTime }, |
|
|
78 |
{ name: 'Gate Error', value: result.quantumMetrics.gateErrors * 100 }, |
|
|
79 |
{ name: 'Volume', value: result.quantumMetrics.quantumVolume / 10 }, |
|
|
80 |
{ name: 'Circuit', value: result.quantumMetrics.circuitDepth / 2 }, |
|
|
81 |
]; |
|
|
82 |
|
|
|
83 |
return ( |
|
|
84 |
<Box sx={{ height: 300, width: '100%' }}> |
|
|
85 |
<Typography variant="subtitle2" gutterBottom> |
|
|
86 |
Quantum Computing Metrics |
|
|
87 |
</Typography> |
|
|
88 |
<ResponsiveContainer> |
|
|
89 |
<RadarChart data={data}> |
|
|
90 |
<PolarGrid /> |
|
|
91 |
<PolarAngleAxis dataKey="name" /> |
|
|
92 |
<PolarRadiusAxis /> |
|
|
93 |
<Radar |
|
|
94 |
name="Quantum Metrics" |
|
|
95 |
dataKey="value" |
|
|
96 |
stroke="#8884d8" |
|
|
97 |
fill="#8884d8" |
|
|
98 |
fillOpacity={0.6} |
|
|
99 |
/> |
|
|
100 |
</RadarChart> |
|
|
101 |
</ResponsiveContainer> |
|
|
102 |
</Box> |
|
|
103 |
); |
|
|
104 |
}; |
|
|
105 |
|
|
|
106 |
const renderOptimizationResults = (result: any) => { |
|
|
107 |
const data = result.optimizationMetrics.energyLandscape.map((value: number, index: number) => ({ |
|
|
108 |
step: index, |
|
|
109 |
energy: value, |
|
|
110 |
})); |
|
|
111 |
|
|
|
112 |
return ( |
|
|
113 |
<Box sx={{ height: 300, width: '100%' }}> |
|
|
114 |
<Typography variant="subtitle2" gutterBottom> |
|
|
115 |
Energy Landscape Optimization |
|
|
116 |
</Typography> |
|
|
117 |
<ResponsiveContainer> |
|
|
118 |
<LineChart data={data}> |
|
|
119 |
<CartesianGrid strokeDasharray="3 3" /> |
|
|
120 |
<XAxis dataKey="step" /> |
|
|
121 |
<YAxis /> |
|
|
122 |
<Tooltip /> |
|
|
123 |
<Legend /> |
|
|
124 |
<Line |
|
|
125 |
type="monotone" |
|
|
126 |
dataKey="energy" |
|
|
127 |
stroke="#82ca9d" |
|
|
128 |
name="Energy Level" |
|
|
129 |
/> |
|
|
130 |
</LineChart> |
|
|
131 |
</ResponsiveContainer> |
|
|
132 |
</Box> |
|
|
133 |
); |
|
|
134 |
}; |
|
|
135 |
|
|
|
136 |
const renderPredictions = (result: any) => { |
|
|
137 |
return ( |
|
|
138 |
<Box sx={{ height: 300, width: '100%' }}> |
|
|
139 |
<Typography variant="subtitle2" gutterBottom> |
|
|
140 |
Trait Predictions Over Time |
|
|
141 |
</Typography> |
|
|
142 |
<ResponsiveContainer> |
|
|
143 |
<LineChart data={result.results}> |
|
|
144 |
<CartesianGrid strokeDasharray="3 3" /> |
|
|
145 |
<XAxis dataKey="timepoint" /> |
|
|
146 |
<YAxis /> |
|
|
147 |
<Tooltip /> |
|
|
148 |
<Legend /> |
|
|
149 |
{result.results[0].predictions.map((pred: any) => ( |
|
|
150 |
<Line |
|
|
151 |
key={pred.trait} |
|
|
152 |
type="monotone" |
|
|
153 |
data={result.results.map((r: any) => ({ |
|
|
154 |
timepoint: r.timepoint, |
|
|
155 |
value: r.predictions.find((p: any) => p.trait === pred.trait).value, |
|
|
156 |
}))} |
|
|
157 |
dataKey="value" |
|
|
158 |
name={pred.trait} |
|
|
159 |
stroke={getRandomColor()} |
|
|
160 |
/> |
|
|
161 |
))} |
|
|
162 |
</LineChart> |
|
|
163 |
</ResponsiveContainer> |
|
|
164 |
</Box> |
|
|
165 |
); |
|
|
166 |
}; |
|
|
167 |
|
|
|
168 |
return ( |
|
|
169 |
<Box> |
|
|
170 |
<Typography variant="h4" gutterBottom> |
|
|
171 |
Quantum-Enhanced Simulations |
|
|
172 |
</Typography> |
|
|
173 |
|
|
|
174 |
{error && ( |
|
|
175 |
<Alert severity="error" onClose={clearError} sx={{ mb: 2 }}> |
|
|
176 |
{error} |
|
|
177 |
</Alert> |
|
|
178 |
)} |
|
|
179 |
|
|
|
180 |
<Grid container spacing={3}> |
|
|
181 |
<Grid item xs={12} md={4}> |
|
|
182 |
<Paper sx={{ p: 2 }}> |
|
|
183 |
<Typography variant="h6" gutterBottom> |
|
|
184 |
New Simulation |
|
|
185 |
</Typography> |
|
|
186 |
<Button |
|
|
187 |
variant="contained" |
|
|
188 |
fullWidth |
|
|
189 |
onClick={startSimulation} |
|
|
190 |
disabled={isSimulating || isProcessing} |
|
|
191 |
sx={{ mb: 2 }} |
|
|
192 |
> |
|
|
193 |
{isSimulating || isProcessing ? ( |
|
|
194 |
<CircularProgress size={24} /> |
|
|
195 |
) : ( |
|
|
196 |
'Start Simulation' |
|
|
197 |
)} |
|
|
198 |
</Button> |
|
|
199 |
{(isSimulating || isProcessing) && ( |
|
|
200 |
<Box sx={{ width: '100%' }}> |
|
|
201 |
<LinearProgress variant="determinate" value={progress} /> |
|
|
202 |
<Typography variant="body2" color="text.secondary" align="center" sx={{ mt: 1 }}> |
|
|
203 |
{progress}% Complete |
|
|
204 |
</Typography> |
|
|
205 |
</Box> |
|
|
206 |
)} |
|
|
207 |
</Paper> |
|
|
208 |
</Grid> |
|
|
209 |
|
|
|
210 |
<Grid item xs={12} md={8}> |
|
|
211 |
<Stack spacing={2}> |
|
|
212 |
{simulationResults.map((result) => ( |
|
|
213 |
<Card key={result.id}> |
|
|
214 |
<CardContent> |
|
|
215 |
<Grid container spacing={3}> |
|
|
216 |
<Grid item xs={12}> |
|
|
217 |
<Typography variant="h6" gutterBottom> |
|
|
218 |
Simulation Results |
|
|
219 |
</Typography> |
|
|
220 |
<Typography variant="body2" color="text.secondary"> |
|
|
221 |
{new Date(result.timestamp).toLocaleString()} |
|
|
222 |
</Typography> |
|
|
223 |
</Grid> |
|
|
224 |
<Grid item xs={12}> |
|
|
225 |
{renderQuantumMetrics(result)} |
|
|
226 |
</Grid> |
|
|
227 |
<Grid item xs={12} md={6}> |
|
|
228 |
{renderOptimizationResults(result)} |
|
|
229 |
</Grid> |
|
|
230 |
<Grid item xs={12} md={6}> |
|
|
231 |
{renderPredictions(result)} |
|
|
232 |
</Grid> |
|
|
233 |
</Grid> |
|
|
234 |
</CardContent> |
|
|
235 |
</Card> |
|
|
236 |
))} |
|
|
237 |
</Stack> |
|
|
238 |
</Grid> |
|
|
239 |
</Grid> |
|
|
240 |
</Box> |
|
|
241 |
); |
|
|
242 |
}; |
|
|
243 |
|
|
|
244 |
export default Simulations; |