From cf66fbf20d4032de7d70781dc77bbc13bc5a06d7 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Fri, 9 May 2025 11:27:08 +0530 Subject: [PATCH] Implement machine count and uptime state management; refactor throughput calculations and logging in simulation components --- .../ui/analysis/ThroughputSummary.tsx | 14 +- .../analysis/throughPut/throughPut.tsx | 229 ++++++++++++++++-- .../armInstance/roboticArmInstance.tsx | 65 ++++- app/src/store/store.ts | 14 ++ 4 files changed, 299 insertions(+), 23 deletions(-) diff --git a/app/src/components/ui/analysis/ThroughputSummary.tsx b/app/src/components/ui/analysis/ThroughputSummary.tsx index 57eabd1..61e1282 100644 --- a/app/src/components/ui/analysis/ThroughputSummary.tsx +++ b/app/src/components/ui/analysis/ThroughputSummary.tsx @@ -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 (
@@ -62,7 +72,7 @@ const ProductionCapacity = ({
Machine Utilization - {machineUtilization} + {machineActiveTime}
diff --git a/app/src/modules/simulation/analysis/throughPut/throughPut.tsx b/app/src/modules/simulation/analysis/throughPut/throughPut.tsx index 71e82f8..385fb0b 100644 --- a/app/src/modules/simulation/analysis/throughPut/throughPut.tsx +++ b/app/src/modules/simulation/analysis/throughPut/throughPut.tsx @@ -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 ( <> - ) -} \ No newline at end of file + ); +} + diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 2107776..e2658f4 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -27,7 +27,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { const isIdleRef = useRef(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) { diff --git a/app/src/store/store.ts b/app/src/store/store.ts index b16e1ff..e0157ff 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -430,3 +430,17 @@ export const useZoneAssetId = create((set) => ({ zoneAssetId: null, setZoneAssetId: (asset) => set({ zoneAssetId: asset }), })); + + +export const useMachineCount = create((set: any) => ({ + machineCount: 0, + setMachineCount: (x: any) => set({ activeLayer: x }), +})); +export const useMachineUptime = create((set: any) => ({ + machineActiveTime: 0, + setMachineActiveTime: (x: any) => set({ activeLayer: x }), +})); +export const useMaterialCycle = create((set: any) => ({ + materialCycleTime: 0, + setMaterialCycleTime: (x: any) => set({ activeLayer: x }), +})); \ No newline at end of file