/// <summary> /// Run requirements planning and backward/forward termination. /// </summary> /// <param name="demand"></param> /// <param name="task"></param> /// <param name="simulationId"></param> public void RunRequirementsAndTermination(IDemandToProvider demand, MrpTask task, int simulationId) { if (demand.State == State.Created) { ExecutePlanning(demand, task, simulationId); if (demand.State != State.Finished) { demand.State = State.ProviderExist; } _context.Update(demand); _context.SaveChanges(); _messageHub.SendToAllClients("Requirements planning completed."); } if (task == MrpTask.All || task == MrpTask.Backward) { _scheduling.BackwardScheduling(demand); demand.State = State.BackwardScheduleExists; _context.Update(demand); _context.SaveChanges(); _messageHub.SendToAllClients("Backward schedule exists."); } if (task == MrpTask.All && CheckNeedForward(demand, simulationId) || task == MrpTask.Forward) { //schedules forward and then backward again with the finish of the forward algorithm _scheduling.ForwardScheduling(demand); demand.State = State.ForwardScheduleExists; _context.Update(demand); _context.SaveChanges(); _scheduling.BackwardScheduling(demand); _messageHub.SendToAllClients("Forward schedule exists."); } _context.SaveChanges(); }
/// <summary> /// Plans all unplanned Orders with MRP I + II /// </summary> /// <param name="task"></param> /// <returns></returns> public async Task CreateAndProcessOrderDemand(MrpTask task, ProductionDomainContext context, int simulationId, ProductionDomainContext evaluationContext) { await Task.Run(() => { if (context != null) { _context = context; } var newOrdersAdded = false; _messageHub.SendToAllClients("Start full MRP cycle...", MessageType.info); //get all unplanned orderparts and iterate through them for MRP var simConfig = _context.SimulationConfigurations.Single(a => a.Id == simulationId); var maxAllowedTime = simConfig.Time + simConfig.MaxCalculationTime; //Todo: put together if problem is solved var orderParts3 = _context.OrderParts.Include(a => a.Order).Where(a => a.IsPlanned == false); var orderParts2 = orderParts3.Where(a => a.Order.CreationTime <= simConfig.Time); var orderParts = orderParts2.Where(a => a.Order.DueTime < maxAllowedTime).Include(a => a.Article).ToList(); if (orderParts.Any()) { newOrdersAdded = true; } foreach (var orderPart in orderParts.ToList()) { var demand = GetDemand(orderPart); _messageHub.SendToAllClients("running requirements for orderpart " + orderPart.Id); //run the requirements planning and backward/forward termination algorithm RunRequirementsAndTermination(demand, task, simulationId); } if (task == MrpTask.All || task == MrpTask.GifflerThompson || task == MrpTask.Capacity) { //run the capacity algorithm PlanCapacities(task, newOrdersAdded, simulationId, evaluationContext); _messageHub.SendToAllClients("Capacities are planned"); } //set all orderparts to be planned foreach (var orderPart in orderParts) { if (task == MrpTask.All || task == MrpTask.GifflerThompson) { orderPart.IsPlanned = true; } } _context.SaveChanges(); _messageHub.SendToAllClients("End of the latest calculated order: " + _context.ProductionOrderWorkSchedules?.Max(a => a.End)); }); }
public void ExecutePlanning(IDemandToProvider demand, MrpTask task, int simulationId) { //creates Provider for the needs var productionOrders = _demandForecast.NetRequirement(demand, task, simulationId); if (demand.State != State.Finished) { demand.State = State.ProviderExist; } var articleBoms = _context.ArticleBoms .Include(a => a.ArticleChild) .ThenInclude(a => a.ArticleBoms) .ToList(); //If there was enough in stock this does not have to be produced if (!productionOrders.Any()) { return; } foreach (var productionOrder in productionOrders) { //if the ProductionOrder was just created, initialize concrete WorkSchedules for the ProductionOrders if (productionOrder.ProductionOrderWorkSchedule == null || !productionOrder.ProductionOrderWorkSchedule.Any()) { _context.CreateProductionOrderWorkSchedules(productionOrder); } var children = articleBoms.Where(a => a.ArticleParentId == productionOrder.ArticleId) .ToList(); if (!children.Any()) { return; } foreach (var child in children) { //create Requester var dpob = _context.CreateDemandProductionOrderBom(child.ArticleChildId, productionOrder.Quantity * (int)child.Quantity); //create Production-BOM _context.TryCreateProductionOrderBoms(dpob, productionOrder, simulationId); //call this method recursively for a depth-first search ExecutePlanning(dpob, task, simulationId); } } }
/// <summary> /// Call this method for a single run without simulation. /// </summary> /// <param name="task"></param> /// <param name="simulationId"></param> /// <returns></returns> public async Task InitializeMrp(MrpTask task, int simulationId) { await Task.Run(async() => { _messageHub.SendToAllClients("Prepare InMemory Tables...", MessageType.info); rebuildNets = new RebuildNets(_context); capacityScheduling = new CapacityScheduling(_context); _context = InMemoryContext.CreateInMemoryContext(); InMemoryContext.LoadData(_evaluationContext, _context); await PrepareSimulationContext(); var simConfig = _context.SimulationConfigurations.Single(x => x.Id == simulationId); await OrderGenerator.GenerateOrders(_context, simConfig, simulationId); var simulationNumber = _context.GetSimulationNumber(simulationId, SimulationType.Central); //call initial central MRP-run await _processMrp.CreateAndProcessOrderDemand(task, _context, simulationId, _evaluationContext); if (task == MrpTask.Backward || task == MrpTask.Forward || task == MrpTask.GifflerThompson) { var list = _context.ProductionOrderWorkSchedules.Select(schedule => new PowsSimulationItem(_context) { End = (task == MrpTask.Backward) ? schedule.EndBackward : (task == MrpTask.Forward) ? schedule.EndForward : schedule.End, Start = (task == MrpTask.Backward) ? schedule.StartBackward : (task == MrpTask.Forward) ? schedule.StartForward : schedule.Start, ProductionOrderId = schedule.ProductionOrderId, ProductionOrderWorkScheduleId = schedule.Id, SimulationId = simulationId }) .ToList(); _evaluationContext.SaveChanges(); FillSimulationWorkSchedules(list, simulationId, simulationNumber, task); } SimulationType simType = SimulationType.Central; switch (task) { case MrpTask.Forward: simType = SimulationType.ForwardPlanning; break; case MrpTask.Backward: simType = SimulationType.BackwardPlanning; break; } CopyResults.ExtractSimulationOrders(_context, _evaluationContext, simulationId, simulationNumber, simType); _messageHub.EndScheduler(); }); }
/// <summary> /// Plans capacities for all demands which are either already planned or just finished with MRP. /// </summary> /// <param name="task"></param> /// <param name="newOrdersAdded"></param> public void PlanCapacities(MrpTask task, bool newOrdersAdded, int simulationId, ProductionDomainContext evaluationContext) { var timer = _context.SimulationConfigurations.Single(a => a.Id == simulationId).Time; var demands = _context.Demands.Where(a => a.State == State.BackwardScheduleExists || a.State == State.ForwardScheduleExists || a.State == State.ExistsInCapacityPlan || (timer > 0 && a.State == State.Injected)).ToList(); List <MachineGroupProductionOrderWorkSchedule> machineList = null; /*if (newOrdersAdded) * { * _rebuildNets.Rebuild(simulationId, evaluationContext); * _messageHub.SendToAllClients("RebuildNets completed"); * }*/ if (timer == 0 && (task == MrpTask.All || task == MrpTask.Capacity)) { //creates a list with the needed capacities to follow the terminated schedules machineList = _capacityScheduling.CapacityRequirementsPlanning(simulationId); } if (timer != 0 || (task == MrpTask.GifflerThompson || (_capacityScheduling.CapacityLevelingCheck(machineList) && task == MrpTask.All))) { _capacityScheduling.GifflerThompsonScheduling(simulationId); } else { foreach (var demand in demands) { SetStartEndFromTermination(demand); } _capacityScheduling.SetMachines(simulationId); } foreach (var demand in demands) { demand.State = State.ExistsInCapacityPlan; } _context.Demands.UpdateRange(demands); _context.SaveChanges(); }
/// <summary> /// Creates providers for the demands through stock, productionOrders or purchases /// </summary> /// <param name="demand"></param> /// <param name="task"></param> /// <param name="simulationId"></param> /// <returns>ProductionOrder to fulfill the demand, ProductionOrder is null if there was enough in stock</returns> public List <ProductionOrder> NetRequirement(IDemandToProvider demand, MrpTask task, int simulationId) { //Todo: search for available POs var stock = _context.Stocks.Include(a => a.DemandStocks) .Single(a => a.ArticleForeignKey == demand.ArticleId); var plannedStock = _context.GetPlannedStock(stock, demand); var productionOrders = new List <ProductionOrder>(); var stockProvider = _context.TryCreateStockReservation(demand); var time = _context.SimulationConfigurations.Single(a => a.Id == simulationId).Time; //if the article has no children it has to be purchased var children = _context.ArticleBoms.Where(a => a.ArticleParentId == demand.ArticleId).ToList(); if (children.Any()) { //if the plannedStock is below zero, articles have to be produced for its negative amount if (plannedStock < 0) { var fittingProductionOrders = _context.CheckForProductionOrders(demand, -plannedStock, _context.SimulationConfigurations.Single(a => a.Id == simulationId).Time); var amount = -plannedStock; if (fittingProductionOrders != null) { foreach (var fittingProductionOrder in fittingProductionOrders) { var availableAmount = _context.GetAvailableAmountFromProductionOrder(fittingProductionOrder); var provider = _context.CreateDemandProviderProductionOrder(demand, fittingProductionOrder, availableAmount < -plannedStock ? availableAmount : -plannedStock); //productionOrders.Add(fittingProductionOrder); _context.AssignProductionOrderToDemandProvider(fittingProductionOrder, provider); amount -= availableAmount < -plannedStock ? availableAmount : -plannedStock; if (amount == 0) { return(productionOrders); } } } if (amount > 0) { var pos = _context.CreateChildProductionOrders(demand, amount, simulationId); productionOrders.AddRange(pos); } } } else if (plannedStock < stock.Min) { _context.CreatePurchaseDemand(demand, stock.Max - stock.Min, _context.SimulationConfigurations.Single(a => a.Id == simulationId).Time); } if (stock.Min <= 0 || plannedStock >= stock.Min || demand.GetType() == typeof(DemandStock)) { return(productionOrders); } if (_context.Demands.OfType <DemandStock>() .Any(a => a.ArticleId == demand.ArticleId && a.State != State.Finished)) { return(productionOrders); } var demandStock = plannedStock < 0 ? _context.CreateStockDemand(demand, stock, stock.Min) : _context.CreateStockDemand(demand, stock, stock.Min - plannedStock); //call processMrp to plan and schedule the stockDemand _processMrp.RunRequirementsAndTermination(demandStock, task, simulationId); return(productionOrders); }
private void FillSimulationWorkSchedules(List <PowsSimulationItem> items, int simulationId, int simulationNumber, MrpTask task) { foreach (var item in items) { var po = _context.ProductionOrders.Include(b => b.Article).Single(a => a.Id == item.ProductionOrderId); var pows = _context.ProductionOrderWorkSchedules.Single(a => a.Id == item.ProductionOrderWorkScheduleId); if (task == MrpTask.None) { var schedule = new SimulationWorkschedule() { ParentId = JsonConvert.SerializeObject(from parent in _context.GetParents(pows) select parent.Id), ProductionOrderId = "[" + po.Id.ToString() + "]", Article = po.Article.Name, DueTime = po.Duetime, End = pows.EndSimulation, EstimatedEnd = pows.End, EstimatedStart = pows.Start, HierarchyNumber = pows.HierarchyNumber, Machine = pows.MachineId == null ? null : _context.Machines.Single(a => a.Id == pows.MachineId).Name, Start = pows.StartSimulation, OrderId = JsonConvert.SerializeObject(_context.GetOrderIdsFromProductionOrder(po)), SimulationConfigurationId = simulationId, WorkScheduleId = pows.Id.ToString(), WorkScheduleName = pows.Name, SimulationType = SimulationType.Central, SimulationNumber = simulationNumber, }; _context.Add(schedule); //_evaluationContext.Add(schedule.CopyDbPropertiesWithoutId()); } if (task == MrpTask.Backward || task == MrpTask.All) { var backward = new SimulationWorkschedule() { ParentId = JsonConvert.SerializeObject(from parent in _context.GetParents(pows) select parent.ProductionOrderId), ProductionOrderId = "[" + po.Id.ToString() + "]", Article = po.Article.Name, DueTime = po.Duetime, End = pows.EndBackward, HierarchyNumber = pows.HierarchyNumber, Start = pows.StartBackward, OrderId = JsonConvert.SerializeObject(_context.GetOrderIdsFromProductionOrder(po)), SimulationConfigurationId = simulationId, WorkScheduleId = pows.Id.ToString(), WorkScheduleName = pows.Name, SimulationType = SimulationType.BackwardPlanning, SimulationNumber = simulationNumber, Machine = pows.MachineGroupId.ToString() }; _context.Add(backward); _evaluationContext.Add(backward.CopyDbPropertiesWithoutId()); } if (task == MrpTask.Forward || task == MrpTask.All) { var forward = new SimulationWorkschedule() { ParentId = JsonConvert.SerializeObject(from parent in _context.GetParents(pows) select parent.ProductionOrderId), ProductionOrderId = "[" + po.Id.ToString() + "]", Article = po.Article.Name, DueTime = po.Duetime, End = pows.EndForward, HierarchyNumber = pows.HierarchyNumber, Start = pows.StartForward, OrderId = JsonConvert.SerializeObject(_context.GetOrderIdsFromProductionOrder(po)), SimulationConfigurationId = simulationId, WorkScheduleId = pows.Id.ToString(), WorkScheduleName = pows.Name, SimulationType = SimulationType.ForwardPlanning, SimulationNumber = simulationNumber, Machine = pows.MachineGroupId.ToString() }; _context.Add(forward); _evaluationContext.Add(forward.CopyDbPropertiesWithoutId()); } } _context.SaveChanges(); _evaluationContext.SaveChanges(); }