• Keine Ergebnisse gefunden

Simulation kontinuierlicher Materialflüsse

Ebene 1 - Materialfluß

5.8 Implementierung

5.8.1 Rezepte

voneinander sind, wird für jede Restriktion ein Zeitpunkttogundtug er-mittelt, um anschließend das Minimum aus beiden alstg=min(tog,tug)zu bestimmen. Für jede Grenze ergibt sich durch Umformungf(tg)C=0, die Suche nach den Nullstellen einer Funktion. Da eine Funktion keine, eine oder mehrere Nullstellen besitzen kann, gilt folgende Definition:

Definition 7(Berechnung vontg). Ein Grenzzustand ist an der kleinsten Stelle tgR+0 erreicht, an dem die Netto-Materialflußfunktion den Wert f(tg) =C (Grenzwert) annimmt und die keinen Extremwert (Minimum oder Maximum) darstellt. Findet sich kein t, daß diese Bedingungen erfüllt, so wird der Grenzzustand bei tg= +∞erreicht.

fokussiert ist. Auch hier kann das Grundrezept in Teilgrundrezepte unterteilt werden. Ein Teilgrundrezept ist im Gegensatz zum Teilur-rezept an eine einzige Anlage gebunden. Somit kann ein TeilurTeilur-rezept in mehrere Teilgrundrezepte überführt werden. Einen Schritt weiter geht das Steuerrezept, da es bereits die konkreten Anweisungen für eine bestimmte Anlage enthält, auf der ein Los (eine Charge) herge-stellt werden soll. Ein Steuerrezept kann somit nach der Zuordnung der Anlagen und der Berücksichtigung der Anlageneigenschaften aus dem Grundrezept hergeleitet werden. Eine detaillierte Darstellung der mit den Rezepten verbundenen Datenstrukturen findet sich in Loos (1997, S. 186).

Die wesentlichen Elemente eines Rezeptes innerhalb der Simulation sind:

• eine systemweit eindeutige ID

• eine fest zugeordnete Ressource, für die dieses Rezept gültig ist

• eine Menge an eingehenden Rezeptbestandteilen (Inputfaktoren)

• eine Menge an ausgehenden Rezeptbestandteilen (Outputfakto-ren)

• ein Referenzbestandteil aus der Menge der ausgehenden Bestand-teile, der das Verhalten bei den Mengenberechnungen des Rezep-tes definiert.

Die Richtung der Rezeptbestandteile ist definiert im Bezug auf die Ressource, für die das Rezept gültig ist. Jeder Rezeptbestandteil ent-spricht einem kontinuierlichen oder diskreten Materialfluß, der auf einer Kante stattfindet. Jede Kante kann mehrere Materialflüsse beinhal-ten, wenn diese den gleichen Baustein als Quelle oder als Ziel besitzen.

DieRecipeSchnittstelle stellt ein Teilsteuerrezept dar, da es für eine einzige Anlage definiert ist und eine Menge an Input- und Output-faktoren besitzt. Im Gegensatz zu einem vollständigen Steuerrezept beinhaltet sie jedoch keine Anweisungen, wie lange die Fertigung auf dieser Anlage zu laufen hat oder welche Menge gefertigt werden soll.

Diese Information muß von einer übergeordneten Ebene kommen, da diese Ebene keine Planungsaufgaben übernimmt. Ein Rezept besitzt einen einzigen internen Zustand, so daß es keiner zeitlichen Verän-derung unterworfen ist. Es ist vollkommen unabhängig von äußeren Einflüssen. Wenn z. B. ein Rezept nach einem anderen nicht ausgeführt werden kann, so ist dies keine Entscheidung, die auf dieser Ebene getroffen wird. Die darüberliegende Planungsebene entscheidet dies aufgrund der Eigenschaften der Maschinen.

Flußfunktion - FlowFunction

Zur mathematischen Repräsentation von kontinuierlichen Produktions-prozessen wurde die Materialflußfunktion eingeführt (vgl. Abschnitt 5.4.2). Die Standard-Losgrößenmodelle beschränken diese auf eine lineare Funktion, welche für zukünftige Anwendungen zu restriktiv ist.

