Vorlesung:

Illustration: Deborah Moldawski

Nächster Zoom Link am 14.07.2022, 14:00-16:00 Uhr: ID: 794 847 5614, PWD: 785453

Die Vorlesung Einführung in die Programmierung für Studierende der Physik stellt ein Pflichtmodul im Bachelor Studium Physik der Goethe-Universität Frankfurt dar. Bei regelmäßiger und erfolgreicher Teilnahme an den Übungen/Praktika erhalten Sie eine Zulassung zur Klausur. Den benoteten Schein und sechs Creditpoints erhält man schließlich bei bestandener Klausur. Falls Sie bereits in einem vergangenen Semester (nach der alten Studienordnung) die Zulassung zur Klausur erhalten haben, können Sie direkt an der abschließenden Klausur teilnehmen. Jedoch rate ich Ihnen, die Vorlesung und die Übungen/Praktika trotzdem nochmals zu belegen, da sich die Inhalte und Schwerpunkte zu den vergangenen Vorlesungen unterscheiden könnten.

Einführung in die Programmierung für Studierende der Physik
(Introduction to Programming for Physicists)
Vorlesung SS 2022

Diese Internetseite fasst die Online-Angebote der Vorlesung Einführung in die Programmierung für Studierende der Physik zusammen. Die Vorlesungstermine finden jeweils dienstags von 15.00-16.00 Uhr und donnerstags von 14.00-16.00 Uhr im Raum Phys-0.111 statt. Die Termine der Übungen/Praktika finden Sie auf der Online-Lernplatform OLAT und die Übungsaufgaben werden im linken Panel unter der jeweiligen Vorlesung und zusätzlich auf OLAT bereitgestellt.

Die Vorlesung gibt einerseits eine Einführung in die Objekt-orientierte Programmiersprache C++ und vermittelt andererseits einige wesentliche Grundlagen der numerischen Mathematik. Es werden die grundlegenden Elemente der Programmiersprache, das Programmierparadigma der Objektorientierung und Simulationen von komplexen physikalischen Problemen behandelt. Das Hauptanliegen der Vorlesung besteht darin, dass die Studierenden die numerische Lösung eines komplexen physikalischen Problems auf dem Computer erstellen können. Der Schwerpunkt wird hierbei auf der Programmiersprache C++ liegen, wobei für die Visualisierung der berechneten Daten die Skriptsprache Python benutzt wird. Zusätzlich werden die berechneten mathematisch/physikalischen Gleichungen mittels Python Jupyter Notebooks analysiert und illustriert.

Literatur zu C++

Literatur zu Python

Literatur zur Numerischen Mathematik

Vorlesung 1

Die objektorientierte Programmiersprache C++ wird im Fokus dieser Vorlesung stehen und nach einem kurzen Einblick in die grundlegenden Elemente der Programmiersprache C++ werden diverse Anwendungsbeispiele aus dem Bereich der Mathematik und Physik behandelt. C++ unterstützt eine Vielzahl von Programmier- und Programmentwurfstilen und wir werden uns im ersten Teil der Vorlesungsreihe zunächst mit der Prozeduralen Programmierung befassen und die wesentlichen in C++ integrierten Typen, Operatoren, Anweisungen und Funktionen anhand von Beispielen vorstellen. Danach werden wir den Programmierstil ändern und den Fokus auf die Strukturierung von Programmen legen (das Programmierparadigma der Objekt-orientierten Programmierung) und auf das in C++ integrierte Klassenkonzept, die Konstruktoren dieser Klassen und die öffentlich/private Zugriffssteuerung eingehen. Dann, im letzten Teil der Vorlesung, werden die von den Studierenden zu bearbeitenden Programmierprojekte vorgestellt und auf weiterführende Themen eingegangen und aktuelle Forschungssimulationen von komplexen physikalischen Anwendungen vorgestellt.

Bevor Sie sich jedoch mit der Programmierung befassen können, müssen wir zunächst einige technische Dinge und nötige Voraussetzungen besprechen. Natürlich benötigt man einen Computer (PC oder Laptop) mit einem Betriebssystem (z.B. Windows, macOS, Linux). In der Fachgemeinde der numerischen Mathematik und theoretischen Physik ist das Betriebssystem Linux weit verbreitet und ich empfehle allen Studierenden, sich zumindest als Zweitsystem Linux zu installieren und die Programmierung auf einem Linux System auszuführen. Wir werden deshalb im Folgenden die wesentlichen, für uns relevanten Grundlagen des Betriebssystems Linux behandelt und danach einige der aktuellen Programmiersprachen kurz vorstellen und deren Installation kurz beschreiben. Zusätzlich erhalten die Studierenden in der ersten Vorlesung eigene Login-Accounts für die Rechner des Instituts für Theoretische Physik der Goethe-Universität und es wird beschrieben, wie man sich mittels des kryptografischen Netzwerkprotokolls SSH auf diese Rechner einloggt. In einem Anwendungsbeispiel wird dann beschrieben, wie man eine eigene Homepage erstellt.

Eine kleine Einführung in Linux

Damit man ein Computerprogramm erstellen und ausführen kann, benötigt man zunächst einen Computer (PC oder Laptop) und ein Betriebssystem, welches die Systemkomponenten des Computers (z.B. Arbeitsspeicher, Festplatten) verwaltet. Betriebssysteme, wie Windows von Microsoft, macOS von Apple oder Linux bilden die Schnittstelle zwischen den Hardware-Komponenten und der Anwendungssoftware des Benutzers des Computers. Das frei erhältliche Betriebssystem Linux wird weltweit auf vielen Großrechnern, Computerclustern und Supercomputern eingesetzt und bildet auch, durch seine führende Rolle als Internet-Server-System, die grundlegende Struktur des Internets. Man kann mittlerweile Linux relativ einfach auf seinem eigenen Computer installieren (siehe Übungsaufgabe 1.1) und mittels einiger Linux-Shell-Befehle ist eine kommandobasierte Benutzung des Computersystems möglich. Zusätzlich wird in diesem Unterpunkt auch vorgestellt, wie man sich mittels des kryptografischen Netzwerkprotokolls SSH auf die Rechner des Instituts für Theoretische Physik der Goethe-Universität einloggt. Die dafür nötigen Login-Accounts werden in den ersten beiden Vorlesungen an die Studierenden verteilt. Beim Klicken auf das nebenstehende Bild erfahren Sie mehr.

Anwendungsbeispiel: Erstellen einer eigenen Internet-Homepage

In diesem Unterpunkt werden einige der besprochenen Linux Shell-Befehle angewendet, um die Erstellung einer eigenen Internet-Homepage zu realisieren. Zusätzlich wird das Secure File Transfer Protocol (SFTP) vorgestellt, mit dem man in verschlüsselter Form von einem Rechner auf einen anderen Rechner Daten übertragen kann (näheres siehe Anwendungsbeispiel: Erstellen einer eigenen Internet-Homepage).

Programmiersprachen

