Analyse des Lattice-Boltzmann-Verfahrens auf der CellBE-Architektur

Analyse des Lattice-Boltzmann-Verfahrens auf der CellBE-Architektur Studienarbeit im Fach Informatik vorgelegt von Dimitrij Kotrev geb. 17.08.1983 i...
0 downloads 1 Views 1MB Size
Analyse des Lattice-Boltzmann-Verfahrens auf der CellBE-Architektur Studienarbeit im Fach Informatik

vorgelegt von

Dimitrij Kotrev geb. 17.08.1983 in Charkow, Ukraine

angefertigt am

Department Informatik Lehrstuhl f¨ ur Informatik 2 Programmiersysteme Friedrich-Alexander-Universit¨ at Erlangen–N¨ urnberg (Prof. Dr. M. Philippsen)

Betreuer: Dipl. Inf. Tobias Werth, Prof. Dr. Michael Philippsen

Beginn der Arbeit: 19.01.2009 Abgabe der Arbeit: 19.10.2009

Ich versichere, dass ich die Arbeit ohne fremde Hilfe und ohne Benutzung anderer als der angegebenen Quellen angefertigt habe und dass die Arbeit in gleicher oder ¨ahnlicher Form noch keiner anderen Pr¨ ufungsbeh¨orde vorgelegen hat und von dieser als Teil einer Pr¨ ufungsleistung angenommen wurde. Alle Ausf¨ uhrungen, die w¨ortlich oder sinngem¨aß u bernommen wurden, sind als solche gekennzeichnet. ¨

Der Universit¨at Erlangen-N¨ urnberg, vertreten durch die Informatik 2 (Programmiersysteme), wird f¨ ur Zwecke der Forschung und Lehre ein einfaches, kostenloses, zeitlich und o¨rtlich unbeschr¨anktes Nutzungsrecht an den Arbeitsergebnissen der Studienarbeit einschließlich etwaiger Schutzrechte und Urheberrechte einger¨aumt.

Erlangen, den 19.10.2009

Dimitrij Kotrev

Studienarbeit Thema: Analyse des Lattice-Boltzmann-Verfahrens auf der CellBE-Architektur Hintergrund: Sony, Toshiba und IBM haben mit dem Cell-Prozessor eine heterogene Mehrkern-Architektur vorgestellt, die die Rechenleistung heutiger PC-Prozessoren bei Weitem u ¨bertrifft. Dabei unterliegen die einzelnen Kerne verschiedenen Einschr¨ankungen und Anforderungen. Beispiele daf¨ ur sind der begrenzte Speicherbereich (Local Store) und die Synchronisierung der Arbeit auf den parallel arbeitenden Kernen (SPUs). Das Lattice-Boltzmann-Verfahren ist ein diskretes Verfahren zur Ann¨aherung der Navier-Stokes-Gleichung in der Str¨omungssimulation. Dabei wird auf einem Gitter eine beschr¨ankte Zahl an Partikeln simuliert und das Verhalten des Flusses durch Str¨omung und Kollision nachgeahmt. Diese Partikel interagieren mit den Partikeln der umgebenden Zellen, so dass bei einer Parallelisierung des rechenintensiven Verfahrens relativ wenige Datenabh¨angigkeiten entstehen. Aufgabenstellung: Im Rahmen der Arbeit sollen die entsprechenden Datenabh¨angigkeiten und Flaschenh¨alse des Lattice-Boltzmann-Verfahrens mit verschiedenen Randbedingungen und unterschiedlicher Dimensionszahl untersucht werden. Dabei soll analysiert werden, welche Informationen durch den Kontext der Anwendung bekannt sind und ¨ dem Ubersetzer mitgeteilt werden k¨onnen. Aus den Analysen soll eine Spracherweiterung f¨ ur den Kontext des Lattice-BoltzmannVerfahrens (und ¨ahnlicher strukturierter Algorithmen) entworfen und implementiert werden. Bei der Implementierung soll auf ein bestehendes Compiler-Framework aufgesetzt werden. Meilensteine: • Einarbeitung in die CellBE-Architektur und in die vorhandene Infrastruktur • Einarbeitung in das Lattice-Boltzmann-Verfahren • Analyse der Datenabh¨angigkeiten bei Betrachtung mehrerer Gittermodelle • Auswahl eines geeigneten Compiler-Frameworks [5,6,7] • Implementierung der Spracherweiterung • Ausarbeitung

Literatur: 1. Kahle, J. A., Day, M. N., Hofstee, H. P., Johns, C. R., Maeurer, T. R., and Shippy, D.: Introduction to the cell multiprocessor. In IBM Journal of Research and Development 49, 4/5 pages 589-604, July 2005. 2. Eichenberger, A. E., O’Brien, K., O’Brien, K., Wu, P., Chen, T., Oden, P. H., Prener, D. A., Shepherd, J. C., So, B., Sura, Z., Wang, A., Zhang, T., Zhao, P., and Gschwind, M.: Optimizing Compiler for the CELL Processor. In Proceedings of the 14th international Conference on Parallel Architectures and Compilation Techniques., IEEE Computer Society, Washington, DC, USA, pages 161-172, September 2005. 3. Bellens, P., Perez, J. M., Badia, R. M., and Labarta, J.: CellSs: a programming model for the cell BE architecture. In Proceedings of the 2006 ACM/IEEE Conference on Supercomputing, ACM, New York, NY, USA, November 2006. 4. IBM. Cell Broadband Engine resource center, http://www-128.ibm.com/developerworks/power/cell/ 5. Lattner, C., Adve, V.: The LLVM Compiler Framework and Infrastructure Tutorial, In Languages and Compilers for High Performance Computing., Springer, Berlin, Germany, 2005 6. Quinlan, D., Ur, S., Vuduc, R.: An Extensible Open-Source Compiler Infrastructure for Testing, In Hardware and Software, Verification and Testing., Springer, Berlin, Germany, 2006 7. Weigand, U.: Porting the GNU Tool Chain to the Cell Architecture, In Proceedings of the GCC Developers’ Summit., Ottawa, ON, Canada, June 2005 Betreuung: Dipl.-Inf. T. Werth, Prof. Dr. M. Philippsen Bearbeiter: Dimitrij Kotrev