Daher wird als Erweiterung die Materialflußfunktion als ein Polynom n-ten Grades implementiert. Der Definitionsbereich der Materialfluß-funktion und des Polynoms stimmen überein, so daß abschnittsweise definierte Funktionen nicht unterstützt werden. Die Beschränkung auf Funktionen, die auf einem einzigen Intervall definiert sind, erfolgt allein aufgrund der Komplexität der Berechnungen. Diese steigen mit jedem zusätzlichen Intervall, so daß diese Option vorerst nicht implementiert wurde.

Durch den Einsatz von Polynomen n-ten Grades ist es möglich, daß nicht polynomial darstellbare Materialflüsse durch eine Taylor-Reihe (Bronstein u. a. 1999, Kap. 6.1.4.5) innerhalb des zu betrachtenden In-tervalls mit der geforderten Genauigkeit approximiert werden können.

Die Implementierung der Polynome erfolgt über eine Standardbi-bliothek. Eingesetzt wird hier die Bibliothek JScience (Dautelle 2007), da sie speziell für Polynome bereits sehr viele Funktionen bereitstellt.

Abbildung 5.13 auf der folgenden Seite stellt die Schnittstellendefini-tion der Klasse vor. Diese enthält bereits Elemente wie Variablen und Terme, die von der Repräsentation der Polynome in JScience abhän-gig sind. Da diese Repräsentation jedoch generisch ist und sehr gut wiederverwendet werden kann, stellt dies keine Einschränkung dar.

FlowFunction FlowFunction.linearTerm : Term FlowFunction.nullTerm : Term

FlowFunction.ROOT_TOLERANCE : double time : Variable<Real>

ZERO : FlowFunction

flowPolynomial : Polynomial<Real>

FlowFunction.createConstantSlopeFlow(double) : FlowFunction FlowFunction.createPolynomial(double, double...) : FlowFunction FlowFunction.createZeroSlopeFlow(double) : FlowFunction FlowFunction(Polynomial<Real>)

add(double) : FlowFunction add(FlowFunction) : FlowFunction calculateNextPositiveZero() : double evaluate(double) : double

getPolynomial() : Polynomial<Real>

minus(double) : FlowFunction minus(FlowFunction) : FlowFunction negate() : FlowFunction

-+ + -+ + + -+ + + + + + + +

Abbildung 5.13: UML-KlassendiagrammFlowFunction

Die Klasse wurde so implementiert, daß sie einem Value-Objekt entspricht (vgl. Abschnitt 4.3 auf Seite 84). Alle mathematischen Ope-rationen, die für diese Klasse zulässig sind, geben eine neue Instanz vonFlowFunctionzurück. Eingesetzt werden sie für die Berechnung der Netto-Materialflußfunktion vonStreamClearing.

Eine wichtige Funktion ist die Bestimmung der kleinsten positiven Nullstellen zur Berechnung des nächsten Grenzzustandes (vgl. Abschnitt 5.7.2). Da es zur Berechnung der Nullstellen von Polynomenn-ten Gra-des mitn5keine allgemeine analytische Lösung gibt (Bronstein u. a.

1999, Kap. 1.6.2.5), muß auf ein numerisches Verfahren zurückgegrif-fen werden. Geeignete Algorithmen sind das Graeffe-Verfahren, die Methode von Bernoulli oder die Methode von Bairstow (Bronstein u. a.

2003, Kap. 7.4.3). Alternativ zu diesen Verfahren kann auch die Eigen-wertmethode (Bronstein u. a. 2003, Kap. 7.4.3.3) eingesetzt werden.

Die Berechnung der Nullstellen des Polynoms wird in ein

Eigenwertpro-blem übertragen, indem das Polynom als charakteristisches Polynom einer entsprechenden Matrix angesehen wird. Für die Berechnung der Eigenwerte einer Matrix gibt es numerische Algorithmen, die in Stan-dardbibliotheken implementiert sind. Im Gegensatz zu den anderen Verfahren, muß das Problem nur in eine andere Repräsentation über-führt werden. Zur Berechnung der Eigenwerte wird die Colt-Library des CERN (CERN 2004) eingesetzt, da diese Bibliothek ausgereift ist und gut erprobte numerischen Algorithmen verwendet.

Bei der Berechnung der Nullstellen eines Polynoms n-ten Grades ist zu beachten, daß jedes Polynomn-ten GradesnNullstellen besitzt (Bronstein u. a. 1999, Kap. 1.6.3). Da die Koeffizienten der Flußfunktion aus dem Bereich der reellen ZahlenRstammen, können die Wurzeln sowohl reelle ,als auch komplexe Werte annehmen. Definition 7 auf Seite 143 schränkt die gültigen Werte auf die positiven reellen Wurzeln ein. Die Eigenwertmethode gibt reelle und komplexe Wurzeln zurück, so daß die komplexen und negativen reellen Wurzeln vor der weiteren Verarbeitung aussortiert werden.