Höhere Programmiersprachen gibt es schon seit den 1950er Jahren und die älteste noch in weitem Gebrauch befindliche Programmiersprache ist Fortran (FORmula TRANslator). Die Programmiersprache BASIC (Beginner's All-purpose Symbolic Instruction Code) wurde Ende der 1970er Jahre, aufgrund der für Jedermann erschwinglichen Heimcomputern (z.B. der Commodore C-64) populär. Die Programmiersprache C entstand 1972 und die Objekt-orientierte Variante von C (C++) wurde im Jahre 1983 von Bjarne Stroustrup vorgestellt. In der Vorlesung wird der Schwerpunkt auf der Programmiersprache C++ liegen und für die Visualisierung der berechneten Daten wird die Skriptsprache Python benutzt, die Anfang der 1990er Jahre entwickelt wurde (siehe Zeittafel der Programmiersprachen). Die Installation von C++ und Python ist auf allen gängigen Betriebssystemen möglich und wird am Beispiel des Betriebssystems Linux unter dem folgenden Link kurz beschrieben: Programmiersprachen.

Weitere Links

Vorlesung 1

Jede quantitative Beschreibung von Vorgängen, nicht nur im Bereich der Physik, benutzt mathematische Zusammenhänge, um das zu beschreibende System zu verstehen. Oft sind diese mathematischen Gleichungen in Form von Bewegungsgleichungen formuliert, deren Lösungen man dann zu bestimmen und analysieren hat. Für einfache physikalische Probleme ist eine solche Lösung auf analytisch mathematischem Weg möglich, jedoch je komplexer (bzw. je realitäts-näher) das zu untersuchende Problem wird, desto komplizierter wird auch dessen Lösung und oft ist es dann auf analytischem Weg nicht mehr möglich eine zusammenhängende mathematische Lösungsgleichung zu finden. Der Computer kann einem bei solchen Problemen in vielschichtiger Weise helfen und in dieser Vorlesung sollen die Studierenden lernen, wie man dem Computer das Problem erklärt, sodass er die numerische Lösung bestimmen kann. Für die Programmierung benötigt man einerseits das Vokabular einer gängigen objektorientierten Programmiersprache (z.B. C++) und andererseits eine auf Algorithmen basierende gründende Vorgehensweise, die die zugrundeliegenden physikalischen Gleichungen numerisch, in einem iterativen Prozess löst, um diese dann grafisch darstellen und analysieren zu können.

Nach einem kurzen Überblick in die Inhalte der gesamten Vorlesung werden die Grundlagen des Betriebssystems Linux behandelt und einige der aktuellen Programmiersprachen kurz vorgestellt. In der Vorlesung wird der Schwerpunkt auf der Programmiersprache C++ liegen und für die Visualisierung der berechneten Daten wird die Skriptsprache Python benutzt. Zusätzlich werden die berechneten mathematisch/physikalischen Gleichungen mittels der web-basierten interaktiven Programmierumgebung in Jupyter-Notebook-Dokumenten behandelt und analysiert.

Vorlesung 2

Im Folgenden wird vorausgesetzt, dass Sie auf Ihrem eigenen Computer einen lauffähigen C++ Compiler und Python 3 installiert haben. Wir beginnen, wie viele andere Einführungen in die Programmierung, mit der C++ Version des klassischen Hello World Programms. Es wird die Textausgabe im Linuxterminal und Eingabe von Zahlenwerten über die Tastatur vorgestellt. Möchte man numerische Berechnungen in der Programmiersprache C++ durchführen, muss man zunächst definieren, in welchem Zahlenraum die numerischen Variablen sich aufhalten und einen speziellen Typ den Variable zuordnen. Die grundlegenden, integrierten Datentypen von C++ und die mittels Operatoren integrierte Arithmetik werden in dieser Vorlesung vorgestellt. Am Ende der Vorlesung werden die Benutzereingabe und die formatierte Ausgabe von Zahlenwerten behandelt.

Das erste C++ Programm (Hello World)

In diesem Unterpunkt wird die Programmiersprache C++ am Beispiel des klassischen Hello World Programms vorgestellt. C++ ist eine kompilierte Programmiersprache, d.h. der vom Programmierer geschriebene Quelltext des Computerprogramms muss zunächst mittels eines Compilers in ein ausführbares Programm umgewandelt werden, damit es genutzt werden kann. Dieser Kompilierungsprozess und die Textausgabe des ausführbaren Hello World Programms im Linuxterminal (mittels cout bzw. printf) wird unter folgendem Link vorgestellt: Das erste C++ Programm (Hello World).

Datentypen und Variablen

In gleicher Weise, wie es in der Mathematik die unterschiedlichen Zahlenmengen (z.B. ℤ, ℕ, ℝ, ℂ ) gibt und man bei mathematischen Berechnungen den Wertebereich einer Variable oder Funktion vorher definieren muss, ist dies auch beim Programmieren in C++ nötig. In diesem Unterpunkt werden die Begriffe Deklaration einer Variable, Datentyp, Wert einer Variable und die Initialisierung einer Variable diskutiert. Die wichtigsten integrierten Datentypen von C++ sind bool, char, int, float und double. Näheres siehe unter folgendem Link: Datentypen und Variablen

Arithmetik und Operatoren

Möchte man mit Datentypen und Variablen mathematische Berechnungen durchführen oder die Datenwerte miteinander vergleichen, ist es zunächst nötig eine Arithmetik (die zum Zählen oder Rechnen gehörige Kunst) zu definieren. Hierzu wurden in C++ geeignete Operatoren definiert, die dem Programmierer neben den arithmetischen Grundrechenarten (Multiplikation, Addition, ...) noch diverse weitere integrierte Operatoren zur Verfügung stellen. Man unterscheidet hierbei die arithmetischen Operatoren, die logischen Vergleichsoperatoren und weitere spezifische Operatoren. Zusätzlich sind einige wichtige mathematische Funktionen (Sinus, Cosinus, ..) in der Standardbibliothek <cmath> vordefiniert (näheres siehe Arithmetik und Operatoren).

Die Ein- und Ausgabe

In diesem Unterpunkt werden wir und die Eingabe von Zahlenwerten durch den Benutzer vorstellen und die formatierte Ausgabe von Datenwerten im Terminalfenster näher betrachten. Die Programmiersprache C++ stellt mehrere integrierte Möglichkeiten der Benutzereingabe und Ausgabe bereit und es werden im Speziellen die Eingabe mittels "cin" und "scanf(...)" und die Ausgabe mittels "cout" und "printf(...)" betrachtet. Am Ende wird noch die hilfreiche Standardbibliothek <limits> vorgestellt, die viele Werte zu Limitierungen bei numerischen Berechnungen enthält (näheres siehe Ein- und Ausgabe).

Weitere Links

Vorlesung 2

Es geschieht einem theoretischen Physiker leider nur zu oft, dass er ein System beschreiben möchte, welches er auf analytischem, mathematischem Weg nicht lösen kann. Betrachten wir z.B. das einfache physikalische Pendel aus dem Themenbereich der Mechanik (siehe z.B. W.Greiner, Klassische Mechanik I). Die zugrundeliegende Differentialgleichung (DGL) des Problems lautet \[ \begin{equation} \frac{d^2 \phi(t)}{dt^2} = -\frac{g}{l} \cdot \hbox{sin}\left( \phi(t) \right) \quad , \end{equation} \] wobei $g$ die Erdbeschleunigung, $l$ die Länge des Pendels und $\phi(t)$ die zeitliche Entwicklung des Pendelwinkels beschreibt. Ungünstigerweise besitzt diese DGL keine analytisch darstellbare Lösung und gewöhnlich vereinfacht man dann das zu beschreibende System (z.B. durch Approximation zum mathematischen Pendel) und gelangt auf diesem Wege doch zu analytischen Lösungen, deren Verhalten man studieren kann. Vergleicht man die Lösung dann mit der Realität, stimmt diese oft nur unter gewissen Randbedingungen. Nimmt man jedoch Anfangswerte des Pendels, die außerhalb des Gültigkeitsbereiches der approximierten Lösung liegen, weichen die Vorhersagen der Pendelbewegung deutlich von der wirklichen Lösung ab. Stoßen wir z.B. das Pendel mit einem sehr starken "Schubs" aus seiner Ruhelage, so stimmt die analytische Lösung des mathematischen Pendels nicht und das wirkliche Pendel verhält sich vollkommen anders. Die folgenden Animationen entstammen einem Python Jupyter Notebook und sie vergleichen die numerische Lösung des physikalischen Pendels mit der analytischen Lösung des mathematischen Pendels, bei der ein Pendelüberschlag nicht möglich ist.


Anhand dieses Beispiels sollte die Sinnhaftigkeit von numerischen Computersimulationen verdeutlicht werden. Nun muss ich aber die Studierenden dieser Vorlesung an dieser Stelle leider schon auch gleich wieder enttäuschen, denn numerische Simulationen sind vom Grunde her nicht genau und stets mit einem nicht reduzierbarem Fehler behaftet. In dieser zweiten Vorlesung werden die Grundlagen der Programmiersprache C++ behandelt (Datentypen und Variablen, Arithmetik und Operatoren und die Ein- und Ausgabe) und der Zahlenraum ℝ$_C$ in dem der Computer rechnet definiert und die damit verbundene Rechenungenauigkeit verdeutlicht.

Vorlesung 3

C++ Anweisungen: Die for-, while- und do-Schleifen

Möchte man als Programmierer ein Problem mittels eines C++ Programms lösen, so muss man dem Computer in Form von Anweisungen sagen, was er zu erledigen hat. In diesem Unterpunkt behandeln wir eine der wichtigsten Anweisungsarten, die sogenannten Schleifenanweisungen. Im Prinzip ist jede Programmzeile, die mit einem Semikolon endet, eine Anweisung an den Computer, jedoch stellen die Schleifenanweisungen eine besondere Art von iterativen Anweisungsprozessen dar, und sind ein oft verwendetes Hilfsmittel der prozeduralen Programmierung. Eine Schleifenanweisung kann als eine for-, while- oder do-Anweisung ausgedrückt werden (näheres siehe C++ Anweisungen: Die for-, while- und do-Schleifen).

Anwendungsbeispiel: Folgen und Reihen

Die im vorigen Unterpunkt besprochenen Schleifenanweisungen finden in vielen C++ Programmen ihre Anwendung. In diesem Unterpunkt wird ihre Anwendung im Bereich der mathematischen Folgen und Reihen diskutiert. Am Beispiel der konvergenten Folge der Eulersche Zahl $e$ und der Leibniz-Reihe zur Berechnung der Kreiszahl $\pi$ wird die Verwendung der while-Schleife vorgestellt. Das Umschreiben der Programme unter Verwendung einer for-Schleife ist Teil der Aufgabe 2 des (siehe Übungsblattes Nr. 3. Es wird unter anderem das Konvergenzverhalten der Folge für die ersten Folgenglieder untersucht und die von vom Programm ausgegebenen Werte visualisiert. Hierzu werden die ausgegebenen Daten in eine separate Datei umgeleitet und dann mittels Gnuplot bzw. Python-Matplotlib dargestellt (näheres siehe Anwendungsbeispiel: Folgen und Reihen).

Eine kleine Einführung in die Programmiersprache Python

Die Programmiersprache Python ist auch eine sehr gute objektorientierte Programmiersprache und im Prinzip hätten wir die gesamte Vorlesung nur mittels Python gestalten können. Die in dieser Vorlesung behandelten Python-Skripte und Python Jupyter Notebooks werden jedoch lediglich zur Visualisierung von Daten und im Bereich der Illustration von mathematisch/physikalischen Gleichungen benutzt. Mittels des Python-Moduls "matplotlib" (siehe Matplotlib: Visualization with Python) können auf einem einfachen Weg Bilder and Animationen des zuvor mit C++ simulierten Systems erzeugt werden. Zusätzlich werden wir, die im nächsten Unterpunkt besprochene C++ Computerarithmetik mittels eines Python Jupyter Notebooks verdeutlichen und dabei die Verwendung von Listen, Arrays und for-Schleifen in der Programmiersprache Python kennenlernen (näheres siehe Eine kleine Einführung in die Programmiersprache Python).

Die Computerarithmetik und der Fehler in numerischen Berechnungen

In diesem Unterpunkt werden wir zwei Klassen von Fehlerquellen in numerischen Berechnungen besprechen, den sogenannten Rundungsfehler, der aufgrund der Computerarithmetik entsteht und der sogenannte Approximierungsfehler (Abschneidefehler bzw.'Truncation error'), der immer dann auftritt, wenn der Programmierer eine exakte mathematische Gleichung mittels approximativer Ausdrücke annähert (näheres siehe Die Computerarithmetik und der Fehler in numerischen Berechnungen).

Weitere Links

Vorlesung 3

In dieser Vorlesung werden wir die wohl wichtigste Form von C++ Anweisungen, die sogenannten Schleifenanweisungen, kennenlernen. Die Schleifenanweisungen stellen einen iterativen Anweisungsprozess dar und können in Form von for-, while- oder do-Anweisung ausgedrückt werden. Möchte man z.B. die natürlichen Zahlen von Null bis 100 im Terminal ausgeben lassen, so kann man dies in einer einfachen Weise mittels einer Schleifenanweisung dem Computer sagen. Die Anwendung von Schleifenanweisung wird danach am Beispiel einer mathematischen Folge und Reihe diskutiert.
Die Visualisierung von Daten, die mittels C++ Programmen erstellt wurden, ist ein wichtiges Teilgebiet eines Programmierers im Bereich der Physik. In dieser Vorlesung werden diverse Python-Skripte und Python Jupyter Notebooks vorgestellt, die zur Visualisierung von Daten und im Bereich der Illustration von mathematisch/physikalischen Gleichungen benutzt werden. Mittels des Python-Moduls "matplotlib" (siehe Matplotlib: Visualization with Python) können auf einem einfachen Weg Bilder and Animationen des zuvor mit C++ simulierten Systems erzeugt werden.

Am Ende der Vorlesung kommen wir nochmals auf den, bereits im Unterkapitel Datentypen und Variablen angesprochenen Zahlenraum des Computers (ℝ$_C$) zurück und diskutieren die zwei wichtigsten Fehlerquellen bei nummerischen Berechnungen (Rundungsfehler und Approximierungsfehler). Der Rundungsfehler ist darin begründet, dass der Zahlenraum des Computers (ℝ$_C$), nur eine relativ kleine Teilmenge der reellen Zahlen benutzt und somit reellwertige Zahlen mit einer unendlichen Anzahl von Nachkommastellen nicht speichern kann. Diese Teilmenge ℝ$_C$ umfasst nur rationale Zahlen und speichert den gebrochenen Teil, der mit Mantisse bezeichnet wird, zusammen mit dem exponentiellen Teil, welchen man Charakteristik nennt als eine binäre Liste von Nullen und Einsen. Die zweite Klasse von nummerischen Fehlern, die Approximierungsfehler werden am Beispiel der approximativen Annäherung an die Kreiszahl $\pi$ mittels der alternierenden Leibniz-Reihe besprochen. Bei dieser Art von Fehlern hat es der Programmierer selbst in der Hand, wie genau er in seinem Programm die Berechnung durchführen möchte (näheres siehe Die Computerarithmetik und der Fehler in numerischen Berechnungen).

Vorlesung 4

In dieser Vorlesung werden wir zunächst die Auswahlanweisungen der Sprache C++ vorstellen und danach auf die Definition von C++ Funktionen eingehen. In dem Anwendungsbeispiel Nullstellensuche einer Funktion werden dann die erlernten Konzepte am Beispiel der Methode der Bisektion, dem sogenannten Intervallhalbierungsverfahren verdeutlicht. Zusätzlich wird am Ende die Newton-Raphson Methode der Nullstellenermittlung vorgestellt.

C++ Anweisungen: Auswahlanweisungen mit if und switch

Die Programmiersprache C++ bietet einen konventionellen und flexiblen Satz von Anweisungen. Im Prinzip ist jede Programmzeile, die mit einem Semikolon endet, eine Anweisung. In diesem Unterpunkt werden wir die sogenannten Auswahlanweisungen behandeln, wobei wir in der vorigen Vorlesung die Schleifenanweisungen vorstellt hatten (siehe C++ Anweisungen: Die for-, while- und do-Schleifen). Auswahlanweisungen werden auch als Verzweigung , Tests oder bedingte Anweisungen bezeichnet und sind immer dann anzuwenden, wenn das Programm bei einem gewissen Ereignis bzw. unter einer gewissen Bedingung etwas Bestimmtes tun soll. Es teilt somit das Programm in unterschiedliche Anweisungspfade auf. Auswahlanweisungen können in Form einer if-, (if-else)- oder switch-Anweisung ausgedrückt werden. C++ Anweisungen: Auswahlanweisungen mit if und switch

Funktionen in C++

Die Definition einer C++ Funktion ist im Grunde nichts Anderes, als eine Code-Block (Anweisungsblock) mit einem Funktionsnamen zu verbinden. C++ Funktionen werden außerhalb der main()-Hauptfunktion definiert und vereinfachen somit das Verständnis und die Lesbarkeit des Quelltextes. C++ Funktionen sind ein wichtiges Werkzeug, um den Quelltext eines Programms zu ordnen und wesentliche Algorithmen und zusammenhängende Anweisungsblöcke der main()-Hauptfunktion in einer zusammenhängenden Form auszulagern. Die Definition einer C++ Funktion besteht aus einer Deklaration und einem Anweisungsblock und sie ist der formalen Definition einer mathematischen Funktion nicht unähnlich: "Eine C++ Funktion ist eine Abbildung von dem Datenraum der Argumentenliste in den Datenraum des Rückgabetyps. Die dabei benutzte Abbildungsvorschrift findet sich in dem Anweisungsblock der Funktion. Der 'Rückgabe Typ' kann hierbei eine der schon besprochenen Datentypen (z.B. int oder double) oder ein Daten-Array (siehe nächste Vorlesung) sein. Die Argumentenliste setzt sich aus einer Liste von Datentypen der formalen Argumente (Parameter) der Funktion zusammen, die jeweils mit einem Komma voneinander getrennt sind. In C++ hat das Wort Funktion eine allgemeinere Bedeutung als im Bereich der Mathematik und die in der Mathematik und Physik definierte Funktionen stellen eine echte Teilmenge der C++ Funktionen dar (näheres siehe Funktionen in C++).

Anwendungsbeispiel: Nullstellensuche einer Funktion

In diesem Unterpunkt möchten wir ein grundlegendes Problem der numerischen Mathematik behandeln, die Nullstellensuche einer Funktion. Wir betrachten im Speziellen die Funktion $f(x)=e^x-10$ und wollen berechnen, bei welchem x-Wert die Funktion Null wird ($f(x)=0$). Hat eine Funktion im Teilintervall $[a,b] \in ℝ$ eine Nullstelle bei $x=p$, so kann man diese Nullstelle numerisch mittels unterschiedlicher Methoden berechnen. In diesem Unterpunkt betrachten wir zunächst die Methode der Bisektion (das Intervallhalbierungsverfahren) zur Ermittlung der Nullstelle. In der nebenstehenden Abbildung ist die Funktion $f(x)=e^x-10$ im Teilintervall $[a,b] = [2,4]$ als blaue Kurve dargestellt und man erkennt die zu bestimmende Nullstelle, welche sich beim Wert $p = $ ln$(10) \approx 2.302585...$ befindet. In diesem Unterpunkt wird der Algorithmus des Intervallhalbierungsverfahrens vorgestellt und mittels eines C++ Programms umgesetzt. Das C++ Programm verwendet hierbei eine Funktionendefinition und benutzt eine geschachtelte (if-else)-Anweisung. Die berechneten Ergebnisse werden dann mit einem Python Skript visualisiert. Zusätzlich wird ebenfalls die Newton-Raphson Methode der Nullstellenermittlung vorgestellt und mittels eines C++ Programms realisiert (näheres siehe Anwendungsbeispiel: Nullstellensuche einer Funktion).

Weitere Links

Vorlesung 4

Die möglichen integrierten Anweisungsbefehle innerhalb einer Programmiersprache sind die wohl wichtigsten Grundvokabeln, die man als Programmierer kennen muss. In der vorigen Vorlesung hatten wir uns bereits mit den Schleifenanweisungen befasst und in dieser Vorlesung werden wir uns mit den Auswahlanweisungen beschäftigen. Im Speziellen werden die if-Anweisung, die (if-else)-Anweisung und die switch-Anweisung besprochen. Auswahlanweisungen stellen eine Art von Programmverzweigungen dar und sind immer dann anzuwenden, wenn das Programm bei einem gewissen Ereignis etwas Bestimmtes tun soll.
Ein weiteres wichtiges Konzept bei der Erstellung eines C++ Quelltextes ist der Begriff der "Funktion". C++ Funktionen sind ein wichtiges Werkzeug, um den Quelltext eines Programms zu ordnen und wesentliche Algorithmen und zusammenhängende Anweisungsblöcke der main()-Hauptfunktion in einer zusammenhängenden Form auszulagern. Man könnte salopp sagen, dass Funktionen kleine Unterprogramme sind, die definierte Teilprobleme lösen. Im Grunde bedeutet die Definition einer Funktion im Programm nichts Anderes, als eine Code-Block (Anweisungsblock) mit einem Funktionsnamen zu verbinden. In C++ hat das Wort Funktion eine allgemeinere Bedeutung als im Bereich der Mathematik und die in der Mathematik und Physik definierte Funktionen stellen eine echte Teilmenge der C++ Funktionen dar. Wir werden in dieser Vorlesung lediglich eine erste grundsätzliche Einführung in den Themenbereich der C++ Funktionen geben und auf die allgemeinere Verwendung von Funktionen im Laufe der Vorlesung noch genauer eingehen. Gerade in den Unterpunkten, die sich mit der objektorientierten Programmierung befassen, sind Klassen-Funktionen, Konstruktoren und das Überladen von Funktionen ein wichtiges Thema.
Am Ende dieser Vorlesung wenden wir das Erlernte an und besprechen eines der grundlegenden Probleme der numerischen Mathematik: Die Nullstellensuche einer Funktion. Wir nehmen dabei an, dass eine Funktion $f(x)$ im Intervall $[a,b] \in ℝ$ eine Nullstelle hat und berechnen dann diese Nullstelle numerisch, approximativ mittels der Methode der Bisektion und dem Newton-Raphson Algorithmus. Beide Methoden werden in dem Anwendungsbeispiel: Nullstellensuche einer Funktion im Detail besprochen und der zugrundeliegende Algorithmus der Nullstellensuche wird mittels einer Python-Skript Visualisierung verdeutlicht.

Vorlesung 5

In dieser Vorlesung werden wir zunächst auf das C++ Array- und Zeiger Konzept eingehen und sowohl die eindimensionalen Zahlenarrays, als auch die eindimensionalen Zeichenarrays an Beispielen verdeutlichen. Am Ende des ersten Teils gehen wir auf die Problematik der Übergabe eines Arrays an eine C++ Funktion ein. Als ein Anwendungsbeispiel der eindimensionalen Arrays betrachten wir dann die Lagrange Polynome Methode, bei der ein Polynom mittels einer gegebenen Menge Stützstellen berechnet wird. Es wird ein C++ Programm vorgestellt, welches mittels des Lagrange Polynom Algorithmus die xy-Wertetabelle des Polynoms erzeugt und diese Daten werden dann mittels eines Python Jupyter Notebooks visualisiert. Zusätzlich wird in dem Notebook auch die analytische Form der Polynome unter Verwendung der Computer-Algebra-Bibliothek "sympy" berechnet und dieses Notebook zeigt somit ein weiteres wichtiges Anwendungsfeld von Python Jupyter Notebooks auf, das dem Verständnis und der Herleitung der zu berechnenden Gleichungen dient.

C++ Arrays, Zeiger und Referenzen

Alle die bis zu diesem Abschnitt besprochenen Datentypen, verbinden den Namen des deklarierten Typs mit einem einzelnen Wert, d.h. mit einer skalar wertigen Größe. Um die in der Physik und Mathematik gebräuchlichen Größen wie Vektoren und Matrizen in einem Computerprogramm adäquat abbilden zu können, gibt es die sogenannten Datenarrays. Ein C++ Array ist eine geordnete Menge von Elementen des gleichen Typs T. In diesem Unterpunkt werden die wesentlichen Grundlagen zu eindimensionalen C++ Arrays vorgestellt. Da die interne Array-Implementierung der Programmiersprache C++ eng mit dem C++ Zeiger Konzept verknüpft ist, werden wir zunächst die Begriffe Zeiger, Adresse und Referenz an mehreren Beispielen vorstellen, um danach die eindimensionalen Arrays am Beispiel des Zeichen-Arrays des "HelloWorld" - Programmes zu verdeutlichen (siehe nebenstehende Abbildung). Das C++-Zeigerkonzept ist der grundlegende integrierte Sprachmechanismus, um den Zugriff auf den Hauptspeicher des Computers direkt zu ermöglichen. Am Ende dieses Unterpunktes zeigen wir, wie man Arrays an Funktionen übergibt. Möchte man ein Array an eine Funktion als Argument übergeben, sollte man dies nicht über die einzelnen Werte des Arrays machen, da man dann die Array-Einträge nicht verändern kann. Stattdessen übergibt man ein Array (dies gilt auch für mehrdimensionale Arrays) als Zeiger auf sein erstes Element mit einem zusätzlichen Vermerk zu seiner Dimension (näheres siehe C++ Arrays, Zeiger und Referenzen).

Anwendungsbeispiel: Interpolation und Polynomapproximation

Die Interpolation ist ein Teilgebiet der numerischen Mathematik und es befasst sich mit der Problematik, eine analytische Funktion mittels einer gegebenen Menge von Werten zu bestimmen. In diesem Unterpunkt werden wir die Interpolation einer Funktion $f(x)$ mittels der Methode der Lagrange Polynome vorstellen, bei der man mehrere Stützstellenpunkte $\vec{x}=\left( x_0, x_1, \, ... \,, x_n \right)$ für die Konstruktion des approximierenden Polynoms verwendet. Die nebenstehende Abbildung stellt z.B. das Lagrange Polynom $P_6(x)$ dar, welches die Funktion $f(x)=1/x$ mittels der sieben Stützstellen $\vec{x}=\left( 1, 1.5, 2, 2.5, 3, 5, 7 \right)$ approximiert. Nachdem die Theorie der Lagrange Polynome Methode kurz vorgestellt wurde, wird ein C++ Programm entworfen, welches den Kern-Algorithmus des Verfahrens implementiert und dabei das Array-Konzept benutzt. Es wird unter anderem z.B. der Vektor $\vec{x}$ der x-Werte der Stützstellenpunkte als ein double-Array "double points[]" deklariert und direkt mit den Stützstellenwerten initialisiert. Die berechneten Lagrangepolynome werden danach mittels eines Jupyter Notebook visualisiert und mit der Funktion $f(x)$ verglichen. Zusätzlich wird in dem Notebook auch die analytische Form der Polynome unter Verwendung der Computer-Algebra-Bibliothek "sympy" berechnet (näheres siehe Anwendungsbeispiel: Interpolation und Polynomapproximation).

Aus aktuellem Anlass: Live Übertragung der ESO-Pressekonferenz (Neues vom Schwarzen Loch im Zentrum der Milchstrasse)

Aus aktuellem Anlass wird die Vorlesung am 12.05.2022 ab ca. 15.00 Uhr unterbrochen, um die Pressekonferenz der Europäische Südsternwarte (engl. European Southern Observatory, ESO) live zu verfolgen (näheres siehe Pressekonferenz bei der ESO über bahnbrechende Ergebnisse des Event Horizon Telescope-Projekts). Vor einigen Jahren wurde das erste Bild eines Schwarzen Loches der Welt präsentiert. Es handelte sich hierbei um das Bild des schwarzen Loches im Zentrum unserer Nachbargalaxie Messier 87 (M87$^*$), bzw. ein wenig genauer, um die dem schwarzen Loch entweichende Radiostrahlung. Das Bild wurde mittels eines weltweiten Verbunds von Radiowellenteleskopen (EHT: Event Horizon Teleskop, siehe auch Black Hole Cam) sichtbar gemacht. Das EHT beobachtete im Jahre 2017 zwei supermassive schwarze Löcher: das schwarze Loch in unserer Milchstraße (Sagittarius A*, Masse $M\approx 4.15 \cdot 10^6 M_\odot$, Abstand zur Erde $D \approx 26670$ Lichtjahre) und in unserer Nachbargalaxie Messier 87 (M87*, Masse $M\approx 6.5 \cdot 10^9 M_\odot$, Abstand zur Erde $D \approx 53$ Millionen Lichtjahre). In beiden Systemen kreist Materie in einer Akkretionsscheibe um ein supermassives schwarzes Loch und emittiert beim Einfallen elektromagnetische Strahlung. In der Pressekonferenz wurde das erste Bild des Supermassiven Schwarzen Loches im Zentrum unserer Milchstraße (SGR A*) gezeigt (siehe nebenstehende Abbildung). Siehe auch die nachfolgenden Artikel in den Zeitschriften Focus, Stern, Süddeutsche, Zeit, Frankfurter Allgemeine, Welt, n-tv, RTL. Video Material findet man unter Relastro@ITP - Goethe University, Frankfurt.

Weitere Links

Vorlesung 5

Die zugrundeliegenden Gleichungen der Physik sind oft in Form von vektoriellen und matrixwertigen Gleichungen formuliert. Vektoren und Matrizen sind mathematische Konstrukte, die eine Vielzahl von Elementen (Zahlen) in einer gebundenen Form zusammenfassen. Wie deklariert man ein solches zusammengesetztes Konstrukt in einem C++ Programm? An diesem Punkt der Vorlesung wollen wir noch nicht auf das C++ Container Konzept eingehen, welches unter anderem den wichtigen Container vector der Standardbibliothek bereitstellt, sondern wir betrachten uns das schon in alten C-Programmen oft verwendete, integrierte C++ Array Konzept. Ein C++ Array (nicht zu verwechseln mit dem Container array der Standardbibliothek) stellt ein zusammengesetztes Konstrukt von Elementen eines Datentyps dar. Ein Vektor $\vec{v}=\left( 1, 3, 7 \right)$ bestehend aus drei ganzzahligen Elementen kann z.B. mittels des int-Arrays "int v[3] = {1,3,4};" definiert werden. Der Zugriff auf die einzelnen Werte des Arrays erfolgt hierbei durch Angabe seines Indexes, wobei die Elemente von 0 bis 2 indiziert werden (z.B. $v_1=3 \, \rightarrow$ v[1]). Wie wird nun ein solches zusammenhängendes Konstrukt von Zahlen im Hauptspeicher geordnet gespeichert? Da die interne Array-Implementierung der Programmiersprache C++ eng mit dem C++ Zeiger Konzept verknüpft ist, werden wir in dieser Vorlesung zunächst die Begriffe Zeiger, Adresse und Referenz an mehreren Beispielen vorstellen und die eindimensionalen Arrays am Beispiel des Zeichen-Arrays des "HelloWorld" - Programmes zu verdeutlichen (siehe obere Abbildung im linken Frame). Das C++-Zeigerkonzept ist der grundlegende integrierte Sprachmechanismus, um den Zugriff auf den Hauptspeicher des Computers direkt zu ermöglichen. Zusätzlich wird darauf eingegangen, wie man Arrays an C++ Funktionen übergibt.
Das erlernte C++ Array Konzept wird dann an dem Beispiel der Methode der Lagrange Polynome verdeutlicht. Die Lagrange Polynome Methode ist ein wichtiges Teilgebiet der numerischen Mathematik und es befasst sich mit der Problematik ein Polynom vom Grade $n$ ($P_n(x)$) mittels einer gegebenen Menge von ($n+1$) Stützstellenpunkten zu bestimmen. Das Verfahren wird bei einer Vielzahl von numerischen Algorithmen verwendet, bei denen eine vorgegebene Funktion $f(x)$ durch ein Polynom $P_n(x)$, mittels der Angabe der ($n+1$) x-Werte der Stützstellenpunkten ($\vec{x}=\left( x_0, x_1, \, ... \,, x_n \right)$), approximiert wird. Die untere Abbildung im linken Frame veranschaulicht z.B. das Lagrange Polynom $P_6(x)$ dar, welches die Funktion $f(x)=1/x$ mittels der sieben Stützstellen $\vec{x}=\left( 1, 1.5, 2, 2.5, 3, 5, 7 \right)$ approximiert. Die Methode der Lagrange Polynome ist ein wichtiges Hilfsmittel der numerischen Mathematik, jedoch wird sie selten in Programmen verwendet, da es numerisch geeignetere Methoden der Interpolation gibt. Wie wir im nebenstehenden Anwendungsbeispiel sehen werden, unterscheidet sich das approximierte Lagrange Polynom oft erheblich von der wirklichen Funktion und bei einer Verwendung einer großen Anzahl von Stützstellen oszilliert das approximierte Polynom von hohem Grade oft teils erheblich um $f(x)$. Mittels einer stückweisen Polynomapproximation (z.B. die kubische Spline-Interpolation) kann oft eine bessere nummerische Approximation erzielt werden (näheres siehe Vorlesung 9).

Vorlesung 6

Mehrdimensionale C++ Arrays

In diesem Unterpunkt werden wir uns mit der Deklaration von integrierten mehrdimensionale C++ Arrays befassen. C++ Zahlen-Arrays haben bei der Programmierung von physikalischen Problemen eine bedeutende Rolle, da sie der numerischen Implementierung von Matrizen entsprechen. Obwohl die eigentliche Definition dieser zusammenhängenden Objekte einfachen Darstellungen folgt und z.B. der Zugriff auf die Elemente eines C++ Arrays mittels einer, in der Physik gebräuchlichen Index-Schreibweise, erfolgt, ist die genaue interne Speicherung solcher Matrix-ähnlicher Strukturen nicht so einfach zu verstehen und bedarf eines Zeigerkonzeptes (siehe C++ Arrays, Zeiger und Referenzen). In gleicher Weise wie auch bei eindimensionalen Arrays sind mehrdimensionale C++ Arrays mittels des Konstruktes des Zeigers implementiert. Eine $(m \times n)$-Matrix ${\bf \cal A}$, bestehend aus Gleitkommazahlen vom Typ double kann auf tiefster Ebene als ein integriertes Array deklariert werden: double A[m][n]; Der Zugriff auf den Wert eines Array-Elementes kann nun entweder durch die Angabe des entsprechenden Matrix-Indexes erfolgen (A[i][j]), oder durch den dereferenzierten Wert seiner Zeigerposition im Array erfolgen ( *(A[i] + j) bzw. *(zeiger_A + i*n + j) ). Danach wird am Beispiel der Multiplikation zweier Matrizen der Zugriff auf die einzelnen Elemente des Arrays verdeutlicht. Zuletzt wird das Thema Mehrdimensionale C++ Arrays und Funktionen behandelt. C++ Arrays lassen sich nicht direkt als Wert übergeben; stattdessen übergibt man ein Array als Zeiger auf sein erstes Element, mit einer zusätzlichen Angabe seiner Dimensionen (näheres siehe Mehrdimensionale C++ Arrays).

Jupyter Notebooks und das Rechnen mit symbolischen Ausdrücken

Ein Computeralgebrasystem ist ein Computerprogramm, das der Bearbeitung algebraischer Ausdrücke dient. Es löst nicht nur mathematische Aufgaben mit festen Zahlenwerten, sondern auch solche mit symbolischen Ausdrücken (Gleichungen von Variablen, Funktionen, Polynomen und Matrizen). In diesem Unterkapitel wird die Programmiersprache Python, in Verbindung mit der Python-Bibliothek SymPy benutzt, um symbolische Berechnungen durchzuführen (Matrix-Berechnungen, Differentiation, Integration, analytisches Lösen von Differentialgleichungen). In diesem Sinne agiert das Jupyter Notebook als ein Computeralgebrasystem und es löst nicht nur mathematische Aufgaben mit festen Zahlenwerten, sondern auch solche mit symbolischen Ausdrücken (Gleichungen von Variablen, Funktionen, Polynomen und Matrizen). Beim Klicken auf das nebenstehende Bild gelangt man zu dem Jupyter Notebook Das Computeralgebrasystem: Python Jupyter + SymPy ('Jupyter_sympy.ipynb' , View Notebook, Download Notebook). Am Ende des Notebooks wird unter anderen auch der Anwendungsfall der Herleitung der Differentiationsregeln mittels der Methode der Lagrange Polynome behandelt, die dann im nächsten Unterpunkt bei der Numerische Differentiation benutzt werden.

Numerische Differentiation

Die im vorigen Unterpunkt hergeleiteten Differentiationsregeln der numerischen Mathematik sind im Folgenden nochmals zusammenfassend dargestellt: \[ \begin{eqnarray} \hbox{Zweipunkteformel (n=1):}\,\, && \,\, f^\prime(x_0) \approx \frac{1}{h} \left[ f(x_0 + h) - f(x_0) \right] \\ \hbox{Dreipunkte-Endpunkt-Formel (n=2):}\,\, && \,\, f^\prime(x_0) \approx \frac{1}{2h} \left[ - 3\,f(x_0) + 4 \, f(x_0 + h) - f(x_0 + 2 \, h) \right] \\ \hbox{Dreipunkte-Mittelpunkt-Formel (n=2):}\,\, && \,\, f^\prime(x_0) \approx \frac{1}{2h} \left[ f(x_0 + h) - f(x_0 - h) \right] \\ \hbox{Fünfpunkte-Mittelpunkt-Formel (n=4):}\,\, && \,\, f^\prime(x_0) \approx \frac{1}{12 \, h} \left[ f(x_0 - 2 \, h) - 8 \, f(x_0 - h) + 8 \, f(x_0 + h) - f(x_0 + 2 \, h) \right] \end{eqnarray} \] In diesem Unterpunkt werden die Ableitungsregeln in einem C++ Programm verwendet, um die numerische Ableitung der Funktion $f(x)= 10 \, e^{-x/10} \cdot \hbox{sin}(x)$ zu approximieren und die Ergebnisse dann mit der wirklichen, analytisch bestimmbaren Ableitung $f^\prime(x)$ zu vergleichen (näheres siehe Numerische Differentiation).

Weitere Links

Vorlesung 6

Im ersten Teil dieser Vorlesung werden wir uns zunächst mit der Deklaration von mehrdimensionale C++ Arrays befassen. Zwei dimensionale C++ Zahlen-Arrays entsprechen der numerischen Implementierung von zwei dimensionale Matrizen, welche in der Physik eine bedeutende Rolle spielen. Möchten wir z.B. eine $(m \times n)$-Matrix ${\bf \cal A} = (a_{ij})_{i=1,2,...,m \, ; \, j=1,2,...,n}$), bestehend aus Gleitkommazahlen vom Typ double in einem C++ Programm als ein integriertes Array deklarieren, so würden wir die folgende Anweisung in den Quelltext schreiben: \[ \begin{equation} {\bf \cal A} =\left( \begin{array}{cccc} a_{11} & a_{12} & ... & a_{1n}\\ a_{21}& a_{22}& ...&a_{2n} \\ ...& ...& ...& ...\\ a_{m1}& a_{m2}& ...& a_{mn}\\ \end{array} \right) \, \Longrightarrow \, \hbox{Deklaration: double A[m][n];} \end{equation} \] In gleicher Weise wie auch bei eindimensionalen Arrays sind mehrdimensionale C++ Arrays mittels des Konstruktes des Zeigers implementiert und die einzelnen Elemente eines Arrays (z.B. "double A[m][n]") sind im Hauptspeicher in Form von Zeigern/Referenzen geordnet.
Der zweite Teil der Vorlesung befasst sich mit dem Thema der numerischen Differentiation. Die Ableitung (Differentiation) einer Funktion stellt ein fundamentales Konzept der Mathematik dar, welches bei der Formulierung von physikalischen Bewegungsgleichungen essenziell ist. Die mathematische Definition der Ableitung einer Funktion, der sogenannte Differentialquotient, benutzt dabei eine Grenzwert-Formulierung ($h \to 0$), wobei in der numerischen Mathematik hingegen mehrere Differentiationsregeln formuliert werden, die den wirklichen Wert der Ableitung approximieren. Die analytische Herleitung dieser Regeln benutzt die Methode der Lagrange Polynome (siehe Anwendungsbeispiel: Interpolation und Polynomapproximation). Im zweiten Unterpunkt des linken Frames dieser Vorlesung wird die Herleitung der Differentiationsregeln mittels eines Python Jupyter Notebooks behandelt und im dritten Unterpunkt werden die Differentiationsregeln in einem C++ Programm verwendet, um die Ableitung einer Funktion $f(x)$ approximativ zu bestimmen.

Vorlesung 7

In dieser Vorlesung werden wir den Programmier- und Programmentwurfstil der objektorientierten Programmierung kennenlernen. Die gesamte Idee der objektorientierten Programmierung beruht gänzlich auf dem Konzept der Klasse. Eine C++ Klasse ist ein benutzerdefinierter neuer Datentyp, der durch das Schlüsselwort 'class' gekennzeichnet wird. Außerdem werden wir, nachdem wir in einem Jupyter Notebook die Integrationsregeln hergeleitet haben, den Anwendungsfall der numerischen Integration betrachten.

Objekt-orientierte Programmierung und C++ Klassen

Die meisten Programmiertechniken, die wir bis jetzt kennengelernt haben, verwendeten den Programmentwurfstil der prozeduralen Programmierung. Wir werden nun den Fokus auf die Strukturierung von Programmen legen (das Programmierparadigma der objektorientierten Programmierung) und auf das in C++ integrierte Klassenkonzept eingehen. Das Konzept der objektorientierten Programmierung beruht auf der alltäglichen Erfahrung, dass man Objekte nach zwei Maßstäben beurteilt: Ein Objekt besitzt einerseits messbare Eigenschaften und ist aber auch andererseits über seine Verhaltensweisen definiert. Eine C++ Klasse ist ein benutzerdefinierter neuer Datentyp, der durch das Schlüsselwort 'class' gekennzeichnet wird und die gesamte Idee der objektorientierten Programmierung beruht gänzlich auf diesem Konzept der Klasse. In einer C++ Klasse werden die messbaren Eigenschaften des Objektes in Instanzvariablen (Daten-Member) gespeichert und durch Konstruktoren werden diese Daten-Member dann initialisiert. Die Verhaltensweisen des Objektes werden durch klasseninterne Funktionen, die sogenannten Member-Funktionen beschrieben (näheres siehe Objekt-orientierte Programmierung und C++ Klassen).

Theorie: Numerische Integration

Wir betrachten in diesem Unterpunkt die Methode der numerischen Integration mittels der "Geschlossenen Newton-Cotes Gleichungen" (closed Newton-Cotes formulars). Die Vorgehensweise der Herleitung dieser Gleichungen erfolgt, indem man die zu integrierende Funktion $f(x)$ in ein Lagrange Polynom vom Grade N ($P_N(x)$) entwickelt ((siehe Anwendungsbeispiel: Interpolation und Polynomapproximation)) und dann durch analytische Integration zur Approximation gelangt. Beim Klicken auf die nebenstehende Abbildung gelangen Sie zu einem Jupyter Notebook, das die Herleitung der einzelnen Integrationsregeln veranschaulicht und speziell die Trapez-Regel ($N=1$), die Simpson's-Regel ($N=2$), die Simpson's-3/8-Regel ($N=3$) und die $N=4$-Regel behandelt. Möchte man eine Funktion jedoch über ein großes Intervall integrieren, so liefern auch die höheren N-Regeln keine genaue Approximation. Man sollte dann eine iterative, stückweise numerische Integration verwenden, wobei man innerhalb der einzelnen Teilstücke eine der oberen Integrationsregeln verwendet. Die nebenstehende Abbildung veranschaulicht diese stückweise numerische Integration, wobei das Integrationsintervall $[2,4]$ in drei Teilintervalle unterteilt wurde und in den jeweiligen Teilintervallen die Simpson's-Regel verwendet wurde (näheres siehe Theorie: Numerische Integration).

Anwendungsbeispiel: Numerische Integration

Die im vorigen Unterpunkt hergeleiteten Integrationsregeln der numerischen Mathematik sind im Folgenden nochmals zusammenfassend dargestellt: \[ \begin{eqnarray} \hbox{Die Trapez-Regel (N=1):}\,\, & \,\, \int_a^b f(x) \, dx \approx \frac{(x_1 - x_0)}{2} \cdot \left( f(x_0) + f(x_1) \right) = \frac{h}{2} \cdot \left( f(x_0) + f(x_1) \right) & \\ \hbox{Die Simpson's-Regel (N=2):}\,\, & \,\, \int_a^b f(x) \, dx \approx \frac{h}{3} \cdot \left( f(x_0) + 4 f(x_1) + f(x_2) \right) & \\ \hbox{Die Simpson's-3/8-Regel (N=3):}\,\, & \,\, \int_a^b f(x) \, dx \approx \frac{3 \, h}{8} \cdot \left( f(x_0) + 3 f(x_1) + 3 f(x_2) + f(x_3) \right) & \\ \hbox{Die N=4 Regel:}\,\, & \,\, \int_a^b f(x) \, dx \approx \frac{2 \, h}{45} \cdot \left( 7 f(x_0) + 32 f(x_1) + 12 f(x_2) + 32 f(x_3) + 7 f(x_4) \right) & \end{eqnarray} \] , wobei die jeweiligen Stützstellen $x_i$ in gleichförmiger Weise zwischen den Integrationsgrenzen aufgeteilt werden (z.B. für die N=4 Regel: $(x_0=a, x_1=x_0 + h, x_2=x_0 + 2h, x_3=x_0 + 3h, x_4=x_0 + 4h=b)$. In diesem Unterpunkt werden die Integrationsregeln in einem C++ Programm verwendet, um das bestimmte Integral der Funktion $f(x)= 10 \, e^{-x/10} \cdot \hbox{sin}(x)$ in den Grenzen [2,4], mittels der numerischen Integrationsregeln, approximativ berechnet: $\int_2^4 10 \, e^{-x/10} \cdot \hbox{sin}(x) \, dx$ (näheres siehe Anwendungsbeispiel: Numerische Integration).

Weitere Links

Vorlesung 7

Mittels der bisher erlernten Programmierkonzepte können wir bereits viele umfangreiche Berechnungen durchführen und Sie werden auch bald an Ihrem eigenen Programmier-Projekt arbeiten. Als Programmierer eines umfangreichen Programmes kommt man sich manchmal wie ein Schöpfer einer neuen fiktiven, virtuellen Kreatur vor und in dieser Vorlesung werden wir eine ganz neue Art von Herangehensweise bei der Erschaffung eines Programmes erlernen. Mittels eigener, dem Problem angepasster Programmierobjekte ist es durch einen Abstraktionsmechanismus möglich, eine geordnete Struktur in den Ideenreichtum eines C++ Quelltextes bringen. Eine Klasse stellt dabei den Bauplan für das zu konstruierende Objekt bereit und die wirkliche Realisierung des Objektes (die Instanzbildung) findet dann im Hauptprogramm zur Laufzeit statt. Eine Klasse stellt somit eine formale Beschreibung dar, wie das Objekt beschaffen ist, d.h. welche Merkmale (Instanzvariablen bzw. Daten-Member der Klasse) und Verhaltensweisen (Methoden der Klasse bzw. Member-Funktionen) das zu beschreibende Objekt hat. Eine Klasse ist also eine Vorlage, eine abstrakte Idee, die ein Grundgerüst von Eigenschaften und Methoden vorgibt. Die Erzeugung eines Objektes dieser Klasse entspricht der Materialisierung dieser Idee im Programm. Bei der Erzeugung (Materialisierung) des Objektes wird der sogenannte Konstruktor der Klasse aufgerufen, und verlässt das Objekt den Gültigkeitsbereich seines Teilbereiches des Programms, wird es durch den sogenannten Destruktor wieder zerstört. Das Grundgerüst einer Klasse besitzt die folgende Form (siehe untere Box), wobei im Anweisungsblock der Klasse nicht alle der aufgezählten Größen deklariert bzw. definiert werden müssen.

class Klassenname {
    Private Instanzvariablen (Daten-Member)
    
    public:
        Konstruktoren
        Member-Funktionen
        (Destruktor)
}; 

Vorlesung 8

Die Container der Standardbibliothek, insbesondere der sequentielle Container <vector>, sind ein wichtiges Abstraktionskonstrukt, das man einfach in seinen eigenen Programmen verwenden kann. In dieser Vorlesung werden wir im ersten Unterpunkt die Klasse <vector>, kennenlernen und auf unterschiedliche Beispiele anwenden. Der zweite Unterpunkt befasst sich dann mit dem numerischen Lösen von Differentialgleichungen erster Ordnung.

C++ Container und die vector Klasse der Standardbibliothek

Die C++ Standardbibliothek verfügt über eine Vielzahl nützlicher Programmierkonstrukte und ein oft verwendetes Klassenkonzept sind die sogenannten C++ Container. Ein Container ist ein Objekt, das eine Sammlung von Elementen aufnimmt. Die verfügbaren STL-Container gliedern sich in sequentielle Container (wie z.B. '<vector>' und '<list>') und ungeordnete/geordnete assoziative Container (wie z.B. '<map>' und '<unordered_map>'). In diesem Unterpunkt werden wir uns mit dem Container <vector> näher befassen. Der STL-Container <vector> stellt einen sequenziellen Typ von Objekten dar und ist somit eine Sequenz von Elementen eines bestimmten Typs. Man kann sich die Struktur eines vector-Objektes als ein eindimensionales Array vorstellen, bei welchem man zusätzlich noch die Anzahl der Elemente im Programmverlauf verändern kann. Außerdem stellt die vector-Klasse mehrere Memberfunktionen bereit, die einem bei der Konstruktion des Vektors helfen. Wir gehen zunächst auf die Klassenstruktur des standard Containers <vector> ein und verdeutlichen das Konzept des Vektors anhand von Integer Vektoren. Man kann die Klasse <vector> jedoch auch als ein Container von Objekten verwenden. Dies verdeutlichen wir anhand einer Simulation von nicht-wechselwirkenden Ding-Objekten (siehe nebenstehende Abbildung; näheres siehe C++ Container und die vector Klasse der Standardbibliothek).

Differentialgleichungen: Numerische Lösung von Anfangswertproblemen

In diesem Unterpunkt werden wir unterschiedliche Verfahren zum Lösen von Differentialgleichungen (DGL) erster Ordnung kennenlernen. Zunächst wird der iterative Algorithmus zum numerischen Lösen einer DGL am Beispiel des einfachen Euler Verfahrens beschrieben und auf die DGL $\dot{y}(t) = - y(t)$ angewandt. Danach werden einige weitere Verfahren zum Lösen einer DGL erster Ordnung vorgestellt (Mittelpunktmethode, Modifizierte Euler Methode, und Runge-Kutta Ordnung vier Methode) und in einem C++ Programm auf die DGL $\dot{y}(t) = y(t) - t^2 + 1$ angewandt. Am Ende werden die simulierten Zeitentwicklungen der unterschiedlichen Verfahren in einem Jupyter Notebook visualisiert und miteinander verglichen. Zusätzlich wird in diesem Notebook auch die numerische Lösung direkt in Python generiert (Methode "integrate.odeint()" im Python-Modul "scipy"). Näheres siehe Differentialgleichungen: Numerische Lösung von Anfangswertproblemen.

Weitere Links

Vorlesung 8

In der vorigen Vorlesung hatten wir das Klassenkonzept kennengelernt und eine Beispielklasse 'Ding' erstellt. Hierbei wurden die messbaren Eigenschaften des Dings (Daten-Member der Klasse) von den Verhaltensweisen des Dings (Member-Funktionen der Klasse) getrennt in der Klasse implementiert. Wie programmiert man die Verhaltensweisen eines Objektes? Das Verhalten eines Objektes unter einem einwirkenden Einfluss stellt eine Art von zeitlichem Verlauf dar. In Abhängigkeit von der jeweiligen Fragestellung und Natur des physikalischen Problems sind zwei generelle Programmzweige von zeitlich veränderlichen Systemen zu identifizieren: Die Agenten-basierte Simulation und Simulationen von physikalischen Bewegungsgleichungen. Im ersten Teil dieser Vorlesung (siehe C++ Container und die vector Klasse der Standardbibliothek) werden wir eine Art von Agenten-basierte Simulation kennenlernen. Die 'Agenten' stellen in diesem Fall die Teilchen in einer Kiste dar, die als Objekte der Klasse 'Ding' erzeugt wurden. Die zeitliche Entwicklung wird hierbei über eine Member-Funktion realisiert.
Im zweiten Teil werden wir dann sehen, wie man eine zeitliche Entwicklung eines Systems unter Verwendung seiner Bewegungsgleichungen simuliert (näheres siehe Differentialgleichungen: Numerische Lösung von Anfangswertproblemen). In dieser und der folgenden Vorlesung werden wir uns den Themenbereich des numerischen Lösens von Differentialgleichungen näher betrachten und mehrere Verfahren zum Lösen von Differentialgleichungen erster Ordnung kennenlernen. Die einzelnen Verfahren werden dann in einem C++ Programm implementiert und miteinander verglichen. Zusätzlich wird in einem Jupyter Notebook gezeigt, wie man mittels Python auch numerisch eine Differentialgleichung lösen kann.

Vorlesung 9

In dieser Vorlesung befassen wir uns zunächst mit dem numerischen Lösen von Systemen gekoppelter Differentialgleichungen und Differentialgleichungen zweiter Ordnung und stellen im darauf folgenden Teil mögliche Programmierprojekte vor, die von den Studierenden bearbeitet werden können. Beim Klicken auf die Überschriften der Projekte gelangen Sie zu einer detaillierteren Beschreibung der einzelnen Projektthemen.

Systeme von gekoppelten Differentialgleichungen und Differentialgleichungen zweiter Ordnung

In der vorigen Vorlesung hatten wir die unterschiedlichen Verfahren zum Lösen von Differentialgleichungen erster Ordnung kennengelernt. Die Bewegungsgleichungen vieler physikalischer Systeme sind jedoch von zweiter Ordnung in der Zeit und in diesem Teilkapitel beschreiben wir die Vorgehensweise wie man solche Differentialgleichungen höherer Ordnung numerisch mittels eines C++ Programmes löst. Um ein Differentialgleichung zweiter Ordnung mittels des Computers lösen zu können, schreibt man zunächst die DGL in ein System von zwei gekoppelten Differentialgleichungen ersten Ordnung um und diese löst man dann mit den Verfahren, die in der vorigen Vorlesung behandelt wurden. In diesem Unterpunkt werden wir uns zunächst mit Systemen von gekoppelten Differentialgleichungen erster Ordnung befassen und dann das numerische Lösen von Differentialgleichungen zweiter Ordnung vorstellen (näheres siehe Systeme von gekoppelten Differentialgleichungen und Differentialgleichungen zweiter Ordnung).

Studentische Projekte

Das Foucaultsche Pendel

Im Jahre 1851 gelang Jean Bernard Léon Foucault ein anschaulicher Beweis der Erdrotation. Aufgrund der, in rotierenden Bezugssystemen auftretenden Coriolisbeschleunigung, dreht sich die Schwingungsebene des Pendels langsam. Dieses Projekt ist ein Anwendungsfall der Newtonschen Mechanik in bewegten Bezugssystemen (siehe z.B. Walter Greiner, 'Klassische Mechanik II' [8. Auflage, 2008, Kapitel I3. Seite 18]) und das zugrundeliegende System von drei gekoppelten Differentialgleichungen zweiter Ordnung gilt es numerisch mittels eines C++ Programmes zu lösen und die berechneten Daten mittels Python zu visualisiern.

Das periodisch angetriebene Pendel

Das Projekt periodisch angetriebenes Pendel ist ein Anwendungsfall aus der klassischen Mechanik (siehe z.B. Walter Greiner, 'Klassische Mechanik II' [8. Auflage, 2008, Kapitel VII27. Seite 496]). Das System besteht aus einem Pendel, auf welches zusätzlich eine äußere Kraft mit periodischer Zeitabhängigkeit wirkt. Außerdem soll das Pendel durch eine geschwindigkeitsabhängige Luftreibung gedämpft sein. Die zugrundeliegende Bewegungsgleichung des periodisch angetriebenen Pendels ist stark nichtlinear und die, nur auf numerischem Weg zu berechnenden Lösungen, zeigen deterministisch chaotische Bewegungen.

Das Doppelpendel

Das Projekt Doppelpendel ist ein Anwendungsfall aus der klassischen Mechanik (siehe untere Animation). Das System besteht aus zwei miteinander verbundenen Pendeln, wobei wir die Luftreibung zunächst vernachlässigen. Die Herleitung der Bewegungsgleichungen des Doppelpendels erfolgt am elegantesten mittels der Euler-Lagrange Gleichungen, bzw. mittels der Hamilton Theorie. Mittels der Lagrange-Gleichungen gelangt man zu zwei gekoppelten Differentialgleichungen zweiter Ordnung, die man dann in ein System von vier gekoppelten DGLs erster Ordnung umschreiben muss um es numerisch lösen zu können. Die zugrundeliegende Bewegungsgleichung des Doppelpendels ist stark nichtlinear, sodass kleine Abänderungen in den Anfangswerten, nach einiger Zeit qualitativ unterschiedliche Bewegungen zur Folge haben (deterministisches Chaos).

Die schwingende Kette

Das Projekt Die schwingende Kette ist ein zentrales Beispiel eines schwingenden Massensystems, ein Problem aus der klassischen Mechanik (siehe Walter Greiner, 'Klassische Mechanik II' [8. Auflage, 2008, Kapitel I7. Seite 76]). Das System besteht aus einem masselosen Faden, der mit $N+1$ Massenpunkten (Dingen, Teilchen, Perlen) besetzt ist. Die $N+1$ 'Perlen' sollen in diesem Projekt als Objekte einer Klasse programmiert werden. Jede Perle besitzt eine ganzzahlige Instanzvariable $n$ (die Nummer der Perle) und die erste ($n=0$) und letzte Perle ($n=N+1$) wird so befestigt, dass sie sich nicht im Raum bewegen können. Die Bewegungsgleichung der schwingenden Kette stellen ein System von $N$ Differentialgleichungen zweiter Ordnung dar. Es sollen die Spezialfälle $N=2$ und $N=3$ mit einem C++ Programm simuliert werden um dann durch Erhöhung der Teilchenzahl den Kontinuums-Grenzwert der schwingenden Saite (siehe Walter Greiner, 'Klassische Mechanik II' [8. Auflage, 2008, Kapitel I8. Seite 88]) approximativ abbilden zu können.

Planetenbewegungen

In diesem Projekt wird die Bewegung eines Körpers in einem gravitativem Zentralkraftfeld untersucht. Die Bewegungsgleichung eines Massenpunktes (Venus, Erde) im Gravitationsfeld der Sonne ist ein oft behandeltes System in der klassischen Mechanik (siehe z.B. Walter Greiner, 'Mechanik Teil 1' [5. Auflage, 1989, Kapitel 26. Seite 266])). Die Bewegungsgleichungen des betrachteten Systems in drei Dimensionen, formuliert mittels der Newtonschen Gravitationstheorie, stellen ein System von drei gekoppelten Differentialgleichungen 2. Ordnung dar, die man dann in ein System von sechs gekoppelten DGLs erster Ordnung umschreiben muss um es numerisch lösen zu können.

Räuber-Beute Simulationen

Das Projekt Räuber Beute Simulation hat Ihren Ursprung im Fachgebiet der Populationsökologie (bzw. Populations-/Evolutionsbiologie). Die Räuber-Beute Gleichung beschreibt den natürlichen Überlebenskampf mehrerer Spezies, die einander auffressen. Die Population der Räuberwesen ernährt sich von der Population der Beutewesen und sinkt die Anzahl der Beutewesen, so erniedrigt sich die Reproduktionsrate der Räuberwesen, da diese Hunger erleiden müssen. Das Projekt besteht aus zwei formell getrennten Simulationen: Eine Agenten-ähnliche Simulation auf individueller Lebewesen Formulierung und eine Simulation, die auf Basis einer analytischen Räuber-Beute Gleichung.

Weitere Links

Vorlesung 9

Das numerische Lösen von Differentialgleichungen ist ein mathematisch anspruchsvolles Thema und kann in dieser Vorlesung nicht im Detail erläutert werden. Im ersten Teil dieser Vorlesung sollen die im vorigen Unterpunkt (Differentialgleichungen: Numerische Lösung von Anfangswertproblemen) besprochenen Verfahren auf Systeme von gekoppelten Differentialgleichungen und Differentialgleichungen zweiter Ordnung angewendet werden. Die Bewegungsgleichungen vieler physikalischer Systeme sind von zweiter Ordnung in der Zeit und es soll die Vorgehensweise besprochen werden, wie man solche Differentialgleichungen höherer Ordnung numerisch mittels eines C++ Programmes löst.
Ab der nächsten Vorlesung (Vorlesung 10) werden die Studierenden dann an eigenen Projekten arbeiten, wobei viele dieser Projekte Probleme behandeln, die man nur mittels einer numerischen Lösung adäquat beschreiben kann (siehe linkes Panel dieser Vorlesung). Beim Klicken auf die Überschriften der Projekte gelangen Sie zu einer detaillierteren Beschreibung der einzelnen Projektthemen. Neben den hier vorgestellten Projekten, können auch eigene Projektthemen behandelt werden. Bei Interesse können auch Projekte aus dem Bereich der Physik der sozio-ökonomischen Systeme (z.B. Replikatordynamik der Evolutionären Spieltheorie, Simulationen von komplexen Netzwerken), oder Projekte im Themengebiet der allgemeinen Relativitätstheorie (z.B. Bewegung um ein schwarzes Loch mittels der Geodätengleichung, näheres siehe Allgemeine Relativitätstheorie mit dem Computer)) behandelt werden. Die studentischen Projekte können alleine oder in Gruppen (bis zu drei Personen) durchgeführt werden.

