Beispiel #1
0
        private FabEqp CheckEqp(string factoryID, string shopID, string eqpID, string where, ref bool hasError)
        {
            FabEqp eqp = ResHelper.FindEqp(eqpID);

            if (eqp == null)
            {
                hasError = true;

                ErrHist.WriteIf(where + eqpID,
                                ErrCategory.PERSIST,
                                ErrLevel.WARNING,
                                factoryID,
                                shopID,
                                Constants.NULL_ID,
                                Constants.NULL_ID,
                                Constants.NULL_ID,
                                Constants.NULL_ID,
                                eqpID,
                                Constants.NULL_ID,
                                "NOT FOUND EQP",
                                string.Format("Table:{0}", where)
                                );
            }

            return(eqp);
        }
Beispiel #2
0
        //Chamber생성
        internal static void InitializeParallelChamber(AoEquipment aeqp)
        {
            var eqp = aeqp.ToFabAoEquipment();

            if (eqp.IsParallelChamber == false)
            {
                return;
            }

            FabEqp taretEqp = aeqp.Target as FabEqp;

            AoChamberProc2 proc     = eqp.FirstProcess <AoChamberProc2>();
            var            chambers = proc.Chambers;

            if (chambers != null)
            {
                int count = chambers.Length;
                eqp.SubEqps = new FabSubEqp[count];

                for (int i = 0; i < count; i++)
                {
                    var    chamberInfo = chambers[i];
                    string subEqpID    = chamberInfo.Label;

                    var subEqp = taretEqp.GetSubEqp(subEqpID) as FabSubEqp;
                    subEqp.ChamberInfo = chamberInfo;

                    eqp.SubEqps[i] = subEqp;

                    subEqp.LastPlan             = SimHelper.CreateInitLastPlan(subEqp.StatusInfo);
                    subEqp.LastIdleRunStartTime = aeqp.NowDT;
                    subEqp.LastIdleStartTime    = aeqp.NowDT;
                }
            }
        }
Beispiel #3
0
        public static Time GetTransferTime(FabLot lot, AoEquipment eqp)
        {
            string from = null;
            string to   = null;

            if (lot != null && lot.PreviousFabPlan != null)
            {
                if (lot.PreviousFabPlan.IsLoaded)
                {
                    FabEqp prevEqp = lot.PreviousPlan.LoadedResource as FabEqp;
                    from = prevEqp.OutStocker;
                }
                else
                {
                    //init wip step --> next step
                    if (lot.Plans.Count == 2)
                    {
                        string wipEqpID = lot.Wip.WipEqpID;
                        var    prevEqp  = ResHelper.FindEqp(wipEqpID);
                        from = prevEqp != null ? prevEqp.OutStocker : wipEqpID;
                    }
                }
            }

            if (eqp != null)
            {
                to = (eqp.Target as FabEqp).InStocker;
            }

            return(GetTransferTime(from, to));
        }
Beispiel #4
0
        public static bool IsMixRunning(this FabEqp eqp)
        {
            if (eqp.IsParallelChamber == false)
            {
                return(false);
            }

            if (eqp.SubEqpGroups.Count < 2)
            {
                return(false);
            }

            List <string> currentSteps = new List <string>();

            foreach (var item in eqp.SubEqps.Values)
            {
                if (item.CurrentStep != null)
                {
                    if (item.CurrentStep.StdStep.IsMixRunStep == false)
                    {
                        continue;
                    }

                    if (currentSteps.Contains(item.CurrentStepID) == false)
                    {
                        currentSteps.Add(item.CurrentStepID);
                    }
                }
            }

            return(currentSteps.Count > 1);
        }
Beispiel #5
0
        /// <summary>
        /// </summary>
        /// <param name="entity"/>
        /// <param name="now"/>
        /// <param name="target"/>
        /// <param name="factor"/>
        /// <param name="ctx"/>
        /// <returns/>
        public WeightValue ASSIGN_STEP_PRIORITY(Mozart.Simulation.Engine.ISimEntity entity, DateTime now, Mozart.Simulation.Engine.ActiveObject target, Mozart.SeePlan.DataModel.WeightFactor factor, Mozart.SeePlan.Simulation.IDispatchContext ctx)
        {
            if (factor.Factor == 0)
            {
                return(new WeightValue(0));
            }

            FabAoEquipment eqp       = target as FabAoEquipment;
            FabEqp         targetEqp = eqp.TargetEqp;
            FabLot         lot       = entity as FabLot;

            float score = 0f;

            bool isLastStep = false;
            var  last       = eqp.GetLastPlan();

            if (last != null)
            {
                if (last.StepID == lot.CurrentStepID)
                {
                    isLastStep = true;
                }
            }

            if (isLastStep || targetEqp.MainRunSteps.Contains(lot.CurrentFabStep.StdStep))
            {
                score = 1f;
            }

            string lastStepID = last == null ? "-" : last.StepID;
            string desc       = string.Format("[Last : {0}, MainSteps:{1}]",
                                              lastStepID, targetEqp.EqpMainRunsSteps);

            return(new WeightValue(score * factor.Factor, desc));
        }