Kurzzusammenfassung Cell Broadband Engine, ein von Sony, Toshiba und IBM entwickelter Prozessor, zeichnet sich durch seine hohe Leistung und Energieeffizienz aus. Seine heterogene Architektur macht es dem Programmierer und Compiler nicht leicht diese Leistung voll auszusch¨opfen. Acht Rechenkerne und ein SIMD-Befehlssatz eignen sich sehr gut f¨ ur parallelisierbare und rechenintensive Probleme, wie das Lattice-Boltzmann-Verfahren (LBM). Das LBM ist ein Verfahren zu Simulation von Fluiden. Im Rahmen dieser Arbeit wird untersucht, wie man die Programmierung des LBM auf dem Cell-Prozessor einfacher gestalten kann. Dazu wurde OpenLB, ein Framework zur Programmierung von Lattice-Boltzmann-Simulationen, f¨ ur den Cell-Prozessor angepasst. Die Programmiersprache C++, in der das Framework entwickelt wurde, wurde f¨ ur die Portierung beibehalten um weiterhin objekt-orientiert und modular programmieren zu k¨onnen. Es wurden Algorithmen f¨ ur den 2D- und 3D-Fall entwickelt, sowie weitere Konzepte, die z.B. das Programmieren mit dem SIMD-Befehlssatz erleichtern, umgesetzt. Sowohl im Hinblick auf die Bedienbarkeit, als auch die erzielte Leistung des portierten Frameworks konnten gute Ergebnisse erzielt werden.

i

ii

Inhaltsverzeichnis 1

Einleitung 1.1 1.2

2

3

4.2 4.3 4.4

5

19

Collide-Schritt auf der SPE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .19 4.1.1 Typinformationen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .20 4.1.2 Objekt-Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 Stream-Schritt auf der SPE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 Partitionierung des Gitters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 Algorithmen zu Abarbeitung des Gitters. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23 4.4.1 2D-Collide-Stream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 4.4.2 3D-Collide-Stream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 4.4.3 Stream-Schritt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 4.4.4 Behandlung großer Zeilen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

Implementierung 5.1 5.2 5.3 5.4 5.5

13

Lattice-Boltzmann-Verfahren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 OpenLB. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14

Entwurf 4.1

3

Probleme moderner Prozessoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Cell Broadband Engine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Programmieren auf der Cell/B.E. Architektur . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

Einf¨ uhrung in das Lattice-Boltzmann-Verfahren 3.1 3.2

4

Verwandte Arbeiten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Aufbau der Arbeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

Cell Broadband Engine Architecture 2.1 2.2 2.3

1

29

Grundlegende Vorbereitungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Reduzierung der Codegr¨osse auf der SPE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Ausrichtung und Gr¨oße der Objekte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Verwendung des Objekt-Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Initialisierung der kopierten Objekte. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .31

iii

Inhaltsverzeichnis 5.6 5.7

6

Ergebnisse 6.1 6.2 6.3

7

iv

Vektorisierung. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .32 Weitere Optimierungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 37

Vorbereitungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 Beispiel: cylinder2d. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .37 Beispiel: bstep3d . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

Zusammenfassung und Ausblick

45

Abbildungsverzeichnis 2.1 2.2 2.3 2.4 2.5

Aufbau des Cell/B.E. Prozessors [14] . . . . . . . . . . . . Synergistic Processor Element (SPE) [14] . . . . . . . . . Erstellungsprozess einer Cell/B.E. ausf¨ uhrbaren Datei [18] Double-Buffering . . . . . . . . . . . . . . . . . . . . . . . SIMD Addition [14] . . . . . . . . . . . . . . . . . . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

4 5 7 10 10

3.1 3.2 3.3 3.4

D2Q9 Modell . . . . . . . . . . . . . . . . . . . . . . . . . . . D3Q15 Modell (links) und D3Q27 Modell (rechts) [16] . . . . D3Q19 Modell [16] . . . . . . . . . . . . . . . . . . . . . . . . Vereinfachtes UML-Diagramm der relevanten OpenLB Klassen

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

14 14 15 16

4.1 4.2 4.3 4.4 4.5 4.6 4.7

Typinformationen f¨ ur Dynamics und Momenta Objekte Stream-Abh¨angigkeiten im D2Q9 Modell . . . . . . . . Stream Abh¨angigkeiten im D3Q27 Modell . . . . . . . Aufteilung eines 9x9 Gitters in drei Bl¨ocke . . . . . . . 2D Collide-Stream . . . . . . . . . . . . . . . . . . . . 3D Collide-Stream . . . . . . . . . . . . . . . . . . . . Behandlung grosser Zeilen . . . . . . . . . . . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

20 21 22 22 24 26 27

5.1

Vektorisierung: Arbeit [16] (Oben) und Implementierung dieser Arbeit (Unten) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

33

cylinder2d, 336x64, 1000 Iterationen . . . . . . . . . . . . . . . . . . . . Messung: cylinder2d, 336x64, 1000 Iterationen . . . . . . . . . . . . . . . Messung: cylinder2d, 720x720, 1000 Iterationen . . . . . . . . . . . . . . Speedup: cylinder2d, 336x64, 1000 Iterationen . . . . . . . . . . . . . . . bstep3d, 100 Schritte (Oben), 500 Schritte (Mitte), 1000 Schritte (Unten) bstep3d: Relative Laufzeiten . . . . . . . . . . . . . . . . . . . . . . . . . bstep3d: Speedup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . MLUPS Ergenisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

38 38 39 40 41 41 42 43

6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8

. . . . . . .

. . . . . . .

. . . . .

. . . . . . .

. . . . . . .

v

Abbildungsverzeichnis

vi

Tabellenverzeichnis 2.1

SIMD-Intrinsics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10

4.1

Stream-Abh¨angigkeiten im D3Q27-Modell . . . . . . . . . . . . . . . . .

21

6.1

bstep3d: Gemessene Laufzeiten in Sekunden . . . . . . . . . . . . . . . .