Vorlesung 10

In dieser Vorlesung werden wir zunächst die ersten Teilaufgaben eines weiteren Projektes (das Projekt Achterbahn) exemplarisch besprechen. Es wird gezeigt, wie man die Bewegungsgleichungen des betrachteten Systems unter Verwendung der Euler-Lagrange Gleichungen mittels eines Jupyter Notebooks generiert. Das Umschreiben der DGL zweiter Ordnung in ein System von zwei DGLs erster Ordnung und die Implementierung und Lösung der Gleichungen mittels eines C++ Programmes wird ebenfalls beispielhaft vorgeführt. Die weiteren Teilaufgaben des Projektes wurden hingegen noch nicht bearbeitet, sodass Studierende auch dieses Projekt weiter bearbeiten können. Im zweiten Unterpunkt der Vorlesung werden wir auf die Vererbung von Klassenmerkmalen bei abgeleiteten Klassen und auf Klassenhierarchien eingehen.

Beispiel Projekt: Die Achterbahn

Das Projekt Achterbahn ist ein Anwendungsfall aus der klassischen Mechanik. Das Problem ist eine Verallgemeinerung des Problems "Bewegung eines Massenpunktes auf einer Zykloidenbahn" (siehe Aufgabe 15.7: Walter Greiner, 'Klassische Mechanik II' [8. Auflage, 2008, Kapitel V15. Seite 271]). Das System besteht aus zwei Achterbahn-Wagen unterschiedlicher Massen $m_i \, , \,\, i \in [0,1]$, die reibungsfrei auf einer Metallschiene gleiten können. Die Achterbahn hat eine Länge von $l \, [m]$ und besitzt keine Kurven, sodass man den Verlauf der Metallschiene der Achterbahn als eine eindimensionale Funktion $h(x) \, , \,\, x \in [-l/2, l/2]$ beschreiben kann, wobei $h(x)$ die Höhe der Metallschiene der Achterbahn an der Position $x$ in der Einheit Metern beschreibt. Die Herleitung der Bewegungsgleichungen erfolgt am elegantesten mittels der Euler-Lagrange Gleichungen, bzw. mittels der Hamilton Theorie. Die Bewegung eines Wagens wird durch eine Differentialgleichung zweiter Ordnung bestimmt und diese hängt nicht von dem Wert der Masse des Wagens ab. Um diese DGL zweiter Ordnung numerisch lösen zu können, schreibt man sie in ein System von zwei DGLs erster Ordnung um. Die nebenstehende Animation visualisiert die C++ Simulation zweier Wagen, wobei der Verlauf der Metallschiene der Achterbahn durch die Funktion $h(x) = e^{\frac{\sqrt{x^2}}{10}} \cdot \left( \hbox{sin}\left( \frac{x^2}{10} \right) \right)^2$ gegeben ist. Jeder der Achterbahn-Wagen besitzt nun am vorderen und hinterem Bereich eine extrem starke und robuste Metallfeder, die zum Einsatz kommt, wenn sich zwei der Wagen treffen. Es wird dabei angenommen, dass es sich bei einem Zusammenprall der Wagen um einen elastischen Stoß zweier Körper handelt (näheres siehe Beispiel Projekt: Die Achterbahn).