Beispiel #6
0
        public static Time GetTransferTime(AoEquipment fromEqp, AoEquipment toEqp)
        {
            FabEqp from = fromEqp.Target as FabEqp;
            FabEqp to   = toEqp.Target as FabEqp;

            return(GetTransferTime(from.OutStocker, to.InStocker));
        }
Beispiel #7
0
        public static void InitPM(this FabEqp eqp)
        {
            if (eqp.PMList == null)
            {
                eqp.PMList = new List <PMSchedule>();
            }

            List <PMSchedule> pmlist = DownMaster.GetPmList(eqp);

            if (eqp.State == ResourceState.Down && eqp.StatusInfo.MesStatus == MesEqpStatus.PM)
            {
                //EqpStatus PM 상태 반영
                FabPMSchedule initPM = CreateHelper.CreateFabPMSchedule(eqp.StatusInfo.StartTime, (int)eqp.StatusInfo.Duration, ScheduleType.PM, 0, 0);
                eqp.PMList.Add(initPM);

                //설비상태가 PM일경우 24시간 이내 PM은 무시
                DateTime pmFenceDate = ModelContext.Current.StartTime.AddDays(1);
                foreach (PMSchedule item in pmlist)
                {
                    if (item.StartTime < pmFenceDate)
                    {
                        continue;
                    }

                    eqp.PMList.Add(item);
                }
            }
            else
            {
                eqp.PMList.AddRange(pmlist);
            }
        }
Beispiel #8
0
        /// <summary>
        /// </summary>
        /// <param name="aeqp"/>
        /// <param name="loadableChambers"/>
        /// <param name="hb"/>
        /// <param name="handled"/>
        /// <param name="prevReturnValue"/>
        /// <returns/>
        public ISet <string> GET_NEED_SETUP_CHAMBERS0(Mozart.SeePlan.Simulation.AoEquipment aeqp, Mozart.SeePlan.Simulation.ChamberInfo[] loadableChambers, Mozart.SeePlan.Simulation.IHandlingBatch hb, ref bool handled, ISet <string> prevReturnValue)
        {
            FabLot lot = hb.ToFabLot();
            FabEqp eqp = aeqp.Target as FabEqp;

            List <FabSubEqp> list = ChamberMaster.GetSubEqps(eqp, loadableChambers);

            return(ChamberMaster.GetNeedSetupChamberIDs(list, lot));
        }
Beispiel #9
0
        public static List <PMSchedule> GetPMList(this FabEqp eqp)
        {
            if (eqp.PMList == null)
            {
                eqp.PMList = new List <PMSchedule>();
            }

            return(eqp.PMList);
        }
Beispiel #10
0
        public static void AddFromEqp(this FabEqp eqp, FabEqp target)
        {
            if (eqp.FromMapEqps == null)
            {
                eqp.FromMapEqps = new List <FabEqp>();
            }

            eqp.FromMapEqps.Add(target);
        }
Beispiel #11
0
        internal static void AddBaseEqp(this FabStdStep step, FabEqp eqp)
        {
            if (step.BaseEqps == null)
            {
                step.BaseEqps = new List <string>();
            }

            step.BaseEqps.Add(eqp.EqpID);
        }