40

vii

Tabellenverzeichnis

viii

Algorithmenverzeichnis 2.1 2.2 2.3

DaCS: PPE Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . DaCS: SPE Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Vektor-Addition mit SIMD-Intrinsics in C . . . . . . . . . . . . . . . . .

8 9 11

3.1 3.2

collideAndStream() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . bulkCollideAndStream() . . . . . . . . . . . . . . . . . . . . . . . . . . .

16 17

4.1

2D Collide-Stream-Schritt . . . . . . . . . . . . . . . . . . . . . . . . . .

25

5.1 5.2 5.3 5.4 5.5

Verwendung des Objekt-Cache in Cell::collide() . . . . placement new Operator . . . . . . . . . . . . . . . . . Ausschnitt aus der Implementierung der Klasse Vector Nicht vektorisierte Berechnung . . . . . . . . . . . . . Vektorisierte Berechnung . . . . . . . . . . . . . . . . .

31 31 34 35 35

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

ix

Algorithmenverzeichnis

x

1 Einleitung Hochkomplizierte Multimediaanwendungen, aufwendige Spiele und rechenintensive Forschungsaufgaben erfordern heute immer leistungsf¨ahigere Rechenmaschinen. Vor allem stellt es die Prozessorhersteller vor neue Herausforderungen. Denn die Prozessorentwicklung st¨osst an Grenzen, die eine weitere Entwicklung mit herk¨ommlichen Techniken nicht mehr rentabel machen. Daher m¨ ussen neue Konzepte entwickelt werden. Cell Broadband Engine (Cell/B.E.) ein neuer Prozessor, welcher von Sony, Toshiba und IBM entwickelt wurde, soll eine hohe Performanz bieten und zugleich energieeffizienter sein als die heutigen Prozessoren. Seine Leistung soll vor allem bei sehr rechenintensiven Anwendungen aus Forschung und Unterhaltung zum Vorschein treten. Ein innovatives Designkonzept zeichnet diesen Prozessor. Es ist ein Mehrkern-Prozessor, wie viele andere auf dem heutigen Markt, mit dem Unterschied, dass die Kerne heterogen aufgebaut sind und f¨ ur unterschiedliche Aufgaben gedacht sind. Aus insgesamt neun Kernen, dient ein Kern haupts¨achlich der Ausf¨ uhrung eines Betriebssystems und der Hauptanwendung. Die anderen acht sind mehr f¨ ur aufwendige Berechnungen konzipiert und bieten unter anderem die M¨oglichkeit mit Vektoren zu rechnen und zwei Befehls-Pipelines um zwei Befehle gleichzeitig auszuf¨ uhren. Ein wichtiges Merkmal dieser Prozessorarchitektur, liegt in der Freiheit, die sie einem bietet. Dem Programmierer wird so viel Kontrolle u ¨ber den Prozessor gegeben, wie es nur m¨oglich ist. Die Leistung einer Anwendung liegt demnach v¨ollig in der Hand des Programmierers und in der Art, wie er die St¨arken des Prozessors ausnutzt. Um einen optimalen Code zu schreiben muss der Programmierer sehr viel Wissen u ¨ber die Internas des Prozessors haben, es ist daher noch ziemlich schwierig guten Code daf¨ ur zu schreiben. Damit man die Leistung des Prozessors f¨ ur mehr Anwendungen zug¨anglicher machen kann, ist man zur Zeit in der Forschung bem¨ uht, Wege zu finden, dem Programmierer die Arbeit der Optimierung per Hand abzunehmen. Man sucht daher nach neuen CompilerTechniken und erforscht neue Programmiermodelle, um in Zukunft das volle Potenzial des Cell/B.E Prozessors bequemer nutzen zu k¨onnen. Lattice-Boltzmann-Verfahren (LBM)[8] ist eine numerische Methode zu Simulation von Fluiden. Es ist eine sehr rechenintensive Methode, aber auch hoch-parallelisierbar. Es hat somit sehr gute Voraussetzungen f¨ ur eine Analyse auf der Cell/B.E. Architektur. Ziel dieser Arbeit ist auch zu untersuchen, in wie weit man das Programmieren des Lattice-Boltzmann-Verfahrens auf dem Cell/B.E. bequemer gestalten kann.

1

1 Einleitung

1.1 Verwandte Arbeiten Im Artikel Lattice Boltzmann Simulation Optimization on Leading Multicore Platforms [20] wurde eine Lattice-Boltzmann-Anwendung auf eine Reihe von aktuellen MehrkernProzessoren portiert, unter anderem auf einen Cell-Prozessor. Der Cell-Prozessor konnte andere Systeme in puncto Leistung und Energieeffizienz bei weitem u ¨bertreffen. Diese Leistung entstand aber auf Kosten eines hohen Programmieraufwands. Lehrstuhl 10 an der Friedrich-Alexander-Universit¨at Erlangen-N¨ urnberg (FAU) befasst sich sehr intensiv mit dem Lattice-Boltzmann-Verfahren. So wurde dort LBM auf dem Cell-Prozessor genutzt um Blutgef¨aße zu simulieren. [17] Wiederum konnten gute Performanz-Resultate erzielt werden, erforderte aber viel Wissen u ¨ber den Prozessor und Handoptimierungen. Die Arbeit von Christian Kollee [16] bildet einen Ausgangspunkt f¨ ur diese Arbeit. Er portierte das OpenLB-Framework auf den Cell-Prozessor mit dem Ziel die Bedienbarkeit zu erleichtern, was ihm nur bedingt gelungen ist. Einige seiner Konzepte wurden dennoch aufgegriffen und verbessert. OpenLB [3] ist ein C++ Framework mit dem sich LBM Simulation realisieren lassen. Dieses Framework wird in dieser Arbeit verwendet und wird in einem sp¨ateren Kapitel n¨aher erl¨autert. Eine Weiterentwicklung des Frameworks namens Palabos [5] ist vor kurzem erschienen und soll noch mehr erweitertbar und effizienter sein. Ein ganz anderen Ansatz verfolgt das waLBerla [9] Projekt vom Lehrstuhl 10 an der FAU. Es handelt sich dabei um einen einzelnen Lattice-Boltzmann-L¨oser f¨ ur eine große Anzahl verschiedener Anwendungen. Er zielt dabei auf physikalische Korrektheit, High Performance und eine einfache, intuitive Anwendung ab. Das Problem wird dabei u ¨ber eine Konfigurationsdatei spezifiziert, was hohe Flexibilit¨at verspricht.