Abgeleitete Klassen, Vererbung von Klassenmerkmalen und Klassenhierarchien

Im zweiten Unterpunkt der Vorlesung werden wir auf die Vererbung von Klassenmerkmalen bei abgeleiteten Klassen eingehen. C++ Klassen stehen häufig in Beziehung zueinander. Man hat beispielsweise eine Oberklasse (z.B. Pendel), und aus dieser leitet sich eine andere Klasse (z.B. mathematisches Pendel, oder physikalisches Pendel) ab. Diese abgeleitete Klasse (auch Subklasse) erbt dann bestimmte Eigenschaften der Daten-Member und Member-Funktionen der Oberklasse 'Pendel' (auch Basisklasse oder Superklasse). Die Superklasse hat dabei oft einen übergeordneten, abstrakten Charakter und es können in ihr virtuelle Funktionen deklariert werden, die in den jeweiligen abgeleiteten Klassen dann definiert werden. In umfangreichen C++ Programmen baut sich somit eine Art von Klassenhierarchie auf und oft werden dabei auch sogenannte Templates eingesetzt, auf die wir erst in der nächsten Vorlesung eingehen werden. Die nebenstehende Abbildung zeigt die Simulation eines physikalischen Pendels mit Stokesschem Reibungsterm. Das zugrundeliegende C++ besitzt eine Superklasse 'Ding', die als eine Schnittstelle der kartesischen Orte und Geschwindigkeiten des Pendels fungiert. Von ihr wurde die Klasse 'Pendel' des physikalischen Pendels abgeleitet (Schnittstellenvererbung) und von dieser die Sub-Subklasse 'Pendel_math' des mathematischen Pendels (harmonischer Oszillator mit Reibung) abgeleitet (Implementierungsvererbung). Näheres siehe Abgeleitete Klassen, Vererbung von Klassenmerkmalen und Klassenhierarchien.

