Implement machine count and uptime state management; refactor throughput calculations and logging in simulation components

This commit is contained in:
Gomathi 2025-05-09 11:27:08 +05:30
parent 6b7bd18e0c
commit cf66fbf20d
4 changed files with 299 additions and 23 deletions

View File

@ -1,3 +1,5 @@
import { useEffect, useState } from "react";
import { useMachineCount, useMachineUptime } from "../../../store/store";
import {
ProductionCapacityIcon,
ThroughputSummaryIcon,
@ -16,7 +18,15 @@ const ProductionCapacity = ({
const partialFillPercent =
((progressPercent / 100) * totalBars - barsToFill) * 100;
const isLoading = true;
const [isLoading, setIsLoading] = useState(false);
const { machineCount, setMachineCount } = useMachineCount()
const { machineActiveTime, setMachineActiveTime } = useMachineUptime()
useEffect(() => {
setIsLoading(true);
machineUtilization = machineActiveTime
console.log('machineActiveTime: ', machineActiveTime);
}, [machineActiveTime])
return (
<div className="throughtputSummary-container analysis-card">
<div className="throughtputSummary-wrapper analysis-card-wrapper">
@ -62,7 +72,7 @@ const ProductionCapacity = ({
</div>
<div className="metric">
<span className="label">Machine Utilization</span>
<span className="value">{machineUtilization}</span>
<span className="value">{machineActiveTime}</span>
</div>
</div>
</>

View File

@ -1,31 +1,232 @@
import React, { useEffect } from 'react'
// import React, { useEffect, useState } from 'react';
// import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
// import { useProductStore } from '../../../../store/simulation/useProductStore';
// import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences';
// import { useArmBotStore } from '../../../../store/simulation/useArmBotStore';
// import { useMachineCount, useMachineUptime, useMaterialCycle } from '../../../../store/store';
// import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
// import { useMachineStore } from '../../../../store/simulation/useMachineStore';
// import { useConveyorStore } from '../../../../store/simulation/useConveyorStore';
// import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore';
// import { useMaterialStore } from '../../../../store/simulation/useMaterialStore';
// export default function ThroughPut() {
// const { selectedProduct } = useSelectedProduct();
// const { products, getProductById } = useProductStore();
// const { armBots } = useArmBotStore();
// const { vehicles } = useVehicleStore();
// const { machines } = useMachineStore();
// const { conveyors } = useConveyorStore();
// const { storageUnits } = useStorageUnitStore();
// const { materials } = useMaterialStore();
// const { machineCount, setMachineCount } = useMachineCount();
// const { setMachineActiveTime } = useMachineUptime();
// const { materialCycleTime, setMaterialCycleTime } = useMaterialCycle();
// const [totalActiveTime, setTotalActiveTime] = useState(0);
// // 1. Setting static active times and counting machines
// useEffect(() => {
// const productData = getProductById(selectedProduct.productId);
// if (productData) {
// const productSequenceData = determineExecutionMachineSequences([productData]);
// if (productSequenceData?.length > 0) {
// let totalItems = 0;
// productSequenceData.forEach((sequence) => {
// totalItems += sequence.length;
// sequence.forEach((item) => {
// if (item.type === "roboticArm") {
// armBots.filter(arm => arm.modelUuid === item.modelUuid)
// .forEach(arm => {
// if (arm.activeTime >= 0) {
// console.log('armBot activeTime:', arm.activeTime);
// }
// });
// } else if (item.type === "vehicle") {
// vehicles.filter(vehicle => vehicle.modelUuid === item.modelUuid)
// .forEach(vehicle => {
// if (vehicle.activeTime >= 0) {
// vehicle.activeTime = 10; // static
// }
// });
// } else if (item.type === "machine") {
// machines.filter(machine => machine.modelUuid === item.modelUuid)
// .forEach(machine => {
// if (machine.activeTime >= 0) {
// machine.activeTime = 12; // static
// }
// });
// } else if (item.type === "transfer") {
// conveyors.filter(conveyor => conveyor.modelUuid === item.modelUuid)
// .forEach(conveyor => {
// if (conveyor.activeTime >= 0) {
// conveyor.activeTime = 5; // static
// }
// });
// } else if (item.type === "storageUnit") {
// storageUnits.filter(storage => storage.modelUuid === item.modelUuid)
// .forEach(storage => {
// if (storage.activeTime >= 0) {
// storage.activeTime = 8; // static
// }
// });
// }
// });
// });
// setMachineCount(totalItems);
// }
// }
// }, [products, selectedProduct, armBots, vehicles, machines, conveyors, storageUnits, getProductById, setMachineCount]);
// // 2. Set material cycle time (static also)
// useEffect(() => {
// materials.forEach((material) => {
// material.startTime = 50;
// material.endTime = 100;
// const totalCycleTime = material.endTime - material.startTime;
// setMaterialCycleTime(totalCycleTime);
// });
// }, [materials, setMaterialCycleTime]);
// // 3. Sum of all activeTimes after static values are set
// useEffect(() => {
// let sum = 0;
// armBots.forEach(arm => { if (arm.activeTime > 0) sum += arm.activeTime; });
// vehicles.forEach(vehicle => { if (vehicle.activeTime > 0) sum += vehicle.activeTime; });
// machines.forEach(machine => { if (machine.activeTime > 0) sum += machine.activeTime; });
// conveyors.forEach(conveyor => { if (conveyor.activeTime > 0) sum += conveyor.activeTime; });
// storageUnits.forEach(storage => { if (storage.activeTime > 0) sum += storage.activeTime; });
// setTotalActiveTime(sum);
// setMachineActiveTime(sum);
// }, [armBots, vehicles, machines, conveyors, storageUnits, setMachineActiveTime]);
// // 4. Calculate throughput when activeTime and materialCycleTime are ready
// useEffect(() => {
// if (totalActiveTime > 0 && materialCycleTime > 0) {
// const avgProcessTime = (totalActiveTime / materialCycleTime) * 100;
// console.log('Throughput (%):', avgProcessTime.toFixed(2));
// }
// }, [totalActiveTime, materialCycleTime]);
// return (
// <>
// </>
// );
// }
import React, { useEffect, useState } from 'react';
import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
import { useProductStore } from '../../../../store/simulation/useProductStore';
import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences';
import { useArmBotStore } from '../../../../store/simulation/useArmBotStore';
import { useMachineCount, useMachineUptime, useMaterialCycle } from '../../../../store/store';
import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
import { useMachineStore } from '../../../../store/simulation/useMachineStore';
import { useConveyorStore } from '../../../../store/simulation/useConveyorStore';
import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore';
import { useMaterialStore } from '../../../../store/simulation/useMaterialStore';
export default function ThroughPut() {
const { selectedProduct } = useSelectedProduct();
const { products,getProductById } = useProductStore()
const { products, getProductById } = useProductStore();
const { armBots } = useArmBotStore();
const { vehicles } = useVehicleStore();
const { machines } = useMachineStore();
const { conveyors } = useConveyorStore();
const { storageUnits } = useStorageUnitStore();
const { materials } = useMaterialStore();
const { setMachineCount } = useMachineCount();
const { setMachineActiveTime } = useMachineUptime();
const { setMaterialCycleTime } = useMaterialCycle();
const [totalActiveTime, setTotalActiveTime] = useState(0);
const [throughputData, setThroughputData] = useState(0); // <=== ADD THIS
// Setting machine count
useEffect(() => {
let productData = getProductById(selectedProduct.productId)
const productData = getProductById(selectedProduct.productId);
if (productData) {
let productSequenceData = determineExecutionMachineSequences([productData])
console.log('productSequenceData: ', productSequenceData);
const productSequenceData = determineExecutionMachineSequences([productData]);
if (productSequenceData?.length > 0) {
let totalItems = 0; // 👈 initialize total count
productSequenceData.map((sequence, index) => {
let totalItems = 0;
productSequenceData.forEach((sequence) => {
totalItems += sequence.length;
// sequence.map((item, idx) => {});
});
console.log(`Total items across all sequences: ${totalItems}`); // 👈 FINAL TOTAL ✅
} else {
console.log('No productSequenceData found!');
setMachineCount(totalItems);
}
}
}, [products])
}, [products, selectedProduct, getProductById, setMachineCount]);
// Setting material cycle time
useEffect(() => {
materials.forEach(() => {
const staticStartTime = 50;
const staticEndTime = 100;
const totalCycleTime = staticEndTime - staticStartTime;
setMaterialCycleTime(totalCycleTime);
});
}, [materials, setMaterialCycleTime]);
// Calculate Sum, Machine Uptime and Throughput
useEffect(() => {
let sum = 0;
console.log('armBots: ', armBots);
armBots.forEach(arm => {
console.log('arm.activeTime: ', arm.activeTime);
if (arm.activeTime > 0) sum += arm.activeTime;
});
vehicles.forEach(vehicle => {
if (vehicle.activeTime > 0) sum += 10; // static
});
machines.forEach(machine => {
if (machine.activeTime > 0) sum += 12; // static
});
conveyors.forEach(conveyor => {
if (conveyor.activeTime > 0) sum += 5; // static
});
storageUnits.forEach(storage => {
if (storage.activeTime > 0) sum += 8; // static
});
console.log('sum: ', sum);
const avgProcessTime = 100 - 50; // static 50
const machineUptime = (sum / avgProcessTime) * 100;
console.log('machineUptime: ', machineUptime.toFixed(2));
const machineCount = 3; // static
const throughput = (3600 / avgProcessTime) * machineCount * (machineUptime / 100); // **IMPORTANT divide by 100 for %**
console.log('throughPutData: ', throughput.toFixed(2));
setTotalActiveTime(sum);
setMachineActiveTime(sum);
setThroughputData(throughput); // Save it properly here
}, [armBots, vehicles, machines, conveyors, storageUnits, setMachineActiveTime]);
// Just display throughput when ready
useEffect(() => {
console.log('throughputData: ', throughputData);
if (throughputData > 0) {
console.log('Final Throughput (units/hour): ', throughputData.toFixed(2));
}
}, [throughputData]);
return (
<>
</>
)
);
}

View File

@ -27,7 +27,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
const isIdleRef = useRef<boolean>(false);
let startTime: number;
const { setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore();
const { setArmBotActive, setArmBotState, removeCurrentAction,incrementActiveTime,incrementIdleTime } = useArmBotStore();
const { setIsVisible } = useMaterialStore();
const { selectedProduct } = useSelectedProduct();
const { getActionByUuid } = useProductStore();
@ -161,8 +161,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
useEffect(() => {
if (!isPlaying) return;
const intervalMs = 1000 / isSpeedRef.current;
console.log('intervalMs: ', intervalMs);
const intervalMs = 1000
if (!armBot.isActive && armBot.state == "idle" && (currentPhase == "rest" || currentPhase == "init") && !isIdleRef.current) {
isIdleRef.current = true
@ -173,7 +172,8 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
clearInterval(activeTimerId.current);
activeTimerId.current = null;
}
console.log(`✅ Active Cycle completed in ${activeSecondsElapsed.current} seconds`);
incrementActiveTime(armBot.modelUuid, activeSecondsElapsed.current)
// console.log(`✅ Active Cycle completed in ${activeSecondsElapsed.current} seconds`);
// 🚨 2. Reset active timer seconds after logging
activeSecondsElapsed.current = 0;
@ -188,7 +188,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
idleTimerId.current = setInterval(() => {
if (!isPausedRef.current) {
idleSecondsElapsed.current += 1;
console.log(`🕒 Idle Timer: ${idleSecondsElapsed.current} seconds`);
// console.log(`🕒 Idle Timer: ${idleSecondsElapsed.current} seconds`);
}
}, intervalMs);
} else if (armBot.isActive && armBot.state != "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) {
@ -200,7 +200,8 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
clearInterval(idleTimerId.current);
idleTimerId.current = null;
}
console.log(`🕒 Idle Cycle completed in: ${idleSecondsElapsed.current} seconds`);
incrementIdleTime(armBot.modelUuid, idleSecondsElapsed.current)
// console.log(`🕒 Idle Cycle completed in: ${idleSecondsElapsed.current} seconds`);
idleSecondsElapsed.current = 0;
// 🚨 Start Active Timer
@ -211,7 +212,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
activeTimerId.current = setInterval(() => {
if (!isPausedRef.current) {
activeSecondsElapsed.current += 1
console.log(`🕒 Active Timer: ${activeSecondsElapsed.current} seconds`);
// console.log(`🕒 Active Timer: ${activeSecondsElapsed.current} seconds`);
}
}, intervalMs);
}
@ -287,6 +288,56 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
// }, [armBot, currentPhase, isPlaying, isIdleRef.current, isPausedRef.current]);
// useEffect(() => {
// if (!isPlaying) return;
// let frameId: number | null = null;
// let lastTime = performance.now();
// const tick = (currentTime: number) => {
// const delta = currentTime - lastTime;
// lastTime = currentTime;
// const secondsToAdd = delta / 1000; // ⚡REAL time passed (NO speed multiplication)
// if (!isPausedRef.current) {
// // Update Timer
// if (isIdleRef.current) {
// idleSecondsElapsed.current += secondsToAdd;
// console.log(`🕒 Idle Timer: ${idleSecondsElapsed.current.toFixed(2)} seconds (Speed: ${isSpeedRef.current}x)`);
// } else {
// activeSecondsElapsed.current += secondsToAdd;
// console.log(`🕒 Active Timer: ${activeSecondsElapsed.current.toFixed(2)} seconds (Speed: ${isSpeedRef.current}x)`);
// }
// }
// frameId = requestAnimationFrame(tick);
// };
// // Detect mode switch
// if (!armBot.isActive && armBot.state === "idle" && (currentPhase === "rest" || currentPhase === "init") && !isIdleRef.current) {
// isIdleRef.current = true;
// console.log(`✅ Active Cycle completed in ${activeSecondsElapsed.current.toFixed(2)} seconds`);
// activeSecondsElapsed.current = 0;
// idleSecondsElapsed.current = 0;
// } else if (armBot.isActive && armBot.state !== "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) {
// isIdleRef.current = false;
// console.log(`🕒 Idle Cycle completed in: ${idleSecondsElapsed.current.toFixed(2)} seconds`);
// idleSecondsElapsed.current = 0;
// activeSecondsElapsed.current = 0;
// }
// frameId = requestAnimationFrame(tick);
// return () => {
// if (frameId !== null) {
// cancelAnimationFrame(frameId);
// }
// };
// }, [armBot, currentPhase, isPlaying]);
useEffect(() => {
const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid);
if (targetMesh) {

View File

@ -430,3 +430,17 @@ export const useZoneAssetId = create<ZoneAssetState>((set) => ({
zoneAssetId: null,
setZoneAssetId: (asset) => set({ zoneAssetId: asset }),
}));
export const useMachineCount = create<any>((set: any) => ({
machineCount: 0,
setMachineCount: (x: any) => set({ activeLayer: x }),
}));
export const useMachineUptime = create<any>((set: any) => ({
machineActiveTime: 0,
setMachineActiveTime: (x: any) => set({ activeLayer: x }),
}));
export const useMaterialCycle = create<any>((set: any) => ({
materialCycleTime: 0,
setMaterialCycleTime: (x: any) => set({ activeLayer: x }),
}));