1.2 Aufbau der Arbeit Kapitel 2 beschreibt n¨aher den Cell/B.E. Prozessor und geht auf dessen Programmierung ein. Kapitel 3 f¨ uhrt in das Lattice-Boltzmann-Verfahren ein und stellt OpenLB vor, ein Framework zur Erstellung von Simulationen mit dem Lattice-Boltzmann-Verfahren. Kapitel 4 beschreibt ein Konzept, wie man OpenLB auf den Cell/B.E. portieren kann. In Kapitel 5 werden die Implementierungsdetails erl¨autert. Resultate und Testergebnisse werden im Kapitel 6 pr¨asentiert. Im letzten Kapitel wird eine Zusammenfassung der Arbeit und ein Ausblick auf weitere Entwicklungen gegeben.

2

2 Cell Broadband Engine Architecture Cell Broadband Engine Architecture (CBEA) ist eine von Sony, Toshiba und IBM gemeinsam entwickelte Mikroprozessor Architektur. Das Ziel dieser Entwicklung war die Schaffung einer Familie von Mikroprozessoren deren Leistung die der moderner Prozessoren bei weitem u ¨bertrifft. Besonders Spiele- und Multimedia-Anwendungen sollten von dieser Architektur profitieren. [15]

2.1 Probleme moderner Prozessoren Damit CBEA Prozessoren solch eine herausragende Leistung liefern k¨onnen, wurde bei der Entwicklung versucht die drei grossen H¨ urden anzupacken, die die Leistung moderner Prozessoren stark eingrenzen. [21] Eine g¨angige Methode, um die Prozessoren zu beschleunigen, ist die Erh¨ohung der Taktrate des Prozessors. In den letzten Jahren ist die Taktrate der Prozessoren rapide gestiegen. Den Zugriff auf den Hauptspeicher konnte man aber nicht im selben Maß steigern. Die Folge ist, dass die Zugriffszeit auf den Hauptspeicher, gemessen in Prozessortakten, mit jeder neuen Prozessorgeneration immer gr¨osser wurde. Ein Zugriff auf Daten im Hauptspeicher kann heute mehrere hundert Prozessortakte kosten. Mit großen Caches und ausgefallenen Cache-Hierarchien versucht man heute diesem Problem entgegenzuwirken. Das Problem bleibt aber immer noch bestehen, denn bei einem Cachefehlzugriff muss wieder der Hauptspeicher angesprochen werden und das kostet wieder eine Menge Zeit. Die Performanz einer Anwendung h¨angt daher stark davon ab, wie sie auf Daten zugreift. [21] Um die Taktrate eines Prozessors zu erh¨ohen, geht man h¨aufig dazu u ¨ber tiefere Befehlspipelines zu implementieren, die es auch erm¨oglichen, mehr Befehle pro Prozessortakt auszuf¨ uhren. Heute sind wir an einem Zeitpunkt angelangt, an dem sich solch einer Vergr¨osserung der Befehlspipeline nicht mehr rentiert, da die Einbußen, die dadurch entstehen, sonst den Geschwindigkeitsgewinn zunichte machen. Solche Einbußen, treten auf z.B. durch falsch vorhergesagte Spr¨ unge, die ein Leeren der Pipeline veranlassen, oder Datenabh¨angigkeiten zwischen den Befehlen, die dazu f¨ uhren, dass ein Befehl in der Pipeline warten muss. [10] Durch die hohen Taktraten und immer dichtere und komplexe Transistortechnologien auf dem Prozessor geht immer mehr Leistung durch Abw¨arme verloren, so dass Leistungsteigerungen auf diesem Wege sich bald nicht mehr rentieren. Zus¨atzlich wirkt sich die hohe W¨arme negativ auf elektrische Schaltkreise aus und kann einen Prozessor sogar

3

2 Cell Broadband Engine Architecture

Abbildung 2.1: Aufbau des Cell/B.E. Prozessors [14] zerst¨oren, wenn er nicht ausreichend gek¨ uhlt wird. Daher ist es jetzt an der Zeit, neue und energieeffizientere L¨osungen f¨ ur dieses Problem zu finden. [15], [11]

2.2 Cell Broadband Engine Cell Broadband Engine (Cell/B.E.) ist die erste Implementierung der CBEA. Dieser Prozessor wird in der Sony-Spielekonsole Playstation 3 eingesetzt. Der Cell/B.E. besteht aus neun Prozessoreinheiten auf einem Chip, die alle miteinander u ¨ber den Element Interconnect Bus (EIB) verbunden sind. Die Prozessoreinheiten teilen sich in eine PowerPC Processor Element (PPE) und acht Synergistic Processor Elements (SPE) auf. Der Memory Interface Controller (MIC) verbindet den EIB mit dem Hauptspeicher. Der Cell Broadband Engine Interface (BEI) verwaltet den Datentransfer zwischen dem EIB und E/A-Ger¨aten. Abbildung 2.1 stellt eine schematische Darstellung des Cell/B.E dar. [14] Die PPE ist der Hauptprozessor, der haupts¨achlich Kontrollaufgaben u ¨bernimmt. Unter anderem f¨ uhrt er das Betriebssystem aus, verwaltet die Systemressourcen und ist auch zust¨andig f¨ ur die Erzeugung und Verwaltung der SPE Threads. Er basiert auf einem 64Bit PowerPC RISC Kern, dessen Befehlssatz um die Vector/SIMD Multimedia-Befehle erweitert wurde. Zus¨atzlich kann die PPE zwei Threads gleichzeitig ausf¨ uhren, wodurch sie mit Hilfe des Multimedia Befehlssatzes eine nicht zu vernachl¨assigende Rechenleistung bietet. [14] Besonders rechenintensive Aufgaben sollten aber die acht SPE’s u ¨bernehmen. Eine SPE ist ein 128-Bit RISC Prozessor, mit einem Single Instruction, Multiple Data (SIMD) Befehlssatz. Mit einem SIMD-Befehl ist es m¨oglich eine Operation gleichzeitig auf mehrere Daten anzuwenden. So lassen sich zum Beispiel vier Fliesskomma-Additionen mit einem Befehl durchf¨ uhren. Wie man in der Abbildung 2.2 erkennen kann, besteht die

