public void CheckQueues(MazakSchedulesAndLoadActions mazakData) { if (!OpenDatabaseKitDB.MazakTransactionLock.WaitOne(TimeSpan.FromMinutes(3), true)) { log.Debug("Unable to obtain mazak db lock, trying again soon."); return; } try { var transSet = CalculateScheduleChanges(mazakData); if (transSet != null && transSet.Schedules.Count() > 0) { _transDB.Save(transSet, "Setting material from queues"); } CurrentQueueMismatch = false; } catch (Exception ex) { CurrentQueueMismatch = true; log.Error(ex, "Error checking for new material"); } finally { OpenDatabaseKitDB.MazakTransactionLock.ReleaseMutex(); } }
public LogTranslation(BlackMaple.MachineFramework.JobDB jDB, BlackMaple.MachineFramework.JobLogDB logDB, MazakSchedulesAndLoadActions mazakSch, BlackMaple.MachineFramework.FMSSettings settings, Action <LogEntry> onMazakLogMessage) { _jobDB = jDB; _log = logDB; _mazakSchedules = mazakSch; _settings = settings; _onMazakLog = onMazakLogMessage; _jobs = new Dictionary <string, JobPlan>(); }
public MazakWriteData CalculateScheduleChanges(MazakSchedulesAndLoadActions mazakData) { log.Debug("Starting check for new queued material to add to mazak"); var schs = LoadSchedules(mazakData); if (!schs.Any()) { return(null); } AttemptToUnallocateCastings(schs); CalculateTargetMatQty(mazakData, schs); AttemptToAllocateCastings(schs, mazakData); return(UpdateMazakMaterialCounts(schs)); }
private void CalculateTargetMatQty(MazakSchedulesAndLoadActions mazakData, IEnumerable <ScheduleWithQueues> schs) { // go through each job and process, and distribute the queued material among the various paths // for the job and process. foreach (var job in schs.GroupBy(s => s.Unique)) { var uniqueStr = job.Key; var numProc = job.First().Job.NumProcesses; log.Debug("Checking job {uniq} with schedules {@pathGroup}", uniqueStr, job); // do processes 2+ so that correct material counts are present during check for // castings in proc1. for (int proc = 2; proc <= numProc; proc++) { CheckInProcessMaterial(job.First().Job, job, proc); } CheckCastingsForProc1(job, mazakData); } }
public MazakSchedulesAndLoadActions LoadSchedulesAndLoadActions() { return(WithReadDBConnection(conn => { var trans = conn.BeginTransaction(); try { var ret = new MazakSchedulesAndLoadActions() { Schedules = _openReadDB.LoadSchedules(conn, trans).Schedules, LoadActions = CurrentLoadActions(), Tools = LoadTools(conn, trans) }; trans.Commit(); return ret; } catch { trans.Rollback(); throw; } })); }
private List <DecrSchedule> JobsToDecrement(MazakSchedulesAndLoadActions schedules) { var jobs = new List <DecrSchedule>(); foreach (var sch in schedules.Schedules) { //parse schedule if (!MazakPart.IsSailPart(sch.PartName)) { continue; } if (string.IsNullOrEmpty(sch.Comment)) { continue; } MazakPart.ParseComment(sch.Comment, out string unique, out var procToPath, out bool manual); if (manual) { continue; } //load the job if (string.IsNullOrEmpty(unique)) { continue; } var job = _jobDB.LoadJob(unique); if (job == null) { continue; } // if already decremented, ignore if (_jobDB.LoadDecrementsForJob(unique).Any()) { continue; } // check load is in process var loadOpers = schedules.LoadActions; var loadingQty = 0; if (loadOpers != null) { foreach (var action in loadOpers) { if (action.Unique == job.UniqueStr && action.Process == 1 && action.LoadEvent && action.Path == procToPath.PathForProc(action.Process)) { loadingQty += action.Qty; Log.Debug("Found {uniq} is in the process of being loaded action {@action}", job.UniqueStr, action); } } } jobs.Add(new DecrSchedule() { Schedule = sch, Job = job, Proc1Path = procToPath.PathForProc(proc: 1), NewPlanQty = CountCompletedOrMachiningStarted(sch) + loadingQty }); } return(jobs); }
private void AttemptToAllocateCastings(IEnumerable <ScheduleWithQueues> schs, MazakSchedulesAndLoadActions mazakData) { // go through each job and check for castings in an input queue that have not yet been assigned to a job foreach (var job in schs.Where(s => !s.LowerPriorityScheduleMatchingPartSkipped).OrderBy(s => s.Job.RouteStartingTimeUTC).GroupBy(s => s.Unique)) { var uniqueStr = job.Key; var partName = job.First().Job.PartName; var numProc = job.First().Job.NumProcesses; log.Debug("Checking job {uniq} with for unallocated castings", uniqueStr); bool needRecheckProc1 = false; // check for any raw material to assign to the job var proc1Queues = job .Select(s => s.Procs[1].InputQueue) .Where(q => !string.IsNullOrEmpty(q)) .Distinct(); foreach (var queue in proc1Queues) { var inQueue = _log.GetMaterialInQueue(queue); var remain = job.Select(s => s.SchRow.PlanQuantity - CountCompletedOrMachiningStarted(s) ).Sum(); var alreadyAssigned = inQueue .Where(m => m.Unique == uniqueStr && FindNextProcess(m.MaterialID) == 1) .Count(); var partsToAllocate = inQueue .Where(m => string.IsNullOrEmpty(m.Unique) && m.PartName == partName) .Any(); log.Debug("Checking unique {uniq} for unallocated castings in queue {queue}, " + " found {remain} remaining parts, {assigned} already assigned parts, {toAllocate} parts to allocate", uniqueStr, queue, remain, alreadyAssigned, partsToAllocate); if (remain > alreadyAssigned && partsToAllocate) { var newMats = _log.AllocateCastingsInQueue(queue, partName, uniqueStr, numProc, remain - alreadyAssigned); log.Debug("Alloacted new ids {@matIds} to {unique}, recalculating proc1 castings", newMats, uniqueStr); needRecheckProc1 = true; } } if (needRecheckProc1) { CheckCastingsForProc1(job, mazakData); } } }
private void CheckCastingsForProc1(IGrouping <string, ScheduleWithQueues> job, MazakSchedulesAndLoadActions mazakData) { string uniqueStr = job.Key; // group the paths for this process by input queue var proc1PathsByQueue = job .Where(s => s.SchRow.PlanQuantity > CountCompletedOrMachiningStarted(s)) .Select(s => s.Procs[1]) .Where(p => !string.IsNullOrEmpty(p.InputQueue)) .GroupBy(p => p.InputQueue); foreach (var queueGroup in proc1PathsByQueue) { var matInQueue = _log.GetMaterialInQueue(queueGroup.Key) .Where(m => m.Unique == uniqueStr && FindNextProcess(m.MaterialID) == 1) .Count() ; var curMazakSchMat = queueGroup.Select(s => s.SchProcRow.ProcessMaterialQuantity).Sum(); log.Debug("Calculated {matInQueue} parts in queue and {mazakCnt} parts in mazak for job {uniq} proccess 1", matInQueue, curMazakSchMat, uniqueStr); if (queueGroup.Count() == 1) { // put all material on the single path if (matInQueue != curMazakSchMat) { queueGroup.First().TargetMaterialCount = matInQueue; } } else { // keep each path at least fixQty piece of material if (matInQueue > curMazakSchMat) { int remain = matInQueue - curMazakSchMat; var potentialPaths = queueGroup .Where(p => p.SchProcRow.ProcessMaterialQuantity == 0) .OrderBy(p => p.SchProcRow.ProcessExecuteQuantity); foreach (var p in potentialPaths) { int fixQty = p.SchProcRow.FixQuantity; if (fixQty <= remain) { remain -= fixQty; p.TargetMaterialCount = fixQty; } if (remain <= 0) { break; } } } else if (matInQueue < curMazakSchMat) { int toRemove = curMazakSchMat - matInQueue; var potentialPaths = queueGroup .Where(p => p.SchProcRow.ProcessMaterialQuantity > 0) .OrderByDescending(p => p.SchProcRow.ProcessMaterialQuantity) .ThenBy(p => p.SchProcRow.ProcessExecuteQuantity); foreach (var p in potentialPaths) { if (toRemove >= p.SchProcRow.ProcessMaterialQuantity) { p.TargetMaterialCount = 0; toRemove -= p.SchProcRow.ProcessMaterialQuantity; } else { p.TargetMaterialCount = p.SchProcRow.ProcessMaterialQuantity - toRemove; toRemove = 0; } if (toRemove <= 0) { break; } } } } } // now deal with the non-input-queue parts. They could have larger material than planned quantity // if the schedule has been decremented foreach (var sch in job) { if (string.IsNullOrEmpty(sch.Procs[1].InputQueue) && sch.SchRow.PlanQuantity <= CountCompletedOrMachiningStarted(sch) && sch.Procs[1].SchProcRow.ProcessMaterialQuantity > 0 ) { sch.Procs[1].TargetMaterialCount = 0; } } }
private IEnumerable <ScheduleWithQueues> LoadSchedules(MazakSchedulesAndLoadActions mazakData) { var loadOpers = mazakData.LoadActions; var schs = new List <ScheduleWithQueues>(); var pending = _log.AllPendingLoads(); var skippedParts = new HashSet <string>(); foreach (var schRow in mazakData.Schedules.OrderBy(s => s.DueDate).ThenBy(s => s.Priority)) { if (!MazakPart.IsSailPart(schRow.PartName)) { continue; } MazakPart.ParseComment(schRow.Comment, out string unique, out var procToPath, out bool manual); var job = _jobDB.LoadJob(unique); if (job == null) { continue; } // only if no load or unload action is in process bool foundJobAtLoad = false; foreach (var action in loadOpers) { if (action.Unique == job.UniqueStr && action.Path == procToPath.PathForProc(action.Process)) { foundJobAtLoad = true; skippedParts.Add(job.PartName); log.Debug("Not editing queued material because {uniq} is in the process of being loaded or unload with action {@action}", job.UniqueStr, action); break; } } foreach (var pendingLoad in pending) { var s = pendingLoad.Key.Split(','); if (schRow.PartName == s[0]) { skippedParts.Add(job.PartName); foundJobAtLoad = true; log.Debug("Not editing queued material because found a pending load {@pendingLoad}", pendingLoad); break; } } if (foundJobAtLoad) { continue; } // start building the schedule var sch = new ScheduleWithQueues() { SchRow = schRow, Unique = unique, Job = job, LowerPriorityScheduleMatchingPartSkipped = skippedParts.Contains(job.PartName), Procs = new Dictionary <int, ScheduleWithQueuesProcess>(), }; bool missingProc = false; for (int proc = 1; proc <= job.NumProcesses; proc++) { MazakScheduleProcessRow schProcRow = null; foreach (var row in schRow.Processes) { if (row.ProcessNumber == proc) { schProcRow = row; break; } } if (schProcRow == null) { log.Error("Unable to find process {proc} for job {uniq} and schedule {schid}", proc, job.UniqueStr, schRow.Id); missingProc = true; break; } var path = procToPath.PathForProc(proc); sch.Procs.Add(proc, new ScheduleWithQueuesProcess() { SchProcRow = schProcRow, PathGroup = job.GetPathGroup(process: proc, path: path), InputQueue = job.GetInputQueue(process: proc, path: path) }); } if (!missingProc) { schs.Add(sch); } } return(schs); }