Als letztes muß bei jeder positiven reellen Wurzel überprüft werden, ob es sich um einen Extrempunkt handelt, der nicht zu beachten ist.

Die Entscheidung wird anhand folgenden Satzes getroffen (Bronstein u. a. 1999, S. 385):

„Ist die Ordnung der Ableitung, die an der Stelle t=tgerstmalig nicht verschwindet, gerade, dann besitzt f(t) dort ein relatives Ex-tremum: für einen negativen Wert ein relatives Maximum, für einen Positiven ein relatives Minimum. Ist die Ordnung dieser Ableitung un-gerade, dann besitzt die Funktion an dieser Stelle keinen Extremwert, sondern einen Wendepunkt.“

Voraussetzung für die Anwendung dieses Satzes ist die Differen-zierbarkeit der Funktionf(t). Da die Flußfunktionen durch Polynome dargestellt werden, ist die Differenzierbarkeit immer gegeben (Bron-stein u. a. 1999, S. 374). Alle Anforderungen von Definition 7 konnten somit durch den Einsatz von Standardbibliotheken umgesetzt werden.

RecipeItem coefficient : double

direction : FlowDirection function : FlowFunction hash : int

product : ProductID type : FlowType

RecipeItem.createContinuousInput(ProductID, FlowFunction) : RecipeItem RecipeItem.createContinuousOutput(ProductID, FlowFunction) : RecipeItem RecipeItem.createDiscreteInput(ProductID, double) : RecipeItem

RecipeItem.createDiscreteOutput(ProductID, double) : RecipeItem

RecipeItem(FlowDirection, ProductID, coefficient, FlowType, FlowFunction) equals(Object) : boolean

getCoefficient() : double getDirection() : FlowDirection getFunction() : FlowFunction getProductID() : ProductID getType() : FlowType isContinuous() : boolean isDiscrete() : boolean isInput() : boolean isOutput() : boolean

-+ + + + -+ + + + + + + + + +

Abbildung 5.14: UML-KlassendiagrammRecipeItem

Rezeptbestandteile - RecipeItem

Die Input- und Outputfaktoren, aus denen ein Rezept besteht, werden durch die KlasseRecipeItemimplementiert. Das Klassendiagramm auf dieser Seite stellt die Struktur der Klasse dar. Das Design entspricht einem Value-Objekt (vgl. Abschnitt 4.3 auf Seite 84). Dadurch ist es möglich, daß die Instanzen von unterschiedlichen Rezepten gemeinsam verwendet werden.

Die Attribute einesRecipeItemsetzen sich zusammen aus dem Pro-dukt, der Flußrichtung bezogen auf den aktiven Baustein, dem Flußtyp (diskret oder kontinuierlich), sowie der Flußfunktion und dem Pro-duktionskoeffizienten. Die beiden letzten Attribute werden je nach Flußtyp belegt und können auch den Wertnullenthalten. Es werden entsprechende Methoden bereitgestellt, um Flußtyp und Flußrichtung

abzufragen. Flußtyp und Flußrichtung sind in Java als öffentlich zu-gänglich Klasse vom TypEnumdefiniert. Der Konstruktor ist nach außen nicht sichtbar und kann nur von den statischen Factory-Methoden ver-wendet werden. Diese decken alle Kombinationen aus Flußtyp und Flußrichtung ab und konfigurieren den Konstruktor für den Benutzer transparent.

Aufbau eines Rezeptes

Basierend auf den Anforderungen wurde die SchnittstelleRecipe ge-schaffen, die Methoden bereitstellt, um die benötigten Informationen zu erhalten. Als abstrakte Oberklasse implementiertAbstractRecipealle Methoden der Schnittstelle. Die Methoden zur Berechnung von Ma-terialflüssen in einem Intervall oder bis zu einem bestimmten Punkt werden zurückgeführt auf die Berechnung der Flußfunktion zu einem Zeitpunktt. Durch eine Lineartransformation werden so ausgehend vom Startzeitpunkt die Mengen berechnet. Der Startzeitpunkt ist dem Rezept nur als Parameter bekannt und wird von der Kante übergeben, auf der ein Fluß stattfindet.