4

2.2 Cell Broadband Engine

Abbildung 2.2: Synergistic Processor Element (SPE) [14] SPE aus einer Synergistic Processor Unit (SPU) und einem Memory Flow Controller (MFC). Die SPU ist zust¨andig f¨ ur die Befehlsausf¨ uhrung und verf¨ ugt u ¨ber 128 128-Bit Register und einen 256-KB grossen Local Store (LS). Jede SPU ist ein unabh¨angiger Prozessor und af¨ ur optimiert, um SPE-Threads, die von der PPE erzeugt werden, auszuf¨ uhren. Die SPU holt ihre Befehle aus ihrem eigenem LS. Aus dem LS werden auch die Daten geladen und dort abgespeichert. Weiterhin verf¨ ugt die SPU u ¨ber zwei Befehls-Pipelines, somit ist sie in der Lage unter Umst¨anden zwei Befehle gleichzeitig auszuf¨ uhren. Der MFC verf¨ ugt u ¨ber eine Direct Memory Access (DMA) Einheit, die Daten zwischen SPU’s LS und dem Hauptspeicher transferieren kann. Da jeder MFC im Hauptspeicher abgebildet wird, lassen sich DMA-Transfers auch von der PPE oder anderen SPE’s starten. Jeder MFC verwaltet weiterhin eine Warteschlange mit den DMA-Befehlen. Nachdem ein DMA-Befehl in die Warteschlange abgesetzt wurde, kann die SPU ihre Arbeit weiterverrichten, w¨ahrend der MFC die Befehle in der Warteschlange autonom und asynchron abarbeitet. Die unabh¨angige Ausf¨ uhrung der DMA-Befehle und der SPU Befehle erm¨oglicht es DMA-Transfers bequem einzuplanen um Speicher-Latenzzeiten zu verstecken. Bei jedem DMA Transfer k¨onnen bis zu 16KB Daten kopiert werden. Weiterhin unterst¨ utzt MFC DMA-Befehlslisten, die bis zu 2048 Transfers, jedes bis zu 16KB Gr¨osse, repr¨asentieren k¨onnen. [14], [6] Durch die Verteilung der verschiedenen Aufgabengebiete auf die PPE und die SPE Kerne, l¨asst sich die Komplexit¨at der einzelnen Kerne reduzieren. Dadurch sind wieder h¨ohere Taktraten m¨oglich und h¨ohere Energieeffizienz erreichbar. Mit Hilfe der 3-stufigen Speicherhierarchie, bestehend aus großem Registersatz, dem Local Store und dem Hauptspeicher, und dem asynchronen DMA hat der Programmierer mehr Kontrolle u ¨ber Speicherzugriffe. Durch geschickte Einplanung des Zugriffs auf den Hauptspeicher lassen sich

5

2 Cell Broadband Engine Architecture somit die Wartezeiten, die bei einem solchen Zugriff entstehen k¨onnen, minimieren und der Prozessor bleibt dabei nicht stehen und kann sinnvolle Arbeit verrichten. Ein Großteil der Leistung des Cell Prozessors kommt daher von den mehreren Stufen der Parallelisierung. Zum einem sind da die acht Kerne auf die Problem verteilt werden kann. Der SIMD Befehlssatz erm¨oglicht es eine Berechnung auf mehreren Daten gleichzeitig auszuf¨ uhren. Und die Befehls-Pipelines k¨onnen im optimalen Fall zwei Befehle gleichzeitig ausf¨ uhren. Um einen optimalen Code zu erzeugen, muss der Programmierer bzw. der Compiler alle diese Merkmale ausnutzen. Dies sei aber nicht so einfach, denn ein Problem muss genau analysiert werden. Man muss ein Weg finden es auf die mehreren Kerne zu verteilen. Daten m¨ ussen so organisiert oder zusammengefasst werden, dass man auch den SIMD-Befehlssatz nutzen kann. Der begrenzte Speicher des Local Store muss optimal genutzt werden und DMA-Transfers sollten am besten im Hintergrund ablaufen. Letztendlich m¨ ussen die Befehle so angeordnet sein, dass die beiden Befehls-Pipelines gef¨ ullt bleiben und somit der Prozessor nicht durch Wartezust¨ande ausgebremst wird.

2.3 Programmieren auf der Cell/B.E. Architektur Zum Programmieren auf der Cell/B.E. stellt IBM ein kostenloses SDK zu Verf¨ ugung. Es enth¨alt eine GNU C/C++/Fortran Toolchain, zahlreiche Bibliotheken, Programme zum Profilen und Optimieren und einen Cell Simulator. Bei den Toolchains gibt es immer zwei Versionen, eine f¨ ur die PPE und die andere f¨ ur die SPE. Die Programme f¨ ur die PPE und SPE m¨ ussen mit den entsprechenden Toolchains getrennt gebaut werden. Anschließend wird das SPE-Programm in das PPE-Programm eingebunden, wodurch es dann nur eine ausf¨ uhrbare Datei entsteht. Abbildung 2.3 veranschaulicht diesen Prozess.

