/**
         * Bottom-Up-Traversal
         */
        private void ValidatePredecessorOperationsTransitionTimeIsCorrect(
            IStackSet <ProductionOrderOperation> predecessorOperations,
            ProductionOrderOperation lastOperation,
            IDirectedGraph <INode> operationGraph,
            IStackSet <INode> traversedOperations)
        {
            if (predecessorOperations == null)
            {
                return;
            }

            foreach (var currentPredecessor in predecessorOperations)
            {
                if (currentPredecessor.GetType() == typeof(ProductionOrderOperation))
                {
                    ProductionOrderOperation currentOperation = currentPredecessor;
                    traversedOperations.Push(new Node(currentPredecessor));

                    // transition time MUST be before the start of Operation
                    int expectedStartBackwardLowerLimit =
                        lastOperation.GetValue().EndBackward.GetValueOrDefault() +
                        TransitionTimer.GetTransitionTimeFactor() *
                        currentOperation.GetValue().Duration;
                    int actualStartBackward = currentOperation.GetValue().StartBackward
                                              .GetValueOrDefault();
                    Assert.True(actualStartBackward >= expectedStartBackwardLowerLimit,
                                $"The transition time between the operations is not correct: " +
                                $"expectedStartBackward: {expectedStartBackwardLowerLimit}, actualStartBackward {actualStartBackward}");

                    INodes predecessorNodesRecursive =
                        operationGraph.GetPredecessorNodesRecursive(new Node(currentPredecessor));
                    if (predecessorNodesRecursive != null)
                    {
                        IStackSet <ProductionOrderOperation> newPredecessorNodes =
                            new StackSet <ProductionOrderOperation>(
                                predecessorNodesRecursive.Select(x =>
                                                                 (ProductionOrderOperation)x.GetEntity()));
                        ValidatePredecessorOperationsTransitionTimeIsCorrect(newPredecessorNodes,
                                                                             currentOperation, operationGraph, traversedOperations);
                    }
                }
                else
                {
                    throw new MrpRunException(
                              "ProductionOrderToOperationGraph should only contain productionOrders/operations.");
                }
            }
        }
Ejemplo n.º 2
0
        public string GetGraphizString(ProductionOrderBom productionOrderBom)
        {
            // Demand(CustomerOrder);20;Truck

            string graphizString;
            ProductionOrderOperation productionOrderOperation =
                productionOrderBom.GetProductionOrderOperation();

            if (productionOrderOperation != null)
            {
                T_ProductionOrderOperation tProductionOrderOperation =
                    productionOrderOperation.GetValue();
                graphizString = $"D: ProductionOrderBom;{ToGraphizString(productionOrderBom)}"
                                // + $"bs({tProductionOrderOperation.StartBackward});" +
                                // $"be({tProductionOrderOperation.EndBackward});" +
                                // $"\\nOperationName: {tProductionOrderOperation}"
                ;
            }
            else
            {
                throw new MrpRunException("Every productionOrderBom must have exact one operation.");
            }

            return(graphizString);
        }
Ejemplo n.º 3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="articleBom"></param>
        /// <param name="parentProductionOrder"></param>
        /// <param name="dbMasterDataCache"></param>
        /// <param name="quantity">of production article to produce
        /// --> is used for childs as: articleBom.Quantity * quantity</param>
        /// <param name="productionOrderOperation">use already created, null if no one was created before</param>
        /// <returns></returns>
        public static ProductionOrderBom CreateTProductionOrderBom(M_ArticleBom articleBom,
                                                                   Provider parentProductionOrder, ProductionOrderOperation productionOrderOperation,
                                                                   Quantity quantity)
        {
            T_ProductionOrderBom productionOrderBom = new T_ProductionOrderBom();

            if (quantity == null || quantity.GetValue() == 0)
            {
                throw new MrpRunException("Quantity is not set.");
            }

            productionOrderBom.Quantity = articleBom.Quantity * quantity.GetValue(); // TODO: PASCAL .GetValueOrDefault();
            productionOrderBom.ProductionOrderParent =
                (T_ProductionOrder)parentProductionOrder.ToIProvider();
            productionOrderBom.ProductionOrderParentId =
                productionOrderBom.ProductionOrderParent.Id;

            // bom is toPurchase if articleBom.Operation == null
            if (productionOrderOperation != null)
            {
                productionOrderBom.ProductionOrderOperation   = productionOrderOperation.GetValue();
                productionOrderBom.ProductionOrderOperationId =
                    productionOrderBom.ProductionOrderOperation.Id;
            }

            if (productionOrderOperation == null && articleBom.Operation != null)
            {
                productionOrderBom.ProductionOrderOperation =
                    ProductionManager.CreateProductionOrderOperation(articleBom,
                                                                     parentProductionOrder, quantity);
                productionOrderBom.ProductionOrderOperationId =
                    productionOrderBom.ProductionOrderOperation.Id;
            }


            productionOrderBom.ArticleChild   = articleBom.ArticleChild;
            productionOrderBom.ArticleChildId = articleBom.ArticleChildId;

            return(new ProductionOrderBom(productionOrderBom));
        }