Die Klasse implementiert nicht die Methoden, die zur Berechnung der diskreten Bestandteile verantwortlich sind, da diese von der Art des Hauptbestandteils abhängig sind. Das Verhalten der kontinuierlichen Bestandteile ist hingegen identisch und erfolgt inAbstractRecipe. Die Implementierung wird von zwei abgeleiteten Klassen durchgeführt, die für kontinuierliche und diskrete Hauptbestandteile das entspre-chend angepaßte Verhalten zeigen. Aus dem Klassendiagramm auf der nächsten Seite ist ersichtlich, daß die Klasse zu einem Value-Objekt entwickelt wurde (vgl. Abschnitt 4.3 auf Seite 84). Dieses Design wird auch für die davon abgeleiteten Klassen eingesetzt. Der Vorteil eines Value-Objektes zeigt sich hier in dem bei der Erzeugung definierten Zustand. Das Rezept ist von der Simulationszeit unabhängig und kann von verschiedenen Bausteinen gleichzeitig verwendet werden, sowie während der gesamten Simulationsdauer erhalten bleiben.

Die Erzeugung eines Rezeptes wird über einen Builder unterstützt, der eine öffentliche statische lokale Klasse vonAbstractRecipeist (siehe

Recipe

calculateContinuousFlowInInterval(start, from, to, RecipeItem) : double calculateContinuousFlowUntil(start, to, RecipeItem) : double

calculateDiscreteFlow(RecipeItem, mainProductQuantity) : double calculateProductionTime(quantity) : double

getId() : RecipeID

getInput() : List<RecipeItem>

getMachine() : EntityID

getOutput() : List<RecipeItem>

getProductionRate() : double getReferenceProduct() : RecipeItem +

+ + + + + + + + +

AbstractRecipe DEFAULT_RECIPE : Recipe

allItems : List<RecipeItem>

id : RecipeID

input : List<RecipeItem>

machine : EntityID

output : List<RecipeItem>

referenceProduct : RecipeItem

AbstractRecipe(RecipeItem, List<RecipeItem>, EntityID)

calculateContinuousFlowFromZero(SimTime, RecipeItem) : double calculateContinuousFlowInInterval(start, from, to, RecipeItem) : double calculateContinuousFlowUntil(start, to, RecipeItem) : double

equals(Object) : boolean getId() : RecipeID

getInput() : Collection<RecipeItem>

getMachine() : EntityID

getOutput() : Collection<RecipeItem>

getReferenceProduct() : RecipeItem hashCode() : int

isRecipeItemInList(RecipeItem) : boolean +

-# -+ + + + + + + + + +

Abbildung 5.15: UML-KlassendiagrammRecipe

auch Gamma u. a. 1995, S. 97 und Bloch 2008, S. 11). Der Builder übernimmt bei der Erstellung als zwingenden Parameter den Refe-renzbestandteil, womit der Charakter des Rezeptes festgelegt ist. Die weiteren Eigenschaften eines Rezeptes werden aus den Bestandteilen RecipeItemzusammengesetzt. Diese können diskrete oder kontinuier-liche Materialflüsse darstellen, die ggf. eineFlowFunctionbeinhalten.

Da jeder Bestandteil eines Rezeptes entweder ein elementarer Datentyp ist oder sich auf einen solchen zurückführen läßt und gleichzeitig jeder Bestandteil ein Value-Objekt ist, entspricht die KlasseAbstractRecipe ei-nem zusammengesetzten Value-Objekt (Evans 2004, S. 98). Die Vorteile dieses Designs ergeben sich aus der Rückführung auf andere elementa-re Objekte, die für sich alleine nur eine geringe Komplexität besitzen, gemeinsam jedoch eine große Flexibilität aufweisen. Die Klasse kann so alle Vorteile eines Value-Objektes nutzen, wie z. B. den Einsatz in einer Multi-Thread Umgebung. Eine Erweiterung der Testumgebung durch parallele Läufe oder eine Parallelisierung einzelner Komponenten ist für die Datenstrukturen unproblematisch, da sie inhärent „thread safe“

sind (Bloch 2008, S. 75).