DaCS Data Communication and Synchronization (DaCS)[13] ist eine Bibliothek aus dem IBM SDK, die eine bequeme Programmierung des Cell/B.E. Prozessors erlaubt. Sie bietet Funktionen zur Erzeugung, Verwaltung und Synchronisation von SPE-Threads, zur Datenkommunikation und Fehlerbehandlung. Es werden alle Kommunikationsm¨oglichkeiten des Cell/B.E. Prozessors unterst¨ utzt, unter anderem normale DMA-Transfers zwischen PPE und SPE, DMA-Listen, Messages und Mailboxes. Listings 2.1 und 2.2 zeigen eine einfache Verwendung der DaCS Bibliothek. In dem PPE-Code wird zun¨achst die Bibliothek f¨ ur die Verwendung initialisert. Dann erfolgt eine Reservierung der SPE’s. Auf einer reservierten SPE l¨asst sich dann ein Thread starten. Um DMA-Transfers durchf¨ uhren zu k¨onnen, werden die ben¨otigten Speicherbereiche zun¨achst f¨ ur den SPE-Thread bekannt gemacht. Dabei wird ein Deskriptor erzeugt, der alle n¨otigen Informationen u ¨ber ein Speicherbereich enth¨alt. Dieser

6

2.3 Programmieren auf der Cell/B.E. Architektur

Abbildung 2.3: Erstellungsprozess einer Cell/B.E. ausf¨ uhrbaren Datei [18]

wird dann an den SPE-Thread u ¨bergeben. Als n¨achstes k¨onnte der SPE-Thread Daten von und zu diesem Speicherbereich transferieren. Der PPE-Thread wartet bis der Speicherbereich wieder von dem SPE-Thread freigegeben wird und zerst¨ort anschliessend den Deskriptor. Schliesslich wartet der PPE-Thread auf die Beendigung des SPEThreads und beendet das DaCS-System. In dem SPE-Code wird als erstes auch die DaCS-Bibliothek initialisiert. Dann wird der PPE Speicherbereich f¨ ur die Verwendung auf der SPE akzeptiert. Der SPE-Thread erh¨alt somit ein Speicher-Deskriptor (memA) mit den Informationen u ¨ber den Speicherbereich auf der PPE. Dann wird ein Deskriptor f¨ ur einen SPE- Speicherbereich erzeugt (memB), welcher dann f¨ ur die Verwendung mit dem PPE-Speicherbereich assoziert wird. Ab jetzt k¨onnen DMA-Transfers zwischen diesen Speicherbereichen erfolgen. Mit dacs mem get holt der SPE-Thread Daten aus dem PPE-Speicherbereich und kopiert sie in den SPE Speicherbereich. dacs wait wartet auf die Beendigung einer DMAOperation. Mit dacs mem put lassen sich Daten wieder aus dem lokalen Speicherbereich (SPE) in den Speicherbereich der PPE kopieren. Anschließend wird die Assoziation zwischen den Speicherbereichen aufgehoben und der SPE Deskriptor zerst¨ort. dacs exit deinitialisiert das DaCS-System.

Double Buffering Double Buffering ist eine Technik, mit der man versucht, DMA-Transfers hinter einer Berechnung zu verstecken. Oder anders gesagt, man bem¨ uht sich die Wartezeiten, die entstehen k¨onnen, wenn man auf die Vollendung einer DMA-Operation warten muss, auf ein Minimum zu reduzieren. [14]

7