Weitere Links

Vorlesung 10

Einige der im vorigen Kapitel vorgestellten studentischen Projekte benutzen die Programmiersprache Python zunächst zum Aufstellen der zugrundeliegenden Bewegungsgleichungen des betrachteten Systems. Die Herleitung der Bewegungsgleichungen eines physikalischen Systems mittels der Euler-Lagrange Gleichungen, ist ein eleganter mathematischer Trick, um auch komplizierte Systeme analytisch beschreiben zu können. Mittels eines Jupyter Notebooks unter Verwendung der SymPy Bibliothek ist eine solche Herleitung auch auf dem Computer gut zu implementieren. Im ersten Teil dieser Vorlesung wird ein zusätzliches studentisches Projekt besprochen (siehe Projekt: Die Achterbahn), das eine solche analytische Herleitung der Bewegungsgleichungen exemplarisch, beispielhaft zeigt. Die mittels des Python Jupyter Notebooks 'Achterbahn_2.ipynb' (View Notebook, Download Notebook) gefundene Bewegungsgleichung wird dann in ein System von erster Ordnung Differentialgleichungen umgeschrieben und mittels eines C++ Programms numerisch gelöst. Die simulierten Daten werden dann mittels Python in einer Animation visualisiert (siehe Video im linken Panel dieser Vorlesung). Es wird für die ersten Teilaufgaben des Projektes eine Musterlösung: Projekt Achterbahn vorgestellt und die weiteren Teilaufgaben können als studentisches Projekt bearbeitet werden.
Im zweiten Teil dieser Vorlesung betrachten wir weitere wichtige Sprachkonstrukte der Programmiersprache C++. C++ Klassen stehen häufig in Beziehung zueinander und die hierarchische Einteilung in Basisklasse (auch Oberklasse oder Superklasse) und abgeleitete Klasse (auch Subklasse) und das Konzept der Vererbung von Merkmalen der Basisklasse an die Subklasse, ist ein oft verwendetes und nützliches Konstrukt bei der Erstellung von umfangreichen C++ Programmen. Die Vererbung von Klassenmerkmalen kann in Form einer Schnittstellenvererbung oder/und Implementierungsvererbung geschehen. Die Konzepte der Vererbung werden zunächst an einfachen Beispielen erläutert und danach wird der Vererbungsmechanismus am Beispiel des Pendels erläutert.