Beispiel #12
0
        private static EqpArrangeSet ImportEqpArrangeSet(string key, string eqpID, FabEqp targetEqp, string stepID,
                                                         string productID, string productVer, FabStdStep stdStep, bool isFixedProductVer, bool isSubEqp)
        {
            //SubEqp의 경우는 defaultArrange 미지정
            string defaultArrange = isSubEqp ? null : stdStep.DefaultArrange;

            EqpArrangeSet setInfo = new EqpArrangeSet
            {
                Key                  = key,
                EqpID                = eqpID,
                TargetEqp            = targetEqp,
                StepID               = stepID,
                ProductID            = productID,
                ProductVer           = productVer,
                StdStep              = stdStep,
                DefaultArrange       = defaultArrange,
                DefaultLimitTypeList = LcdHelper.ParseLimitType(defaultArrange),
                IsFixedProductVer    = isFixedProductVer,
                IsSubEqp             = isSubEqp
            };

            var list = GetEqpArrangeInfo(eqpID);

            if (list == null || list.Count() == 0)
            {
                return(setInfo);
            }

            foreach (var arr in list)
            {
                if (arr.ActivateType == ActivateType.NONE)
                {
                    continue;
                }

                //MainRunStep이 등록된 설비의 경우, 타 Step의 M은 무시(2019.06.16 - by.liujian(유건))
                if (arr.ActivateType == ActivateType.M)
                {
                    var mainRunStep = targetEqp.MainRunSteps;
                    if (mainRunStep != null && mainRunStep.Count > 0)
                    {
                        if (mainRunStep.Find(t => t.StepID == stepID) == null)
                        {
                            continue;
                        }
                    }
                }

                if (arr.IsMatched(stepID, productID, productVer, isFixedProductVer))
                {
                    setInfo.AddItem(arr);
                }
            }

            return(setInfo);
        }
Beispiel #13
0
        public static bool HasMainRunStep(this FabEqp eqp)
        {
            var list = eqp.MainRunSteps;

            if (list != null && list.Count > 0)
            {
                return(true);
            }

            return(false);
        }
Beispiel #14
0
        public static List <FabSubEqp> GetSubEqps(this FabEqp eqp, ChamberInfo[] chmabers)
        {
            List <FabSubEqp> list = new List <FabSubEqp>();

            foreach (var item in chmabers)
            {
                list.Add(eqp.GetSubEqp(item.Label) as FabSubEqp);
            }

            return(list);
        }
Beispiel #15
0
        internal static void AddPM(FabEqp eqp, PMSchedule pm)
        {
            List <PMSchedule> list;

            if (_pmDic.TryGetValue(eqp, out list) == false)
            {
                list = new List <PMSchedule>();
                _pmDic.Add(eqp, list);
            }

            list.Add(pm);
        }
Beispiel #16
0
        internal static void AddEqp(this FabStdStep stdStep, FabEqp eqp)
        {
            if (stdStep.AllEqps == null)
            {
                stdStep.AllEqps = new List <FabEqp>();
            }

            if (stdStep.AllEqps.Contains(eqp) == false)
            {
                stdStep.AllEqps.Add(eqp);
            }
        }
Beispiel #17
0
        internal static List <PMSchedule> GetPmList(FabEqp eqp)
        {
            List <PMSchedule> list;

            _pmDic.TryGetValue(eqp, out list);

            if (list == null)
            {
                return(list = new List <PMSchedule>());
            }

            return(list);
        }
Beispiel #18
0
        private static void CheckOtherSubEqpGroup(this FabEqp targetEqp, FabSubEqp subEqp, FabStdStep targetStdStep, out bool isIdle, out bool isAvailableMixRun)
        {
            isIdle            = true;
            isAvailableMixRun = true;

            var groupList = targetEqp.SubEqpGroups;

            foreach (var group in groupList)
            {
                //동일 Group 체크 X
                if (group == subEqp.SubEqpGroup)
                {
                    continue;
                }

                var sampleSubEqp = group.SubEqps.Values.FirstOrDefault();
                if (sampleSubEqp == null)
                {
                    continue;
                }

                if (sampleSubEqp.Current != null)
                {
                    isIdle = false;
                }

                if (sampleSubEqp.IsMixRunStep == false)
                {
                    isAvailableMixRun = false;
                }
                else
                {
                    if (sampleSubEqp.CurrentStepID == targetStdStep.StepID)
                    {
                        continue;
                    }

                    FabStdStep stdStep = sampleSubEqp.CurrentStep.StdStep;
                    if (stdStep.MixRunPairSteps.Contains(targetStdStep) == false)
                    {
                        isAvailableMixRun = false;
                    }
                }
            }

            //모두 IDLE인 경우는 isAvailableMixRun = false 상태이므로
            if (isIdle && isAvailableMixRun)
            {
                isAvailableMixRun = false;
            }
        }
