feat: Add comprehensive simulation analysis and performance tracking component with extensive metric collection and utility functions.
This commit is contained in:
@@ -492,7 +492,7 @@ function Analyzer() {
|
|||||||
* Track material addition to an asset
|
* Track material addition to an asset
|
||||||
*/
|
*/
|
||||||
const trackMaterialAddition = useCallback((assetId: string, materialId: string, materialType: string, fromAsset?: string) => {
|
const trackMaterialAddition = useCallback((assetId: string, materialId: string, materialType: string, fromAsset?: string) => {
|
||||||
const timestamp = Date.now();
|
const timestamp = getSimulationTime();
|
||||||
|
|
||||||
if (!materialAdditionsRef.current[assetId]) {
|
if (!materialAdditionsRef.current[assetId]) {
|
||||||
materialAdditionsRef.current[assetId] = [];
|
materialAdditionsRef.current[assetId] = [];
|
||||||
@@ -538,7 +538,7 @@ function Analyzer() {
|
|||||||
* Track material removal from an asset
|
* Track material removal from an asset
|
||||||
*/
|
*/
|
||||||
const trackMaterialRemoval = useCallback((assetId: string, materialId: string, materialType: string, toAsset?: string) => {
|
const trackMaterialRemoval = useCallback((assetId: string, materialId: string, materialType: string, toAsset?: string) => {
|
||||||
const timestamp = Date.now();
|
const timestamp = getSimulationTime();
|
||||||
|
|
||||||
if (!materialRemovalsRef.current[assetId]) {
|
if (!materialRemovalsRef.current[assetId]) {
|
||||||
materialRemovalsRef.current[assetId] = [];
|
materialRemovalsRef.current[assetId] = [];
|
||||||
@@ -583,7 +583,7 @@ function Analyzer() {
|
|||||||
* Track asset state change
|
* Track asset state change
|
||||||
*/
|
*/
|
||||||
const trackStateChange = useCallback((assetId: string, fromState: string, toState: string, context?: { actionName?: string }) => {
|
const trackStateChange = useCallback((assetId: string, fromState: string, toState: string, context?: { actionName?: string }) => {
|
||||||
const timestamp = Date.now();
|
const timestamp = getSimulationTime();
|
||||||
|
|
||||||
// Increment error count if entering error state
|
// Increment error count if entering error state
|
||||||
if (toState === "error") {
|
if (toState === "error") {
|
||||||
@@ -642,7 +642,7 @@ function Analyzer() {
|
|||||||
* Start a new cycle for an asset
|
* Start a new cycle for an asset
|
||||||
*/
|
*/
|
||||||
const startAssetCycle = useCallback((assetId: string, cycleType: string, materialsInvolved: string[] = []) => {
|
const startAssetCycle = useCallback((assetId: string, cycleType: string, materialsInvolved: string[] = []) => {
|
||||||
const timestamp = Date.now();
|
const timestamp = getSimulationTime();
|
||||||
const cycleId = `${assetId}-${timestamp}`;
|
const cycleId = `${assetId}-${timestamp}`;
|
||||||
|
|
||||||
if (!assetCyclesRef.current[assetId]) {
|
if (!assetCyclesRef.current[assetId]) {
|
||||||
@@ -664,7 +664,7 @@ function Analyzer() {
|
|||||||
* Complete a cycle for an asset
|
* Complete a cycle for an asset
|
||||||
*/
|
*/
|
||||||
const completeAssetCycle = useCallback((assetId: string, cycleId: string, success: boolean = true) => {
|
const completeAssetCycle = useCallback((assetId: string, cycleId: string, success: boolean = true) => {
|
||||||
const timestamp = Date.now();
|
const timestamp = getSimulationTime();
|
||||||
const cycles = assetCyclesRef.current[assetId] || [];
|
const cycles = assetCyclesRef.current[assetId] || [];
|
||||||
const cycle = cycles.find((c) => c.cycleId === cycleId);
|
const cycle = cycles.find((c) => c.cycleId === cycleId);
|
||||||
|
|
||||||
@@ -678,7 +678,7 @@ function Analyzer() {
|
|||||||
* Track action completion
|
* Track action completion
|
||||||
*/
|
*/
|
||||||
const trackActionCompletion = useCallback((assetId: string, actionId: string, actionType: string, startTime: number, success: boolean = true) => {
|
const trackActionCompletion = useCallback((assetId: string, actionId: string, actionType: string, startTime: number, success: boolean = true) => {
|
||||||
const endTime = Date.now();
|
const endTime = getSimulationTime();
|
||||||
|
|
||||||
if (!actionCompletionTimesRef.current[assetId]) {
|
if (!actionCompletionTimesRef.current[assetId]) {
|
||||||
actionCompletionTimesRef.current[assetId] = [];
|
actionCompletionTimesRef.current[assetId] = [];
|
||||||
@@ -704,7 +704,7 @@ function Analyzer() {
|
|||||||
*/
|
*/
|
||||||
const updateWIPSnapshot = useCallback(
|
const updateWIPSnapshot = useCallback(
|
||||||
(assetId: string) => {
|
(assetId: string) => {
|
||||||
const timestamp = Date.now();
|
const timestamp = getSimulationTime();
|
||||||
const currentMaterials = getMaterialsByModel(assetId);
|
const currentMaterials = getMaterialsByModel(assetId);
|
||||||
|
|
||||||
if (!wipSnapshotsRef.current[assetId]) {
|
if (!wipSnapshotsRef.current[assetId]) {
|
||||||
@@ -730,7 +730,7 @@ function Analyzer() {
|
|||||||
*/
|
*/
|
||||||
const updateThroughputSnapshot = useCallback(
|
const updateThroughputSnapshot = useCallback(
|
||||||
(assetId: string) => {
|
(assetId: string) => {
|
||||||
const timestamp = Date.now();
|
const timestamp = getSimulationTime();
|
||||||
const timeWindow = 60; // 60 seconds
|
const timeWindow = 60; // 60 seconds
|
||||||
|
|
||||||
if (!throughputSnapshotsRef.current[assetId]) {
|
if (!throughputSnapshotsRef.current[assetId]) {
|
||||||
@@ -742,8 +742,7 @@ function Analyzer() {
|
|||||||
const recentRemovals = removals.filter((r) => timestamp - r.timestamp <= timeWindow * 1000);
|
const recentRemovals = removals.filter((r) => timestamp - r.timestamp <= timeWindow * 1000);
|
||||||
const itemsProcessed = recentRemovals.length;
|
const itemsProcessed = recentRemovals.length;
|
||||||
// Normalize by speed
|
// Normalize by speed
|
||||||
const currentSpeed = Math.max(1, speed);
|
const rate = (itemsProcessed / timeWindow) * 3600; // items per hour
|
||||||
const rate = ((itemsProcessed / timeWindow) * 3600) / currentSpeed; // items per hour
|
|
||||||
|
|
||||||
throughputSnapshotsRef.current[assetId].push({
|
throughputSnapshotsRef.current[assetId].push({
|
||||||
timestamp,
|
timestamp,
|
||||||
@@ -764,7 +763,7 @@ function Analyzer() {
|
|||||||
* Update performance snapshot for an asset
|
* Update performance snapshot for an asset
|
||||||
*/
|
*/
|
||||||
const updatePerformanceSnapshot = useCallback((assetId: string, utilization: number, efficiency: number, quality: number, oee: number) => {
|
const updatePerformanceSnapshot = useCallback((assetId: string, utilization: number, efficiency: number, quality: number, oee: number) => {
|
||||||
const timestamp = Date.now();
|
const timestamp = getSimulationTime();
|
||||||
|
|
||||||
if (!performanceSnapshotsRef.current[assetId]) {
|
if (!performanceSnapshotsRef.current[assetId]) {
|
||||||
performanceSnapshotsRef.current[assetId] = [];
|
performanceSnapshotsRef.current[assetId] = [];
|
||||||
@@ -788,7 +787,7 @@ function Analyzer() {
|
|||||||
* Track bottleneck event
|
* Track bottleneck event
|
||||||
*/
|
*/
|
||||||
const trackBottleneckEvent = useCallback((assetId: string, queueLength: number, utilizationRate: number, waitingMaterials: string[]) => {
|
const trackBottleneckEvent = useCallback((assetId: string, queueLength: number, utilizationRate: number, waitingMaterials: string[]) => {
|
||||||
const timestamp = Date.now();
|
const timestamp = getSimulationTime();
|
||||||
|
|
||||||
if (!bottleneckEventsRef.current[assetId]) {
|
if (!bottleneckEventsRef.current[assetId]) {
|
||||||
bottleneckEventsRef.current[assetId] = [];
|
bottleneckEventsRef.current[assetId] = [];
|
||||||
@@ -840,7 +839,7 @@ function Analyzer() {
|
|||||||
const currentWIP = wipSnapshots.length > 0 ? wipSnapshots[wipSnapshots.length - 1].wipCount : 0;
|
const currentWIP = wipSnapshots.length > 0 ? wipSnapshots[wipSnapshots.length - 1].wipCount : 0;
|
||||||
|
|
||||||
// Calculate throughput rate
|
// Calculate throughput rate
|
||||||
const now = Date.now();
|
const now = getSimulationTime();
|
||||||
const oneHourAgo = now - 3600000;
|
const oneHourAgo = now - 3600000;
|
||||||
const recentRemovals = removals.filter((r) => r.timestamp >= oneHourAgo);
|
const recentRemovals = removals.filter((r) => r.timestamp >= oneHourAgo);
|
||||||
const throughputRate = recentRemovals.length; // items per hour
|
const throughputRate = recentRemovals.length; // items per hour
|
||||||
@@ -907,7 +906,7 @@ function Analyzer() {
|
|||||||
const energyMetrics = calculateEnergyMetrics("conveyor", conveyor.activeTime || 0);
|
const energyMetrics = calculateEnergyMetrics("conveyor", conveyor.activeTime || 0);
|
||||||
|
|
||||||
// Update historical data
|
// Update historical data
|
||||||
const timestamp = new Date().toISOString();
|
const timestamp = getSimulationTime();
|
||||||
const newEntry = {
|
const newEntry = {
|
||||||
timestamp,
|
timestamp,
|
||||||
isActive: !conveyor.isPaused,
|
isActive: !conveyor.isPaused,
|
||||||
@@ -924,7 +923,7 @@ function Analyzer() {
|
|||||||
// Calculate queue if applicable
|
// Calculate queue if applicable
|
||||||
const queueLength = materialFlow.wip;
|
const queueLength = materialFlow.wip;
|
||||||
const currentQueueData = queueLengthsRef.current[conveyor.modelUuid] || [];
|
const currentQueueData = queueLengthsRef.current[conveyor.modelUuid] || [];
|
||||||
queueLengthsRef.current[conveyor.modelUuid] = [...currentQueueData, { timestamp: Date.now(), length: queueLength }].slice(-100);
|
queueLengthsRef.current[conveyor.modelUuid] = [...currentQueueData, { timestamp: getSimulationTime(), length: queueLength }].slice(-100);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
assetId: conveyor.modelUuid,
|
assetId: conveyor.modelUuid,
|
||||||
@@ -1051,7 +1050,7 @@ function Analyzer() {
|
|||||||
const energyMetrics = calculateEnergyMetrics("vehicle", vehicle.activeTime || 0, actualDistance);
|
const energyMetrics = calculateEnergyMetrics("vehicle", vehicle.activeTime || 0, actualDistance);
|
||||||
|
|
||||||
// Update historical data
|
// Update historical data
|
||||||
const timestamp = new Date().toISOString();
|
const timestamp = getSimulationTime();
|
||||||
const currentData = historicalDataRef.current[vehicle.modelUuid] || [];
|
const currentData = historicalDataRef.current[vehicle.modelUuid] || [];
|
||||||
historicalDataRef.current[vehicle.modelUuid] = [
|
historicalDataRef.current[vehicle.modelUuid] = [
|
||||||
...currentData,
|
...currentData,
|
||||||
@@ -1214,7 +1213,7 @@ function Analyzer() {
|
|||||||
|
|
||||||
// Update historical data
|
// Update historical data
|
||||||
|
|
||||||
const timestamp = new Date().toISOString();
|
const timestamp = getSimulationTime();
|
||||||
const newEntry = {
|
const newEntry = {
|
||||||
timestamp,
|
timestamp,
|
||||||
cycleTime: actualCycleTime,
|
cycleTime: actualCycleTime,
|
||||||
@@ -1339,7 +1338,7 @@ function Analyzer() {
|
|||||||
const scrapRate = defectRate * 0.7; // Assume 70% are scrapped
|
const scrapRate = defectRate * 0.7; // Assume 70% are scrapped
|
||||||
|
|
||||||
// Update historical data
|
// Update historical data
|
||||||
const timestamp = new Date().toISOString();
|
const timestamp = getSimulationTime();
|
||||||
const currentData = historicalDataRef.current[machine.modelUuid] || [];
|
const currentData = historicalDataRef.current[machine.modelUuid] || [];
|
||||||
historicalDataRef.current[machine.modelUuid] = [
|
historicalDataRef.current[machine.modelUuid] = [
|
||||||
...currentData,
|
...currentData,
|
||||||
@@ -1452,7 +1451,7 @@ function Analyzer() {
|
|||||||
const turnoverRate = timeMetrics.totalTime > 0 ? (totalOps / timeMetrics.totalTime) * 3600 : 0;
|
const turnoverRate = timeMetrics.totalTime > 0 ? (totalOps / timeMetrics.totalTime) * 3600 : 0;
|
||||||
|
|
||||||
// Occupancy trends
|
// Occupancy trends
|
||||||
const timestamp = new Date().toISOString();
|
const timestamp = getSimulationTime();
|
||||||
const currentData = historicalDataRef.current[storage.modelUuid] || [];
|
const currentData = historicalDataRef.current[storage.modelUuid] || [];
|
||||||
historicalDataRef.current[storage.modelUuid] = [
|
historicalDataRef.current[storage.modelUuid] = [
|
||||||
...currentData,
|
...currentData,
|
||||||
@@ -1472,8 +1471,8 @@ function Analyzer() {
|
|||||||
const averageOccupancy = occupancyData.length > 0 ? occupancyData.reduce((sum, d) => sum + d.utilizationRate, 0) / occupancyData.length : utilizationRate;
|
const averageOccupancy = occupancyData.length > 0 ? occupancyData.reduce((sum, d) => sum + d.utilizationRate, 0) / occupancyData.length : utilizationRate;
|
||||||
|
|
||||||
// Calculate occupancy trends for the last hour
|
// Calculate occupancy trends for the last hour
|
||||||
const hourAgo = Date.now() - 3600000;
|
const hourAgo = getSimulationTime() - 3600000;
|
||||||
const recentOccupancy = occupancyData.filter((d) => new Date(d.timestamp).getTime() > hourAgo).map((d) => d.utilizationRate);
|
const recentOccupancy = occupancyData.filter((d) => d.timestamp > hourAgo).map((d) => d.utilizationRate);
|
||||||
const occupancyTrend = recentOccupancy.length > 1 ? ((recentOccupancy[recentOccupancy.length - 1] - recentOccupancy[0]) / recentOccupancy[0]) * 100 : 0;
|
const occupancyTrend = recentOccupancy.length > 1 ? ((recentOccupancy[recentOccupancy.length - 1] - recentOccupancy[0]) / recentOccupancy[0]) * 100 : 0;
|
||||||
|
|
||||||
const costMetrics = calculateCostMetrics(storage.modelUuid, "storage", storage.activeTime || 0, totalOps);
|
const costMetrics = calculateCostMetrics(storage.modelUuid, "storage", storage.activeTime || 0, totalOps);
|
||||||
@@ -1614,7 +1613,7 @@ function Analyzer() {
|
|||||||
const energyMetrics = calculateEnergyMetrics("human", human.activeTime || 0);
|
const energyMetrics = calculateEnergyMetrics("human", human.activeTime || 0);
|
||||||
|
|
||||||
// Update historical data
|
// Update historical data
|
||||||
const timestamp = new Date().toISOString();
|
const timestamp = getSimulationTime();
|
||||||
const newEntry = {
|
const newEntry = {
|
||||||
timestamp,
|
timestamp,
|
||||||
actionType: human.currentAction?.actionName || "unknown",
|
actionType: human.currentAction?.actionName || "unknown",
|
||||||
@@ -1751,7 +1750,7 @@ function Analyzer() {
|
|||||||
const movementEfficiency = liftSuccessRate * 0.8 + positioningAccuracy * 0.2; // Weighted average
|
const movementEfficiency = liftSuccessRate * 0.8 + positioningAccuracy * 0.2; // Weighted average
|
||||||
|
|
||||||
// Update historical data
|
// Update historical data
|
||||||
const timestamp = new Date().toISOString();
|
const timestamp = getSimulationTime();
|
||||||
const newEntry = {
|
const newEntry = {
|
||||||
timestamp,
|
timestamp,
|
||||||
cycleTime: actualCycleTime,
|
cycleTime: actualCycleTime,
|
||||||
|
|||||||
Reference in New Issue
Block a user