Vorlesung 11

Die bisher behandelten Inhalte fokussierten sich dabei, einerseits auf die C++/Python Grundlagen der objektorientierten Programmierung und andererseits auf die numerischen Algorithmen zum Lösen des betrachteten physikalischen/mathematischen Systems. Mittels der erlernten Konzepte sollte es nun den Studierenden möglich sein, die numerische Lösung eines komplexen physikalischen Problems auf dem Computer zu simulieren. Viele der Arbeitsgruppen am Institut für Theoretische Physik der Goethe-Universität arbeiten an speziellen, nur numerisch lösbaren Teilaspekten der Physik und, die zur Simulation verwendeten hochkomplexen Programme, sind oft in unzähligen Teil-Quelltexten zu einem Programm zusammengefügt. Im ersten Unterpunkt dieser Vorlesung wird den Studierenden gezeigt, wie man zurzeit am Institut an größeren Projekten arbeitet.

Projektstruktur und Dinge die man über C++ wissen sollte

Arbeitet man als Physiker in einer Gruppe an einem großen Simulationsprogramm, dann ist eine geordnete Projektstruktur von Anfang an wichtig. Die Struktur der unzähligen Teilquelltexte und das gemeinsame Arbeiten und Verändern von diesen erfordert eine verteilte Versionsverwaltung der C++ Quelltexte (z.B. die freie Software zur verteilten Versionsverwaltung von Dateien Git). In diesem Unterpunkt wird gezeigt, wie die Projektstruktur eines Großprojektes organisiert wird und wie die Dateistruktur eines komplexen Programms aufgebaut ist.