Beispiel #19
0
        /// <summary>
        /// 현재설비의 이동시간을 등록함
        /// </summary>
        /// <param name="eqp"><현재설비/param>
        /// <param name="targetEqp">대상설비</param>
        /// <param name="transferTime">이동시간(분)</param>
        /// <param name="isFrom">true:이전설비 → 현재설비, false: 현재설비 → 다음설비</param>
        public static void AddTransferTime(this FabEqp eqp, string targetEqp, int transferTime, bool isFrom)
        {
            Dictionary <string, int> dic = isFrom ? eqp.TransferTimeFrom : eqp.TransferTimeTo;

            if (dic == null)
            {
                dic = new Dictionary <string, int>();
            }

            if (dic.ContainsKey(targetEqp) == false)
            {
                dic.Add(targetEqp, transferTime);
            }
        }
Beispiel #20
0
        public static FabSubEqp GetSubEqp(this FabEqp eqp, string subEqpID)
        {
            if (string.IsNullOrEmpty(subEqpID))
            {
                return(null);
            }

            FabSubEqp subEqp;

            if (eqp.SubEqps.TryGetValue(subEqpID, out subEqp))
            {
                return(subEqp);
            }

            return(null);
        }
Beispiel #21
0
        public static List <FabSubEqp> GetSubEqpList(this FabEqp eqp, List <string> subEqps)
        {
            List <FabSubEqp> list = new List <FabSubEqp>();

            foreach (var item in subEqps)
            {
                FabSubEqp sub = GetSubEqp(eqp, item);

                if (sub != null)
                {
                    list.Add(sub);
                }
            }

            return(list);
        }
Beispiel #22
0
        public static bool IsMainRunStep(this FabEqp eqp, string stepID)
        {
            if (eqp.HasMainRunStep() == false)
            {
                return(false);
            }

            var list = eqp.MainRunSteps;
            var find = list.Find(t => t.StepID == stepID);

            if (find != null)
            {
                return(true);
            }

            return(false);
        }
Beispiel #23
0
        internal static void AddAdjustPmList()
        {
            DateTime planStartTime = ModelContext.Current.StartTime;
            DateTime planEndTime   = ModelContext.Current.EndTime;

            foreach (KeyValuePair <FabEqp, List <PMSchedule> > item in _pmDic)
            {
                FabEqp eqp = item.Key;
                item.Value.Sort((x, y) => x.StartTime.CompareTo(y.StartTime));

                PMSchedule lastPMSched = null;
                foreach (PMSchedule pm in item.Value)
                {
                    if (pm.EndTime < planStartTime)
                    {
                        continue;
                    }

                    if (pm.StartTime > planEndTime)
                    {
                        break;
                    }

                    if (lastPMSched != null)
                    {
                        if (lastPMSched.EndTime >= pm.StartTime && lastPMSched.EndTime < pm.EndTime)
                        {
                            lastPMSched.EndTime = pm.EndTime;
                            continue;
                        }
                    }

                    lastPMSched = pm;

                    List <PMSchedule> list;
                    if (_pmList.TryGetValue(eqp, out list) == false)
                    {
                        list = new List <PMSchedule>();
                        _pmList.Add(eqp, list);
                    }

                    list.Add(pm);
                }
            }
        }
Beispiel #24
0
        public static StepTime CreateAverageStepTime(FabStep step, FabEqp eqp, string productID, float tact, float proc, string reason)
        {
            StepTime st = CreateHelper.CreateStepTime(eqp, step, productID, tact, proc);

            List <StepTime> list;

            if (step.StepTimes.TryGetValue(productID, out list) == false)
            {
                list = new List <StepTime>();
            }

            list.Add(st);

            //TODO : Output:
            //OutputMart.Instance.AppxStepTime.Add(item);

            return(st);
        }