Die Erzeugung einer Recipe Instanz wird nach der Konfiguration durchbuild ausgelöst. Die Methode überprüft den Flußtyp des Refe-renzbestandteils und erzeugt eine Instanz vonContinuousRecipeoder DiscreteRecipe. Beide Klassen sind nach außen nicht sichtbar, so daß für den Benutzer die Erzeugung der korrekten Instanziierung vollständig transparent verläuft. Das Verhalten der Klassen wird in den folgenden Abschnitten beschrieben.

Verhalten eines Rezeptes

Das Verhalten eines Rezeptes wird durch den bei der Initialisierung definierten Rezeptbestandteil festgelegt. Es gibt zwei Arten von Re-zeptbestandteilen: kontinuierliche und diskrete Bestandteile. Davon abgeleitet entsprechend zwei Rezeptarten, die über den Hauptbestand-teil charakterisiert sind. Abbildung 5.16 auf der nächsten Seite zeigt beide Klassen, die vonAbstractRecipeabgeleitet wurden.

AbstractRecipe

ContinuousRecipe

ContinuousRecipe(RecipeItem, List<RecipeItem>, EntityID) calculateDiscreteFlow(RecipeItem, double) : double

calculateProductionTime(double) : double getProductionRate() : double

# + + +

DiscreteRecipe rate : double

DiscreteRecipe(RecipeItem, List<RecipeItem>, double, EntityID) calculateDiscreteFlow(RecipeItem, MainProductQuantity) : double calculateProductionTime(MainProductQuantity) : double

equals(Object) : boolean getProductionRate() : double hashCode() : int

-# + + + + +

Abbildung 5.16: UML-Klassendiagramm der Nachfolger von Abstrac-tRecipe

Kontinuierliche Rezepte

Ein kontinuierliches Rezept erzeugt als Hauptprodukt einen kontinuier-lichen Materialfluß. Die Dauer der Produktion wird von einer überge-ordneten Planungsebene definiert. Damit ist auch die Produktionsdauer aller anderen kontinuierlichen Input- und Outputfaktoren bestimmt. Die Materialflüsse sind für diese Faktoren während der gesamten Produkti-onsdauer aktiv. Die Menge der erzeugten und verbrauchten Faktoren wird somit bei allen kontinuierlichen Materialflüssen allein durch die Produktionsdauer bestimmt.

Zu Beginn der Produktion wird mit Hilfe der Flußfunktion des Hauptproduktes die Produktionsdauer berechnet. Voraussetzung ist die Losgröße, die von der Planungsebene bereitgestellt wird. Diskrete Bestandteile werden hingegen unabhängig von der Produktionszeit nur einmal in der angegebenen Menge eingesetzt. Als Inputfaktor zum Beginn der Produktion und als Outputfaktor, wenn die Ressource die Produktion beendet. Ein Aufruf voncalculateDiscreteFlow wird somit immer das Attribut coefficient des RecipeItem zurückgeben. Bei der Berechnung der Produktionsdauer für eine vorgegebene Menge greift calculateProductionTimeauf die Flußfunktion des Referenzbestandteils zurück und läßt diese den Zeitpunkt berechnen, vergleichbar mit der Berechnung eines Grenzzustandes (vgl. Abschnitt 5.7.2).

Diskrete Rezepte

Ein diskretes Rezept erzeugt als Hauptprodukt am Ende der Produkti-on eine Menge, die abhängig vProdukti-on der ProduktiProdukti-onsdauer des Rezeptes ist. Die Produktionsmenge muß nicht ganzzahlig sein, sondern kann auch beliebige Bruchteile annehmen. Kontinuierliche Bestandteile wer-den während der gesamten Produktionsdauer des Rezeptes erzeugt und sind durch ihre Materialflußfunktion charakterisiert. Inputfaktoren von diskreten Bestandteilen werden zum Beginn der Produktion reser-viert, Outputfaktoren am Ende der Produktion bereitgestellt. Die Menge wird incalculateDiscreteFlowwie bei einer klassischen Stückliste durch die Mengenverhältnisse und Produktionskoeffizienten bestimmt. Da die

Mengen zum Beginn der Produktion reserviert werden, muß die Produk-tionsmenge des Hauptproduktes vorher bekannt sein. Die Information hierüber wird von der Planungsebene als Losgröße bereitgestellt. Aus der Losgröße des Hauptproduktes wird mit Hilfe der Produktionsrate einer Maschine incalculateProductionTimedie Produktionsdauer errech-net, die als Ausgangspunkt für die weiteren Berechnungen der Mengen an Input- und Outputfaktoren dient.