Johannes Misch und Alexander Gehwald, zwei Mitarbeiter der Gruppe von Prof. Carsten Greiner am Institut für Theoretische Physik, werden vorstellen, wie man zurzeit am Institut an größeren Projekten arbeitet. Beim Klicken auf die nebenstehende Abbildung gelangen Sie zu der erstellten Internetseite dieses Unterpunktes. Zusätzlich werden in diesem Unterpunkt die noch nicht besprochenen Themenbereiche der C++ Compiler versions, des ISO Standards, der C++ Templates, des 'Resource accquisition is initialization' (RAII) und der C++ Core Guidelines kurz vorgestellt ( näheres siehe Projektstruktur und Dinge die man über C++ wissen sollte).

Klausurvorbereitung und prüfungsrelevante Themen

Im Hinblick auf die anstehende Klausur werden in diesem Unterpunkt die prüfungsrelevanten Inhalte der einzelnen Vorlesungen aufgelistet und Beispielaufgaben und deren Musterlösungen besprochen. Näheres siehe Klausurvorbereitung und prüfungsrelevante Themen.

Weitere Links

Vorlesung 11

Diese Vorlesung stellt den vorletzten Teil der Veranstalltung Einführung in die Programmierung für Studierende der Physik dar. Die Vorlesung gab einerseits eine Einführung in die Objekt-orientierte Programmiersprache C++ und vermittelt andererseits einige wesentliche Grundlagen der numerischen Mathematik. Es wurden die grundlegenden Elemente der Programmiersprachen C++ und Python und das Programmierparadigma der Objektorientierung behandelt - C++ und Python für Physiker. Die Zuhörer dieser Vorlesung sollten nun in der Lage sein, die numerische Lösung eines komplexen physikalischen Problems auf dem Computer zu erstellen. Manchmal arbeitet man aber als Physiker in einer ganzen Gruppe aus Programmierern an einem großen Simulationsprogramm. In diesem Unterpunkt wird gezeigt, wie die Projektstruktur eines Großprojektes organisiert wird und wie die Dateistruktur eines solchen komplexen Programms aufgebaut ist.
Der zweite Teil dieser Vorlesung befasst sich mit den prüfungsrelevanten Inhalten der anstehenden Klausur und es werden Beispielaufgaben und deren Musterlösungen vorgestellt.