Beispiel #25
0
        //#region Load History 관련
        //internal static bool RequireMerge(this FabAoEquipment eqp)
        //{
        //    if (eqp.CurrentLoadInfo != null && eqp.CurrentLoadInfo.IsEmpty == false)
        //        return eqp.CurrentLoadInfo.StartTime == eqp.NowDT && eqp.CurrentLoadInfo.IsIgnoreableState;

        //    return false;
        //}


        ///// <summary>
        ///// 임의로 LoadPlan을 삽입을 위한 함수입니다.
        ///// </summary>
        //internal static void AddLoadPlan(this FabAoEquipment eqp, LoadStates state, DateTime date)
        //{
        //    FabLoadInfo info = CreateHelper.CreateLoadInfo(null, date, state, eqp.MaskID, Constants.NULL_ID);
        //    FabLoadInfo last;

        //    if (eqp.LastLoadInfo == null)
        //    {
        //        eqp.LoadInfos = new List<FabLoadInfo>();
        //        eqp.AddLoadPlan(info);
        //    }
        //    else
        //    {
        //        last = eqp.LastLoadInfo;
        //        last.EndTime = date;
        //        eqp.AddLoadPlan(info);
        //    }

        //}


        ///// <summary>
        ///// 설비에 Plan을 입력합니다.
        ///// </summary>
        ///// <param name="eqp"></param>
        ///// <param name="info"></param>
        //internal static void AddLoadPlan(this FabAoEquipment eqp, FabLoadInfo info)
        //{
        //    if (eqp.LoadInfos == null)
        //        eqp.LoadInfos = new List<FabLoadInfo>();

        //    eqp.LoadInfos.Add(info);
        //}


        ///// <summary>
        ///// 설비의 StateChange 최초 호출시 사용됩니다.
        ///// </summary>
        //public static void AddNewLoadPlan(this FabAoEquipment eqp, FabLoadInfo info, FabLot lot)
        //{
        //    if (lot != null)
        //        info.AddPlanInfo(lot.CurrentFabPlan);

        //    eqp.AddLoadPlan(info);
        //    eqp.CurrentLoadInfo = info;
        //}


        ///// <summary>
        ///// 이전 Plan을 종료하고 현재Plan을 삽입합니다.
        ///// </summary>
        ///// <param name="eqp"></param>
        ///// <param name="last"></param>
        ///// <param name="info"></param>
        ///// <param name="lot"></param>
        //public static void ChangeLoadPlan(this FabAoEquipment eqp, FabLoadInfo last, FabLoadInfo info, FabLot lot)
        //{
        //    if (lot != null)
        //        info.AddPlanInfo(lot.CurrentFabPlan);

        //    last.EndTime = eqp.NowDT;
        //    eqp.AddLoadPlan(info);
        //}
        //#endregion



        #region PM 관련
        public static bool IsPmPeriod(this FabEqp eqp, DateTime date)
        {
            List <PMSchedule> list = eqp.GetPMList();

            if (list == null || list.Count == 0)
            {
                return(false);
            }

            foreach (PMSchedule item in list)
            {
                if (item.IsPmPeriodSection(date))
                {
                    return(true);
                }
            }

            return(false);
        }
Beispiel #26
0
        //internal static void InitMask_LocateWip(AoFactory factory, IHandlingBatch hb)
        //{
        //	FabLot lot = hb.ToFabLot();

        //	if (IsUseTool(lot) == false)
        //		return;

        //	if (lot.CurrentFabPlan.IsInitRunWip == false)
        //		return;

        //	var targetEqp = lot.CurrentPlan.LoadedResource as FabEqp;
        //	if (targetEqp == null)
        //		return;

        //	var mask = targetEqp.InitMask;
        //	if (mask == null)
        //		return;

        //	var aeqp = factory.GetEquipment(targetEqp.EqpID) as FabAoEquipment;
        //	var loableList = GetLoadableMaskList(aeqp, lot);

        //	if (loableList.Contains(mask))
        //	{
        //		aeqp.SeizeMaskTool(mask, lot);
        //	}
        //	else
        //	{
        //		ErrHist.WriteIf(mask.ToolID,
        //			ErrCategory.SIMULATION,
        //			ErrLevel.INFO,
        //			targetEqp.FactoryID,
        //			targetEqp.ShopID,
        //			lot.LotID,
        //			lot.CurrentProductID,
        //			lot.CurrentProductVersion ?? lot.Wip.ProductVersion,
        //			lot.CurrentProcessID,
        //			targetEqp.EqpID,
        //			lot.CurrentStepID,
        //			"CAN NOT INIT MASK_TOOL",
        //			string.Format("Eqp InitMask : {0}", mask.ToolID)
        //			);
        //	}
        //}

        internal static void InitLocate(AoEquipment aeqp, IHandlingBatch hb)
        {
            FabLot lot = hb.ToFabLot();

            if (IsUseTool(lot) == false)
            {
                return;
            }

            FabEqp targetEqp = aeqp.Target as FabEqp;

            var mask = targetEqp.InitMask;

            if (mask == null)
            {
                return;
            }

            var loableList = GetLoadableMaskList(aeqp, lot);

            if (loableList.Contains(mask))
            {
                lot.CurrentMask = mask;
            }
            else
            {
                ErrHist.WriteIf(mask.ToolID,
                                ErrCategory.SIMULATION,
                                ErrLevel.INFO,
                                targetEqp.FactoryID,
                                targetEqp.ShopID,
                                lot.LotID,
                                lot.CurrentProductID,
                                lot.CurrentProductVersion ?? lot.Wip.ProductVersion,
                                lot.CurrentProcessID,
                                targetEqp.EqpID,
                                lot.CurrentStepID,
                                "CAN NOT INIT MASK_TOOL",
                                string.Format("Eqp InitMask : {0}", mask.ToolID)
                                );
            }
        }