Ejemplo n.º 4
0
 public string GetGraphizString(ProductionOrderOperation productionOrderOperation)
 {
     return($"Operation;{productionOrderOperation.GetId()};\\n{productionOrderOperation.GetValue().Name};\\n" +
            $"bs({productionOrderOperation.GetValue().StartBackward});" +
            $"be({productionOrderOperation.GetValue().EndBackward});");
 }
Ejemplo n.º 5
0
        public void ScheduleWithGifflerThompsonAsZaepfel(IPriorityRule priorityRule,
                                                         IDirectedGraph <INode> operationGraph)
        {
            Dictionary <Id, List <Resource> > resourcesByResourceCapabilityId =
                new Dictionary <Id, List <Resource> >();

            foreach (var resourceCapability in _dbMasterDataCache.M_ResourceCapabilityGetAll())
            {
                resourcesByResourceCapabilityId.Add(resourceCapability.GetId(),
                                                    ZppConfiguration.CacheManager.GetAggregator()
                                                    .GetResourcesByResourceCapabilityId(resourceCapability.GetId()));
            }

            // set correct idleStartTimes in resources from operations of last cycle(s)
            IDbTransactionData dbTransactionData =
                ZppConfiguration.CacheManager.GetDbTransactionData();
            IDbTransactionData dbTransactionDataArchive =
                ZppConfiguration.CacheManager.GetDbTransactionDataArchive();

            // TODO: This is a huge performance impact, consider having an T_Resource with new field IdleStartTime
            // so the following collection iterations can be skipped (Archive operations can be huge)
            CorrectIdleStartTimesOfMachines(dbTransactionData.ProductionOrderOperationGetAll(),
                                            resourcesByResourceCapabilityId);
            CorrectIdleStartTimesOfMachines(dbTransactionDataArchive.ProductionOrderOperationGetAll(),
                                            resourcesByResourceCapabilityId);


            /*
             * S: Menge der aktuell einplanbaren Arbeitsvorgänge
             * a: Menge der technologisch an erster Stelle eines Fertigungsauftrags stehenden Arbeitsvorgänge
             * N(o): Menge der technologisch direkt nachfolgenden Arbeitsoperationen von Arbeitsoperation o
             * M(o): Maschine auf der die Arbeitsoperation o durchgeführt wird
             * K: Konfliktmenge (die auf einer bestimmten Maschine gleichzeitig einplanbaren Arbeitsvorgänge)
             * p(o): Bearbeitungszeit von Arbeitsoperation o (=Duration)
             * t(o): Startzeit der Operation o (=Start)
             * d(o): Fertigstellungszeitpunkt von Arbeitsoperation o (=End)
             * d_min: Minimum der Fertigstellungszeitpunkte
             * o_min: Operation mit minimalem Fertigstellungszeitpunkt
             * o1: beliebige Operation aus K (o_dach bei Zäpfel)
             */
            IStackSet <ProductionOrderOperation> S = new StackSet <ProductionOrderOperation>();

            // Bestimme initiale Menge: S = a
            S = CreateS(operationGraph);

            // t(o) = 0 für alle o aus S
            foreach (var o in S)
            {
                int newStart = o.GetStartTimeBackward().GetValue();
                o.SetStartTime(newStart);
            }

            // while S not empty do
            while (S != null && S.Any())
            {
                int d_min = Int32.MaxValue;
                ProductionOrderOperation o_min = null;
                foreach (var o in S)
                {
                    // Berechne d(o) = t(o) + p(o) für alle o aus S
                    int newEnd = o.GetStartTime() + o.GetValue().Duration;
                    o.SetEndTime(newEnd);
                    // Bestimme d_min = min{ d(o) | o aus S }
                    if (o.GetEndTime() < d_min)
                    {
                        d_min = o.GetEndTime();
                        o_min = o;
                    }
                }

                // Bilde Konfliktmenge K = { o | o aus S UND M(o) == M(o_min) UND t(o) < d_min }
                IStackSet <ProductionOrderOperation> K = new StackSet <ProductionOrderOperation>();
                foreach (var o in S)
                {
                    if (o.GetValue().ResourceCapabilityId.Equals(o_min.GetValue().ResourceCapabilityId) &&
                        o.GetStartTime() < d_min)
                    {
                        K.Push(o);
                    }
                }

                // while K not empty do
                if (K.Any())
                {
                    // Entnehme Operation mit höchster Prio (o1) aus K und plane auf nächster freier Resource ein

                    List <ProductionOrderOperation> allO1 = new List <ProductionOrderOperation>();

                    foreach (var machine in resourcesByResourceCapabilityId[o_min.GetResourceCapabilityId()]
                             .OrderBy(x => x.GetIdleStartTime().GetValue()))
                    {
                        if (K.Any() == false)
                        {
                            break;
                        }

                        ProductionOrderOperation o1 = null;
                        o1 = priorityRule.GetHighestPriorityOperation(machine.GetIdleStartTime(),
                                                                      K.GetAll());
                        if (o1 == null)
                        {
                            throw new MrpRunException("This is not possible if K.Any() is true.");
                        }

                        allO1.Add(o1);

                        K.Remove(o1);

                        o1.SetMachine(machine);
                        // correct op's start time if resource's idleTime is later
                        if (machine.GetIdleStartTime().GetValue() > o1.GetStartTime())
                        {
                            int newStart = machine.GetIdleStartTime().GetValue();
                            o1.SetStartTime(newStart);
                            int newEnd = o1.GetStartTime() + o1.GetValue().Duration;
                            o1.SetEndTime(newEnd);
                        }

                        // correct op's start time if op's material is later available
                        DueTime dueTimeOfOperationMaterial = o1.GetEarliestPossibleStartTime();
                        if (dueTimeOfOperationMaterial.GetValue() > o1.GetStartTime())
                        {
                            int newStart = dueTimeOfOperationMaterial.GetValue();
                            o1.SetStartTime(newStart);
                            int newEnd = o1.GetStartTime() + o1.GetValue().Duration;
                            o1.SetEndTime(newEnd);
                        }

                        machine.SetIdleStartTime(new DueTime(o1.GetEndTime()));
                    }


                    // t(o) = d(letzte o1 aus allO1) für alle o aus K (ohne alle o1)
                    foreach (var o in K)
                    {
                        o.SetStartTime(allO1[allO1.Count - 1].GetEndTime());
                    }

                    /*if N(o1) not empty then
                     *  S = S vereinigt N(o1) ohne alle o1
                     */
                    foreach (var o1 in allO1)
                    {
                        INode o1AsNode = new Node(o1);

                        INodes allPredecessorsRecursive =
                            operationGraph.GetPredecessorNodesRecursive(o1AsNode);
                        if (allPredecessorsRecursive != null)
                        {
                            IStackSet <ProductionOrderOperation> N =
                                new StackSet <ProductionOrderOperation>(
                                    allPredecessorsRecursive.Select(x =>
                                                                    (ProductionOrderOperation)x.GetEntity()));

                            // t(o) = d(o1) für alle o aus N(o1)
                            foreach (var n in N)
                            {
                                n.SetStartTime(o1.GetEndTime());
                            }
                        }

                        // prepare for next round
                        operationGraph.RemoveNode(o1AsNode, true);
                    }

                    S = CreateS(operationGraph);
                }
            }
        }