Vorlesung 12

In dieser Vorlesung wird zunächst auf das Paradigma der parallelen Programmierung und das Rechnen auf Supercomputern eingegangen. Bei aufwendigen und rechenintensiven großen Programmen ist es oft nötig, die Programme zu parallelisieren; d.h. den Quelltext des Programms so umzuschreiben, dass einzelne, voneinander unabhängige Teil-Tasks gleichzeitig nebeneinander ausgeführt werden können. Im zweiten Punkt werden zwei aktuelle, komplexe Anwendungsbeispiele vorgestellt, bei denen die theoretisch, physikalische Forschung auf Computersimulationen angewiesen ist.

Das Paradigma der parallelen Programmierung und das Rechnen auf Supercomputern

Computersimulationen von realistischen, komplizierten Problemen erfordern sogar auf Supercomputern (Hochleistungs-Großrechenanlagen, bei denen eine große Anzahl von Mehrprozessor-Computern zu einem Computer-Cluster System verbunden sind) oft eine enorme Rechenzeit. Bei der Konzeption der Simulationsprogramme ist es deshalb erforderlich, dass die Rechenleistung des Computers stets voll ausgelastet ist und separate, voneinander unabhängige Teilaufgaben innerhalb der Programme gleichzeitig (parallel) berechnet werden. Das Paradigma der parallelen Programmierung ist die Art und Weise, wie man ein Programm gestaltet, damit die in dem Programm enthaltenen Teilberechnungen (Tasks) möglichst gleichzeitig, nebeneinander berechnet werden können. Diese Nebenläufigkeit der Programmstränge, die gleichzeitige Ausführung mehrerer Tasks, lässt sich in vielen Programmiersprachen (nicht nur C++ und Python) relativ einfach mittels OpenMP (Open Multi-Processing) parallelisieren. Das in der vorigen Vorlesung dargestellte Programm "Eine Kiste voller Pendel" (siehe Vorlesung 11, Unterpunkt Klausurvorbereitung und prüfungsrelevante Themen) wird in diesem Unterpunkt verwendet, um das Prinzip der parallelen Programmierung zu erläutern. Näheres siehe Das Paradigma der parallelen Programmierung und das Rechnen auf Supercomputern.

Anwendungsbeispiele und weiterführende Vorlesungen

Die Anwendungsmöglichkeiten der Programmierung sind vielschichtig und speziell im Bereich der theoretischen Physik, sind viele der aktuellen Forschungsfragen nur mittels aufwendiger Computersimulationen lösbar.

Eines dieser aktuellen Anwendungsfelder ist die numerische relativistische Astrophysik und die numerische allgemeine Relativitätstheorie. Das Einstein Toolkit (ET) ist eine Softwareplattform, mit der man Probleme aus dem Bereich der relativistischen Astrophysik und Gravitationsphysik nummerisch am Computer simulieren kann. Das ET entwickelte sich im Jahre 1998 aus dem Cactus Code und im Laufe der letzten 20 Jahre wurde seine Performance (hocheffiziente OpenMP/MPI Parallelisierung) und Anwendungsbreite ständig verbessert. Mittlerweile kann man mit dem frei zugänglichen ET-Code Kollisionen von schwarzen Löchern und Neutronensternen simulieren. Die nebenstehende Abbildungund zeigt einige Eigenschaften (Dichte, Temperatur, Rotationsprofil und Frame-Dragging) des in einer Neutronenstern-Kollision produzierten hypermassiven Neutronensterns und wurde mit dem ET simuliert und mittels Python visualisiert. Näheres siehe Vorlesung 'Allgemeine Relativitätstheorie mit dem Computer' und F+L-Praktikum am Institut für Theoretische Physik.

Der wissenschaftliche Untersuchungsgegenstand des zweiten aktuellen Anwendungsfeldes der Programmierung ist, im Gegensatz zum ersten, ein der menschlichen Wahrnehmung näheres. Die Spieltheorie ist ein bedeutendes Mittel zum modellhaften Verständnis komplexer sozioökonomischer Entscheidungs-Prozesse. In ihrer herkömmlichen Form werden die handelnden Akteure als rein rational und egoistisch handelnde Individuen aufgefasst (homo oeconomicus) und eine Population bestehend aus einer großen Anzahl von solchen interdependenten Entscheidern kann sich zu einem Dilemma-artigen Zustand entwickeln. Im Gegensatz zur Physik, die die Gesetzmäßigkeiten der leblosen Materie/Energie und deren Wechselwirkungen in Raum und Zeit betrachtet, ist in der evolutionären Spieltheorie das zu erforschende Ding, der Mensch, und wir sind daran interessiert, wie dieser sich bei ökonomischen oder sozial relevanten strategischen Entscheidungen verhält. Viele Wirtschafts- und Sozialwissenschaftler betrachten die Spieltheorie als die formale Sprache der ökonomischen Theorie. Agentenbasierte Computersimulationen von spieltheoretischen Problemen auf komplexen sozio-ökonomischen Netzwerken sind ein interdisziplinäres aktuelles Forschungsfeld; näheres siehe Vorlesung Physik der sozio-ökonomischen Systeme mit dem Computer im kommenden Wintersemester 2022/23.

Weitere Links

Vorlesung 12

Das Hauptanliegen dieser Vorlesung bestand darin, den Studierenden zu lehren, wie man eine numerische Lösung eines komplexen physikalischen Problems auf dem Computer erstellen kann. Studierende, die dabei Gefallen am Programmieren gefunden haben, empfehle ich (in eigener Sache) die folgenden weiterführenden Vorlesungen/Praktika:

In den oben genannten Vorlesungen und Praktika werden zwei, thematisch sehr unterschiedliche, Systeme mittels des Computers analysiert. Die im nächsten Semester (WS 2022/23) stattfindende Vorlesung Physik der sozio-ökonomischen Systeme mit dem Computer ist ein stark interdisziplinäres Forschungsfeld, in dem die unterschiedlichen Sprachen der Soziologie, der Wirtschaftswissenschaften, der Biologie, der Physik und der Mathematik aufeinander treffen, um zu beschreiben und zu verstehen, wie sich Menschen untereinander verhalten. Der wissenschaftliche Untersuchungsgegenstand, das zu erforschende Ding, ist hierbei der Mensch und wir sind daran interessiert, wie sich dieser bei ökonomischen oder sozial relevanten strategischen Entscheidungen verhält. Wir sind demnach auf der Suche nach einer Art von elementarer Theorie des menschlichen Verhaltens, ähnlich der physikalischen Elementarteilchen-Theorie und ihrer fundamentalen Wechselwirkungen und die Theorie, welche wir zur Beschreibung des interdependenten Entscheidungsverhaltens benutzen werden, ist die sogenannte Spieltheorie. Agentenbasierte, auf spieltheoretischen Grundannahmen basierende Computersimulationen von komplexen sozio-ökonomischen Systemen sind ein interdisziplinäres aktuelles Forschungsfeld, welches in der oben genannten Vorlesung im Detail besprochen wird. Die zweite Vorlesung (Allgemeine Relativitätstheorie mit dem Computer) und auch die von mir betreuten Themen des F+L-Praktikums befassen sich hingegen mit der numerischen Lösung von Problemen innerhalb der relativistischen Astrophysik und allgemeinen Relativitätstheorie (siehe auch linkes Panel dieser Vorlesung).