Beispiel #27
0
        /// <summary>
        /// </summary>
        /// <param name="resource"/>
        /// <param name="stateChangeTime"/>
        /// <param name="handled"/>
        /// <param name="prevReturnValue"/>
        /// <returns/>
        public DateTime GET_EQP_UP_TIME0(Mozart.SeePlan.DataModel.Resource resource, DateTime stateChangeTime, ref bool handled, DateTime prevReturnValue)
        {
            FabEqp eqp = resource as FabEqp;


#if DEBUG
            if (eqp.EqpID == "THPHL100")
            {
                Console.WriteLine();
            }


            if (eqp.State == ResourceState.Up)
            {
                Console.WriteLine();
            }
#endif


            return(eqp.StatusInfo.EndTime);
        }
Beispiel #28
0
        private static EqpArrangeSet GetEqpArrangeSet(string eqpID, FabEqp targetEqp, FabStdStep stdStep,
                                                      string productID, string productVer, bool isSubEqp = false)
        {
            string stepID = stdStep.StepID;

            string key = CreateKey_EqpArrangeSet(eqpID, stepID, productID, productVer);

            //check cache
            EqpArrangeSet info;

            if (Infos.TryGetValue(key, out info) == false)
            {
                bool isFixedProductVer = IsFixedProductVer(stdStep, productVer);

                info = ImportEqpArrangeSet(key, eqpID, targetEqp, stepID, productID, productVer, stdStep, isFixedProductVer, isSubEqp);
                Infos.Add(key, info);

                return(info);
            }

            return(info);
        }
Beispiel #29
0
        public static string GetDispatchWipLog(FabEqp targeEqp, EntityDispatchInfo info, FabLot lot, WeightPreset wp)
        {
            var slot = lot as FabLot;

            StringBuilder sb = new StringBuilder();

            SetDefaultLotInfo(sb, slot);

            if (wp != null)
            {
                foreach (var factor in wp.FactorList)
                {
                    var vdata = slot.WeightInfo.GetValueData(factor);

                    sb.Append("/");

                    if (string.IsNullOrEmpty(vdata.Description))
                    {
                        sb.Append(vdata.Value);
                    }
                    else
                    {
                        sb.Append(vdata.Value + "@" + vdata.Description);
                    }
                }
            }

            if (lot.CurrentFabPlan.LotFilterInfo != null && lot.CurrentFabPlan.LotFilterInfo.FilterType == DispatchFilter.Revaluate)
            {
                sb.Append("/0@[IS_REVALUATE:Y]");
            }
            else
            {
                sb.Append("/0@[IS_REVALUATE:N]");
            }

            return(sb.ToString());
        }
Beispiel #30
0
        /// <summary>
        /// </summary>
        /// <param name="aeqp"/>
        /// <param name="hb"/>
        /// <param name="handled"/>
        /// <param name="prevReturnValue"/>
        /// <returns/>
        public ProcTimeInfo GET_PROCESS_TIME0(AoEquipment aeqp, IHandlingBatch hb, ref bool handled, ProcTimeInfo prevReturnValue)
        {
            FabStep step = hb.CurrentStep as FabStep;
            FabEqp  eqp  = aeqp.Target as FabEqp;

            FabLot   lot = hb.Sample as FabLot;
            StepTime st  = step.GetStepTime(eqp.EqpID, lot.CurrentProductID);

            float mixRunRatio = 1;

            if (aeqp.IsParallelChamber)
            {
                if (eqp.IsMixRunning())
                {
                    mixRunRatio = lot.CurrentFabStep.StdStep.MixCriteria;
                }

                if (mixRunRatio == 0)
                {
                    mixRunRatio = 1;
                }
            }

            ProcTimeInfo time = new ProcTimeInfo();

            if (st != null)
            {
                time.FlowTime = TimeSpan.FromSeconds(st.ProcTime * mixRunRatio);
                time.TactTime = TimeSpan.FromSeconds(st.TactTime * mixRunRatio);
            }
            else
            {
                time.FlowTime = TimeSpan.FromMinutes(10);
                time.TactTime = TimeSpan.FromMinutes(10);
            }

            return(time);
        }