2 Cell Broadband Engine Architecture int main() { ... dacs_init(DACS_INIT_FLAGS_NONE); dacs_reserve_children(DACS_DE_SPE, &num_reserved, &de_list); dacs_de_start(child_de, child_app, &argv, &envv, &child_pid); dacs_mem_create(memA_addr, memA_size, remote_access, local_access, &memA); dacs_mem_share(de_B, pid_B, memA); // SPE-Thread f¨ uhrt Transfers durch dacs_mem_destroy(&memA) dacs_de_wait(child_de, child_pid, &exit_status); dacs_exit(); ... } Listing 2.1: DaCS: PPE Code Daf¨ ur braucht man generell zwei Puffer auf der SPE. In der Initialisierungsequenz werden zun¨achst zwei DMA-Befehle ausgef¨ uhrt, um die beiden Puffer mit Werten aus dem Hauptspeicher zu f¨ ullen. Danach wird gewartet, bis eins der DMA-Befehle abgeschlossen wird. Sobald dies der Fall ist, kann man mit der Berechnung auf den Daten aus dem gef¨ ullten Puffer anfangen. Ist die Berechnung durchgef¨ uhrt, dann sollte im Idealfall zu dem Zeitpunkt der zweite DMA-Befehl fertiggestellt sein und man kann weiter auf dem zweiten Puffer weiterrechnen. Zuvor sollte man, aber den ersten Puffer zur¨ uck in den Hauptspeicher schreiben und eventuell neue Daten anfordern, die wiederrum im Hintergrund der Berechnung transferiert werden. Das Muster aus abwechselnden Folgen der Anforderung von Daten, der Berechnung und dem Austauschen der Puffer wiederholt sich so weiter bis man die komplette Datenmenge bearbeitet hat. Idealerweise sollte die Berechnung l¨anger dauern als die DMA-Operationen, dann entstehen weniger Wartezeiten und die SPE verrichtet immer sinnvolle Arbeit. In Abbildung 2.4 ist der Vorgang schematisch dargestellt.

Vektorisierung Wie vorher bereits erw¨ahnt wurde, verf¨ ugt die SPE u ¨ber einen SIMD Befehlssatz. Ein SIMD Befehl f¨ uhrt eine Operation auf mehreren Daten gleichzeitig aus. SIMD Befehle arbeiten ausschließlich auf Vektoren. Vektoren sind 128-Bit breit und werden normaler-

8

2.3 Programmieren auf der Cell/B.E. Architektur int main() { ... dacs_init(DACS_INIT_FLAGS_NONE); dacs_mem_accept(de_A, pid_A, &memA); dacs_mem_create(memB_addr, memB_size, remote_access, local_access, &memB); dacs_mem_register(de_A, pid_A, memB); dacs_mem_get(memB, memB_offset, memA, memA_offset, size, widB, order, swap); dacs_wait(widB); ... // F¨ uhre Berechnungen auf den Daten dacs_mem_put(memA, memA_offset, memB, memB_offset, size, widB, order, swap); dacs_wait(widB); dacs_mem_deregister(de_A, pid_A, memB); dacs_mem_destroy(&memB); dacs_exit(); ... } Listing 2.2: DaCS: SPE Code weise in kleinere Datentypen zerteilt. Damit kann man mehrere Daten eines Datentyps in einem Vektor unterbringen. Zum Beispiel lassen sich so vier float Werte je 32-Bit darin abspeichern. Man spricht dann von einem Vektor des Datentyps float. Weitere Aufteilungen w¨aren: 16x8-Bit, 8x16-Bit und 2x64-Bit. Eine m¨ogliche SIMD Operation w¨are z.B. eine Addition zweier Vektoren gleichen Datentyps. Dabei wird jeder Wert eines Vektors mit dem korrespondierenden Wert des anderen Vektors addiert. Das Resultat ergibt wieder einen Vektor. (Abbildung 2.5) Wie man unschwer erkennen kann, w¨ urde dieser SIMD Befehl vier sequentielle Additionen ersetzen. F¨ ur die Programmierung in C/C++ werden sogennante SIMD-Intrinsics verwendet. ¨ Das sind, je nach Implementierung, Funktionen und Makros, die dann vom Ubersetzer in entsprechende SIMD-Befehle u ¨bersetzt werden. Dadurch l¨asst sich der SIMD-Befehlssatz in C/C++ nutzen, ohne dabei auf Assembler zur¨ uckgreifen zu m¨ ussen. F¨ ur die Arbeit mit den SIMD-Intrinsics wurden neue Datentypen eingef¨ uhrt. Diese entsprechen den Grunddatentypen von C, denen das Schl¨ usselwort vector vorangestellt wird. So ent-

9

2 Cell Broadband Engine Architecture

Abbildung 2.4: Double-Buffering spu add spu sub spu splats spu insert spu extract

Addition zweier Vektoren Subtraktion zweier Vektoren F¨ uhle alle Felder des Vektors mit einem Wert Setze ein Wert in einem Vektorfeld Hole ein Wert aus einem Vektorfeld Tabelle 2.1: SIMD-Intrinsics

spricht der Datentyp vector float, wie oben beschrieben, einem Vektor aus vier float Werten. In der Tabelle 2.1 sind einige der SIMD-Intrinsics aufgelistet. Das Listing 2.3 zeigt eine Vektor Addition mit Hilfe der SIMD-Intrinsics. [12] Der SIMD-Befehlssatz ist somit eine weitere Ebene der Parallelit¨at des Cell/B.E. Prozessors und man sollte versuchen, Gebrauch davon zu machen, da sonst eine Menge an Rechenpotential verloren geht.

Abbildung 2.5: SIMD Addition [14]

10

2.3 Programmieren auf der Cell/B.E. Architektur

vector float a, b, c; // Alle Felder des Vektors a werden mit dem Wert 1.0f gef¨ ullt a = spu_splats(1.0f); // Alle Felder des Vektors a werden mit dem Wert 2.0f gef¨ ullt b = spu_splats(2.0f); // Setze das erste Element im Vektor b auf den Wert 3.0f b = spu_insert(b, 0, 3.0f); // Vektor c enth¨ alt die Summe der Vektoren a und b c = spu_add(a, b); // Hole den Wert aus dem ersten Vektorfeld des Vektors c float x = spu_extract(c, 0); Listing 2.3: Vektor-Addition mit SIMD-Intrinsics in C

11

2 Cell Broadband Engine Architecture

12

3 Einfu ¨hrung in das Lattice-Boltzmann-Verfahren Dieses Kapitel soll die n¨otigen Grundlagen das Lattice-Boltzmann-Verfahrens vermitteln. Weiterhin wird das OpenLB-Framework, welches dieses Verfahren implementiert, kurz vorgestellt.

3.1 Lattice-Boltzmann-Verfahren Das Lattice-Boltzmann-Verfahren (LBM) ist eine effiziente Methode zur Simulation von Fluiden. Dabei wird der Raum durch ein Gitter diskretisiert. Ein Gitterpunkt oder auch Gitterzelle genannt, ist ein Platz f¨ ur ein fiktives Partikel. Das Gittermodell beschreibt, in welche Richtung diese Partikel im Gitter sich bewegen k¨onnen. Die Bewegungsrichtung eines Partikels wird durch eine Verteilungsfunktion beschrieben. Zu einem bestimmten Zeitpunkt wird die Bewegung der Partikel ausgef¨ uhrt, dies wird als der Stream-Schritt bezeichnet. Dabei kann ein Partikel in eine Nachbarzelle wandern oder in der Gitterzelle verbleiben. Treffen mehrere Partikel in einer Zelle ein, so kommt es zu einer Kollision. Die Kollision wird durch einen Kollisionsoperator aufgel¨ost, der die Verteilungsfunktion in der Zelle neuberechnet. Es gibt viele unterschiedliche Kollisionsmodelle f¨ ur unterschiedliche Anwendungsf¨alle, auf die hier nicht weiter eingegangen wird. Der Kollisionsoperator wird auf alle Gitterzellen angewendet um alle Kollisionen aufzul¨osen. Dieser Vorgang wird als Collide-Schritt bezeichnet. Der Collide- und Stream-Schritt werden abwechselnd auf das Gitter angewendet und definieren somit zusammen einen diskreten Zeitpunkt in der Simulation. Beide Vorg¨ange lassen sich auch zum einen Schritt zusammenfassen, um das Gitter in einem Lauf abzuarbeiten. Mit dem Lattice-Boltzmann-Verfahren lassen sich Simulationen im 2D- als auch im 3D-Raum durchf¨ uhren. Im 2D-Fall verwendet man gew¨ohnlich das D2Q9-Modell. Dabei steht D2 f¨ ur zwei Dimensionen und Q9 f¨ ur neun m¨ogliche Richtungen in denen sich ein Partikel bewegen kann. In Abbildung 3.1 wird das D2Q9 Modell grafisch dargestellt. Das Partikel kann sich dabei entlang der Koordinatenachsen (N,S,O,W) oder entlang der Diagonalen (NO, NW, SW, SO) bewegen oder in der Zelle verbleiben (C). Im 3D-Fall gibt es mehrere unterschiedliche Gittermodelle. Die drei h¨aufigsten sind D3Q15, D3Q19 und D3Q27. Das D3Q15-Modell (Abbildung 3.2) bietet eine schnelle Rechenzeit, da nur wenige Richtungen betrachtet werden m¨ ussen. Das D3Q27-Modell (Abbildung 3.2) ist im Gegensatz viel genauer und bietet somit die beste Approximation.

13

3 Einf¨ uhrung in das Lattice-Boltzmann-Verfahren

Abbildung 3.1: D2Q9 Modell

Abbildung 3.2: D3Q15 Modell (links) und D3Q27 Modell (rechts) [16] Das D3Q19 Modell stellt einen Kompromiss im Hinblick auf Rechenzeit und Genauigkeit zwischen den beiden anderen Modellen dar. F¨ ur eine tiefergehende Auseinandersetzung mit der Thematik LBM wird das Buch von Sauro Succi [19] empfohlen.

3.2 OpenLB OpenLB [3] ist ein Open-Source-Framework, mit dem sich Simulationen von Fluiden mit dem Lattice-Boltzmann-Verfahren implementieren lassen. Das Framework ist modular und objekt-orientiert aufgebaut und ist dadurch sehr flexibel, was neue Erweiterungen betrifft. Es ist aber auch sehr einfach zu bedienen, so dass einfache Simulationen ohne gro?en Aufwand erstellt werden k¨onnen. OpenLB ist in C++ implementiert und bietet somit einen hohen Grad an Portabilit¨at. Zielplattformen sind vorwiegend Systeme mit einem Prozessor, die Unterst¨ utzung von parallelen Systemen u ¨ber OpenMP [4] oder MPI wird aber auch angeboten.

14

3.2 OpenLB

Abbildung 3.3: D3Q19 Modell [16] Die Modularit¨at des Frameworks wird sowohl dynamisch als auch statisch realisiert. Zum einen ist z.B. m¨oglich, u ¨ber objekt-orientierte Schnittstellen das Verhalten der Gitterzellen zur Laufzeit abzu¨andern. Mit Hilfe der C++-Templates wird statische Gene¨ rizit¨at des Codes erm¨oglicht. Gittermodelle lassen sich somit, ohne weitere Anderungen am Code, bequem austauschen.

Aufbau des Frameworks Die Klassen BlockLattice2D und BlockLattice3D stellen einfache Gitter im 2D- bzw. 3D-Fall dar. Diese Klassen, wie die meisten anderen auch, werden durch zwei Template Parameter definiert. Der erste legt fest, welchen Datentyp alle Werte haben und ist entweder float oder double. Der zweite Parameter bestimmt das Gittermodel. Das Gitter wird durch ein Feld von Cell Objekten implementiert. Jedes Cell Objekt enth¨alt alle n¨otigen Informationen f¨ ur den Collide-Schritt. Diese Informationen werden in den Objekten der Schnittstelle Dynamics abgelegt. Alle Kollisionsmodelle implementieren diese Schnittstelle. Die Schnittstelle BasicDynamics leitet sich von Dynamics ab und stellt eine Klasse von einfachen Kollisionsmodellen dar, die bereits f¨ ur viele Zwecke ausreichend sind. Die Implementierungen von BasicDynamics verwenden ein Momenta Objekt f¨ ur die Berechnung der Verteilungsfunktion. Weiterhin wird durch die Unterklassen von Momenta die Berechnung der Verteilungsfunktion an den Randzellen und den restlichen Zellen unterschieden. Die Klasse LatticeStatistics sammelt statistische Daten u ¨ber das Gitter w¨ahrend des Collide-Schritts. Diese k¨onnen eventuell f¨ ur den n¨achsten Durchlauf verwendet werden. Das UML-Diagramm in Abbildung 3.4 verdeutlicht den Zusammenhang zwischen diesen Klassen.

15

3 Einf¨ uhrung in das Lattice-Boltzmann-Verfahren

Abbildung 3.4: Vereinfachtes UML-Diagramm der relevanten OpenLB Klassen

Die Methode collideAndStream() (Listing 3.1) der BlockLattice2D/3D Klasse f¨ uhrt einen Collide-Stream-Schritt auf dem ganzen Gitter durch. Im groben besteht dieser aus drei Phasen. Als erstes wird der Collide-Schritt auf dem Rand des Gitters durchgef¨ uhrt. Die Methode bulkCollideAndStream() l¨auft u ¨ber die restlichen Zellen und f¨ uhrt Collide-Stream auf denen aus. Die Methode boundaryStream() f¨ uhrt den StreamSchritt auf dem Gitterrand aus. Damit ist ein Collide-Stream-Schritt auf dem ganzen Gitter abgeschlossen. template void BlockLattice2D::collideAndStream( int x0, int x1, int y0, int y1) { // Collide-Schritt auf dem Gitterrand collide(x0,x0, y0,y1); collide(x1,x1, y0,y1); collide(x0+1,x1-1, y0,y0); collide(x0+1,x1-1, y1,y1); // Collide-Stream-Schritt auf dem Rest des Gitters bulkCollideAndStream(x0+1,x1-1,y0+1,y1-1); // Stream-Schritt auf dem Gitterrand boundaryStream(x0,x1,y0,y1, x0,x0,y0,y1); boundaryStream(x0,x1,y0,y1, x1,x1,y0,y1); boundaryStream(x0,x1,y0,y1, x0+1,x1-1,y0,y0); boundaryStream(x0,x1,y0,y1, x0+1,x1-1,y1,y1); } Listing 3.1: collideAndStream()

16

3.2 OpenLB Die Methode bulkCollideAndStream() (Listing 3.2) wird dazu verwendet, um auf einem Gitterblock den Collide-Stream-Schritt auszuf¨ uhren. Normalerweise ist es das ganze Gitter außer dem Gitterrand. Im Grunde l¨auft man dabei durch den Gitterblock und ruft auf jeder Gitterzelle die collide()-Methode auf. Anschließen f¨ uhrt man Stream auf dieser Zelle durch. template void BlockLattice2D::bulkCollideAndStream ( int x0, int x1, int y0, int y1 ) { for (int iX=x0; iX

Suggest Documents