Ein Fliesenleger, der ein rechteckiges Bad auslegt, greift nicht zu Dreiecken. Er nimmt Rechtecke — sie passen ohne Verschnitt, Reihe an Reihe, und man sieht sofort, welche Fliese wohin gehört. Für unseren Träger, der selbst ein braves Rechteck ist, drängt sich dieselbe Idee auf: Warum ihn mühsam in acht Dreiecke zerschneiden, wenn vier Rechtecke ihn genauso bedecken?
In Kapitel 10 haben wir den Träger zur Fläche gemacht und mit Dreiecken gepflastert. Dieses Kapitel legt die zweite Elementfamilie daneben: das Rechteck. Und die spannende Frage ist nicht, ob es funktioniert — das tut es, mit derselben Maschinerie wie immer —, sondern worin es sich unterscheidet. Denn ein Rechteck ist nicht einfach „zwei Dreiecke im Sparpaket”. Es interpoliert anders, und dieser Unterschied ist die eigentliche Lehre des Kapitels.
Code
import matplotlib.pyplot as pltknoten = [(0.0, 0.0), (0.5, 0.0), (1.0, 0.0), (0.0, 0.05), (0.5, 0.05), (1.0, 0.05), (0.0, 0.10), (0.5, 0.10), (1.0, 0.10)]dreiecke = [(0, 1, 4), (0, 4, 3), (1, 2, 5), (1, 5, 4), (3, 4, 7), (3, 7, 6), (4, 5, 8), (4, 8, 7)]rechtecke = [(0, 1, 4, 3), (1, 2, 5, 4), (3, 4, 7, 6), (4, 5, 8, 7)]bx = [p[0] for p in knoten]by = [p[1] for p in knoten]fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11.0, 3.2))ax1.triplot(bx, by, dreiecke, color="tab:blue", lw=1.1)ax1.plot(bx, by, "o", color="tab:orange", ms=11, markeredgecolor="black")ax1.set_title("8 Dreiecke (Kapitel 10)", fontsize=10)for r in rechtecke: xs = [knoten[r[k]][0] for k in (0, 1, 2, 3, 0)] ys = [knoten[r[k]][1] for k in (0, 1, 2, 3, 0)] ax2.plot(xs, ys, color="tab:blue", lw=1.1)ax2.plot(bx, by, "o", color="tab:orange", ms=11, markeredgecolor="black")ax2.set_title("4 Rechtecke (dieses Kapitel)", fontsize=10)for ax in (ax1, ax2): ax.set_xlabel("Länge x (m)") ax.set_aspect("equal") ax.set_ylim(-0.03, 0.13)plt.tight_layout()plt.show()
Abbildung 11.1: Derselbe Träger, zwei Pflasterungen. Links das 8-Dreiecke-Netz aus Kapitel 10, rechts das 4-Rechtecke-Netz dieses Kapitels — beide auf demselben 3×3-Knotengitter (neun orange Knoten). Rechts sind es weniger Elemente, keine Diagonalen, und jede Zelle ist so regelmäßig wie der Träger selbst. Ob das auch die bessere Wahl ist, klärt dieses Kapitel.
Was man hier sieht: links das vertraute Dreiecksnetz, rechts das neue Rechtecknetz — dieselben neun Knoten, aber vier Rechtecke statt acht Dreiecke. Weniger Elemente, kein Diagonalen-Wirrwarr, alles rechtwinklig. Das sieht nach der aufgeräumteren Wahl aus. Ob sie es ist, hängt davon ab, wie ein Rechteck zwischen seinen vier Ecken interpoliert — und genau da beginnt die Geschichte.
Lernziele
Nach diesem Kapitel kannst du …
… auf einem Rechteck aus vier Eckwerten interpolieren, indem du erst in \(x\) und dann in \(y\) interpolierst („zweimal Strecke statt einmal Fläche”),
… erklären, warum die bilineare Fläche im Inneren gekrümmt ist (ein Sattel!), obwohl sie auf jeder Kante eine Gerade bleibt — und warum Rechtecke und Dreiecke deshalb kantenkompatibel sind,
… die vier Ansatzfunktionen des Rechtecks als Produkt zweier Hütchen hinzeichnen und ihre Eigenschaften prüfen,
… die 4×4-Elementmatrix eines Rechtecks als Summe von Produkten aus 1D-Integralen aufstellen und den Träger mit vier Rechtecken vernetzen,
… das Rechteck-System mit dem Dreieck-System vergleichen (gleiche Lösung, neun statt fünf Kopplungen pro innerem Knoten) und in einem Satz sagen, was „isoparametrisch” leistet und warum dieses Buch es nicht braucht.
WarnungNaheliegende Vermutung
Vermutung:„Ein Rechteck ist einfach zwei zusammengeklebte Dreiecke — dieselbe Interpolation, nur weniger Verwaltung.”
Warum sie naheliegt: Man kann jedes Rechteck mit einer Diagonale in zwei Dreiecke zerschneiden. Die Knoten sind dieselben, die Fläche ist dieselbe — also, so der Gedanke, muss auch das Ergebnis dasselbe sein. Das Rechteck wäre nur eine bequemere Verpackung für zwei Dreiecke.
Was stattdessen stimmt: Die bilineare Fläche über vier Ecken ist im Inneren gekrümmt — ein Sattel. Die zwei Dreiecke dagegen wären zwei ebene Platten mit einem Knick entlang der Diagonale. Und schlimmer: Je nachdem, welche der beiden Diagonalen man wählt, entsteht ein anderer Knick und ein anderer Wert im Inneren. Das Rechteck kennt diese Diagonalen-Willkür nicht — es hat gar keine Diagonale. Wie groß der Unterschied wird, rechnen wir in diesem Kapitel aus (er kann 280 Grad betragen).
11.1 Bilinear: zweimal interpolieren statt einmal
Fangen wir mit dem einen neuen Baustein an — dem Rest des Kapitels sieht man schon an, dass er die alte Maschinerie nicht anrührt. In Kapitel 10 zerlegte ein Punkt das Dreieck in drei Flächenanteile. Beim Rechteck gehen wir einen anderen, noch einfacheren Weg: Wir interpolieren zweimal hintereinander die gute alte Strecke aus Kapitel 7.
Stell dir ein quadratisches Blech vor, an dessen vier Ecken vier Temperaturfühler kleben: unten links 20 °C, unten rechts 300 °C, oben rechts 100 °C, oben links 40 °C. Gesucht ist die Temperatur an einer Stelle mittendrin. Das Rezept in zwei Schritten:
In \(x\)-Richtung interpolieren, und zwar auf der Unterkante und auf der Oberkante getrennt. Das gibt zwei Zwischenwerte — einen unten, einen oben, beide an der gewünschten \(x\)-Stelle.
In \(y\)-Richtung zwischen diesen beiden Zwischenwerten interpolieren. Fertig.
Nehmen wir den Mittelpunkt des Blechs (halbe Breite, halbe Höhe). Schritt eins auf der Unterkante: die Mitte zwischen 20 und 300 ist \(20 + \tfrac12\,(300-20) = 160\ °\mathrm{C}\). Auf der Oberkante: die Mitte zwischen 40 und 100 ist \(40 + \tfrac12\,(100-40) = 70\ °\mathrm{C}\). Schritt zwei, in der Höhe zwischen diesen beiden:
Abbildung 11.2: Bilinear ist zweimal linear. Schritt 1 (links): auf der Unterkante zwischen 20 und 300 interpolieren (Mitte 160) und auf der Oberkante zwischen 40 und 100 (Mitte 70). Schritt 2 (Mitte): senkrecht zwischen diesen beiden Zwischenwerten interpolieren — 160 und 70 ergeben in der Blechmitte 115 °C. Rechts das Ganze noch einmal als Draufsicht mit dem Rechenweg eingezeichnet. Die drei Interpolationen sind je eine schlichte Strecke wie in Kapitel 7.
Was man hier sieht: drei ganz gewöhnliche Strecken-Interpolationen. Zwei waagerechte (auf Unter- und Oberkante, Schritt 1) und eine senkrechte dazwischen (Schritt 2). Kein neues Werkzeug — nur das Hütchen aus Kapitel 7, dreimal angewandt. Deshalb der Name bilinear: bi für „zweimal”, linear für „geradlinig”.
Diese drei Zeilen Handrechnung gießen wir in Python. Der Code sagt Wort für Wort, was oben stand — erst die beiden Kanten, dann dazwischen:
Code
def bilineare_interpolation(eckwerte, anteil_x, anteil_y):"""Wert an einer Stelle im Rechteck -- bilinear, also zweimal linear. eckwerte: [unten_links, unten_rechts, oben_rechts, oben_links]. anteil_x: 0 = linke Kante, 1 = rechte Kante. anteil_y: 0 = untere Kante, 1 = obere Kante. """ unten_links, unten_rechts, oben_rechts, oben_links = eckwerte# Schritt 1: Unter- und Oberkante in x-Richtung. wert_unterkante = unten_links + anteil_x * (unten_rechts - unten_links) wert_oberkante = oben_links + anteil_x * (oben_rechts - oben_links)# Schritt 2: zwischen beiden in y-Richtung.return wert_unterkante + anteil_y * (wert_oberkante - wert_unterkante)ECKWERTE = [20.0, 300.0, 100.0, 40.0] # unten links / rechts, oben rechts / linksprint("Mitte (x=0,50, y=0,50):", bilineare_interpolation(ECKWERTE, 0.5, 0.5), "°C")print("Viertel(x=0,25, y=0,50):", bilineare_interpolation(ECKWERTE, 0.25, 0.5), "°C")print("Mittelwert der vier Ecken:", sum(ECKWERTE) /4.0, "°C")
Mitte (x=0,50, y=0,50): 115.0 °C
Viertel(x=0,25, y=0,50): 72.5 °C
Mittelwert der vier Ecken: 115.0 °C
Interpretation der Ausgabe: In der Mitte kommen die 115 °C der Handrechnung heraus — und, ein hübscher Zufall, das ist genau der Mittelwert der vier Ecken ($ (20+300+100+40)/4 = 115$). Das gilt aber nur im Zentrum; schon beim Viertelpunkt (72,5 °C) stimmt es nicht mehr mit dem Eckmittel überein. Die „Mitte = Mittel der Ecken”-Regel merken wir uns trotzdem — beim Sattel gleich wird sie zum Kronzeugen.
11.2 Die vier Ansatzfunktionen: zwei Hütchen im Produkt
In Kapitel 7 war die Ansatzfunktion eines 1D-Knotens ein Hütchen: 1 am eigenen Knoten, geradlinig auf 0 zu den Nachbarn. In Kapitel 10 wurde daraus das Zelt über Dreiecken. Beim Rechteck ist die Bauidee noch direkter: Multipliziere ein Hütchen in \(x\) mit einem Hütchen in \(y\).
Ein Rechteck hat vier Ecken, also vier Ansatzfunktionen. Nimm die Ecke unten links. Ihr \(x\)-Hütchen ist 1 an der linken Kante und fällt nach rechts auf 0; ihr \(y\)-Hütchen ist 1 an der unteren Kante und fällt nach oben auf 0. Das Produkt der beiden ist 1 genau in der Ecke unten links und 0 an den drei anderen Ecken — die Ansatzfunktion dieser Ecke. Ebenso für die drei übrigen.
Code
import numpy as npimport matplotlib.pyplot as pltgitter = np.linspace(0, 1, 26)sx, sy = np.meshgrid(gitter, gitter)ecken = [(0, 0), (1, 0), (1, 1), (0, 1)]namen = ["unten links", "unten rechts", "oben rechts", "oben links"]fig = plt.figure(figsize=(11.5, 3.2))for k, (ex, ey) inenumerate(ecken): hut_x = sx if ex ==1else (1- sx) hut_y = sy if ey ==1else (1- sy) N = hut_x * hut_y ax = fig.add_subplot(1, 4, k +1, projection="3d") ax.plot_surface(sx, sy, N, cmap="viridis", edgecolor="0.4", linewidth=0.2) ax.plot([ex], [ey], [1], "o", color="red", ms=6) ax.set_title("N: "+ namen[k], fontsize=9) ax.set_zlim(0, 1) ax.set_xticks([0, 1]); ax.set_yticks([0, 1]); ax.set_zticks([0, 1]) ax.tick_params(labelsize=7)plt.tight_layout()plt.show()
Abbildung 11.3: Die vier Ansatzfunktionen des Rechtecks, jede über dem Einheitsquadrat. Jede steht auf Höhe 1 über ihrer eigenen Ecke (rot) und fällt zu den anderen drei Ecken auf 0. Entlang jeder Kante läuft sie geradlinig (eine Gerade), im Inneren aber ist sie leicht gewölbt — eine Sattelfläche, weil sie das Produkt zweier Hütchen ist. Genau diese Wölbung fehlt dem ebenen Dreiecks-Zelt aus Kapitel 10.
Was man hier sieht: vier Dächer, jedes über einer anderen Ecke auf Höhe 1, zu den drei anderen Ecken auf 0. Anders als das Dreiecks-Zelt (eine ebene Fläche) ist jedes dieser Dächer im Inneren leicht gewölbt — an den Rändern straff, in der Mitte durchgesackt. Diese Wölbung stammt vom Produkt: Eine Größe mal einer anderen, beide veränderlich, ergibt eben keine Ebene mehr.
Prüfen wir die Ansatzfunktionen mit derselben Checkliste wie in Kapitel 10:
Ecke exklusiv. Jede Funktion ist 1 an ihrer eigenen Ecke, 0 an den drei anderen (rote Punkte). Beim Interpolieren gibt jede Ecke also genau ihren eigenen Wert zurück — wie es sein muss.
Summe 1. An jeder Stelle addieren sich die vier Funktionen zu 1 (\((1-s)(1-t) + s(1-t) + st + (1-s)t = 1\), einfach ausmultipliziert). Deshalb bleibt der interpolierte Wert immer zwischen dem kleinsten und größten Eckwert.
Kante linear. Auf jeder Kante ist entweder \(x\) oder \(y\) konstant. Dann wird aus dem Produkt „Hütchen mal Hütchen” ein einzelnes Hütchen mal einer Zahl — eine schlichte Gerade. Und diese Gerade hängt nur von den beiden Knoten dieser Kante ab, nicht von den anderen zwei.
Der letzte Punkt ist der wichtigste, denn er ist genau die Eigenschaft, die in Kapitel 10 die Dreiecke nahtlos zusammengehalten hat:
TippKantenkompatibel — sogar mit Dreiecken
Auf jeder Rechteckkante ist der Verlauf linear und hängt nur von den zwei Knoten dieser Kante ab. Das ist wortgleich die Kantenkompatibilität der Dreiecke aus Kapitel 10: Zwei Nachbarelemente, die sich eine Kante teilen, interpolieren dort dieselben zwei Knotenwerte — kein Sprung, keine Überlappung.
Die Folge ist bemerkenswert: Weil beide Familien auf ihren Kanten linear sind, darf man Rechtecke und Dreiecke sogar im selben Netz mischen — Rechtecke im regelmäßigen Inneren, Dreiecke am schrägen Rand. An der gemeinsamen Kante passen sie exakt zusammen (Übung 11.3 rechnet das nach).
11.3 Der Sattel: warum das Innere sich krümmt
Jetzt zur Pointe des Kapitels. Auf den Kanten ist die bilineare Fläche eine Gerade — das haben wir gerade gesehen. Aber im Inneren? Multipliziert man die vier Ansatzfunktionen aus, bleibt ein einziger Term übrig, den ein Dreieck nicht hat: ein Glied, in dem \(x\)und\(y\) zusammen vorkommen, das gemischte Glied\(x \cdot y\). Und dieses Glied krümmt die Fläche.
Anschaulich ist das die Form, die ein an vier verschieden hoch aufgehängtes Tuch annimmt: In der einen Diagonalrichtung hängt es durch, in der anderen wölbt es sich auf — ein Sattel (dieselbe Form wie ein Kartoffelchip oder ein Pass zwischen zwei Berggipfeln). Am deutlichsten wird der Sattel, wenn man die Eckwerte über Kreuz wählt: zwei gegenüberliegende Ecken kalt, die anderen beiden heiß.
Abbildung 11.4: Die Schlüsselgrafik. Über denselben vier Eckwerten 20/300/20/300 (über Kreuz) drei Flächen. Links das Rechteck: eine glatte, gekrümmte Sattelfläche, im Zentrum 160 °C. Mitte und rechts die zwei Dreiecksvarianten — je nachdem, welche Diagonale man schneidet, zwei ebene Platten mit Knick. Schneidet man entlang der beiden kalten Ecken (Mitte), ist das Zentrum 20 °C; entlang der beiden heißen (rechts) 300 °C. Ein und dieselben Ecken, drei völlig verschiedene Innenwerte.
Was man hier sieht: dreimal dieselben vier Ecken (20/300/20/300), drei grundverschiedene Flächen. Das Rechteck (links) spannt eine glatte, gekrümmte Sattelfläche; ihr Zentrum liegt bei 160 °C — dem Mittel der vier Ecken, wie wir es oben schon gelernt haben. Die beiden Dreiecksvarianten (Mitte, rechts) sind dagegen zwei ebene Platten mit einem scharfen Knick entlang der Diagonale, und ihr Zentrum hängt davon ab, welche Diagonale man geschnitten hat.
Rechnen wir die drei Zentrumswerte nach. Das Zentrum liegt genau auf beiden Diagonalen. Schneidet man entlang Diagonale A (sie verbindet die beiden kalten 20-°C-Ecken), so ist das Zentrum der Mittelpunkt dieser Diagonale, also \((20 + 20)/2 = 20\ °\mathrm{C}\). Schneidet man entlang Diagonale B (die beiden heißen 300-°C-Ecken), ist es \((300 + 300)/2 = 300\ °\mathrm{C}\). Das Rechteck macht keinen Schnitt und landet bei 160 °C — exakt zwischen beiden.
WarnungDie Diagonalen-Willkür
Die Vermutung war: „Rechteck = zwei Dreiecke, dieselbe Interpolation.” Und heraus kommt: ein Unterschied von bis zu 280 Grad im selben Punkt.
Bei den Eckwerten 20/300/20/300 zeigt das Zentrum \[
20\ °\mathrm{C} \;\text{(Diagonale A)}, \qquad
300\ °\mathrm{C} \;\text{(Diagonale B)}, \qquad
160\ °\mathrm{C} \;\text{(Rechteck)}.
\] Die zwei Dreiecksvarianten liegen 280 Grad auseinander — allein durch die Wahl der Schnittdiagonale, einer reinen Netz-Entscheidung ohne physikalischen Grund. Das ist die Diagonalen-Willkür: Das Dreiecksnetz muss sich für eine Diagonale entscheiden und schleppt diese Willkür in die Lösung. Das Rechteck hat keine Diagonale und keine Willkür — sein bilinearer Wert liegt neutral in der Mitte. (Bei sehr feinen Netzen schrumpft der Unterschied, weil die Zellen klein werden und die Eckwerte kaum noch über Kreuz stehen; Kapitel 12 misst das.)
11.3.1 Krümmung aus lauter Geraden
Wie kann eine Fläche gekrümmt sein, wenn sie auf jeder Kante — und sogar auf jeder waagerechten und senkrechten Linie im Inneren — eine Gerade ist? Die folgende Animation zeigt es: Eine waagerechte Scanlinie wandert von unten nach oben über das Rechteck. Auf jeder Höhe ist das Temperaturprofil in \(x\) eine Gerade — aber ihre beiden Endpunkte (die Werte an linker und rechter Kante) wandern mit der Höhe, und deshalb kippt und verschiebt sich diese Gerade laufend. Stapelt man alle diese Geraden übereinander, entsteht die gekrümmte Sattelfläche: Krümmung aus lauter Geraden.
Code
import numpy as npimport matplotlib.pyplot as pltfrom matplotlib.animation import FuncAnimationfrom IPython.display import HTMLul, ur, orr, ol =20.0, 300.0, 20.0, 300.0def profil(t): links = ul + t * (ol - ul) # linke Kante von unten (20) nach oben (300) rechts = ur + t * (orr - ur) # rechte Kante von unten (300) nach oben (20)return links, rechtsfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10.5, 4.0))gitter = np.linspace(0, 1, 21)def zeichne(frame): ax1.clear(); ax2.clear() t = frame /20.0# linkes Feld: Rechteck mit Farbverlauf und Scanlinie sx, sy = np.meshgrid(gitter, gitter) unten = ul + sx * (ur - ul); oben = ol + sx * (orr - ol) feld = unten + sy * (oben - unten) ax1.contourf(sx, sy, feld, levels=20, cmap="coolwarm", vmin=20, vmax=300) ax1.axhline(t, color="black", lw=2.5) ax1.set_title("Scanlinie bei y-Anteil %.2f"% t, fontsize=10) ax1.set_xlabel("x-Anteil"); ax1.set_ylabel("y-Anteil") ax1.set_aspect("equal")# rechtes Feld: alle bisherigen Profile blass, aktuelles kräftigfor vor inrange(frame +1): tv = vor /20.0 lv, rv = profil(tv) farbe ="tab:red"if vor == frame else"0.8" breite =2.5if vor == frame else0.7 ax2.plot([0, 1], [lv, rv], color=farbe, lw=breite) ax2.set_ylim(0, 320); ax2.set_xlim(0, 1) ax2.set_xlabel("x-Anteil"); ax2.set_ylabel("Temperatur (°C)") ax2.set_title("Profil auf der Linie: immer eine Gerade", fontsize=10)return []ani = FuncAnimation(fig, zeichne, frames=21, interval=200, blit=False)plt.close(fig)HTML(ani.to_jshtml())
Abbildung 11.5: Der Interpolations-Scanner. Links wandert eine waagerechte Linie durch das Rechteck (Eckwerte 20/300/20/300); rechts das Temperaturprofil entlang dieser Linie — stets eine Gerade. Ihre Endpunkte laufen an den senkrechten Kanten hoch bzw. runter, darum kippt die Gerade. Die blassen Linien sind die schon gescannten Profile; zusammen füllen sie die gekrümmte Sattelfläche.
Was man sieht: Jedes einzelne Profil ist kerzengerade — und trotzdem ist die Fläche, die alle Profile zusammen aufspannen, gekrümmt. Der Grund ist der gemischte \(x\,y\)-Term: Weil die Endpunkte der Geraden mit der Höhe wandern, dreht sich die Gerade, und eine sich drehende Gerade überstreicht eine gewölbte Fläche. Das Dreieck kann das nicht — seine Ansatzfläche ist eine starre Ebene ohne diesen Term.
11.4 Die Elementmatrix: vier mal vier, aus 1D-Bausteinen
Jetzt der Schritt, der bei der Feder die 2×2-Matrix und beim Dreieck die 3×3-Matrix lieferte: Ein Rechteck hat vier Knoten, also wird sein Steckbrief eine 4×4-Matrix. Und weil wir uns strikt auf achsparallele Rechtecke beschränken (das ist die bewusste Vereinfachung dieses Buches, Strategie §7), bleibt das Ausrechnen erstaunlich einfach: Jede Ansatzfunktion ist ein Produkt „Hütchen in \(x\) mal Hütchen in \(y\)“, und deshalb zerfällt jedes Elementintegral in ein Produkt zweier 1D-Integrale — beide kennen wir schon.
Wir brauchen genau zwei 1D-Bausteine, beide aus früheren Kapiteln:
Steigung mal Steigung auf einer Strecke der Länge \(L\) — die 1D-Matrix aus Kapitel 7: auf der Diagonale \(+1/L\), daneben \(-1/L\).
Hütchen-Überlapp auf einer Strecke der Länge \(L\) — die Massenmatrix aus Kapitel 9: \(\frac{L}{6}\begin{pmatrix}2&1\\1&2\end{pmatrix}\).
Jeder Eintrag der 4×4-Matrix ist die Summe von zwei Produkten dieser Bausteine:
\[
K_{ij} = \lambda\,d\,\Bigl(
\underbrace{[\text{Steigung}\times\text{Steigung in }x]\cdot[\text{Hütchen-Überlapp in }y]}_{\text{der }x\text{-Beitrag}}
\;+\;
\underbrace{[\text{Hütchen-Überlapp in }x]\cdot[\text{Steigung}\times\text{Steigung in }y]}_{\text{der }y\text{-Beitrag}}
\Bigr).
\]
In Worten: In der einen Richtung liefern die Steigungen den Beitrag (dort zählt, wie steil die Ansatzfunktion abfällt), in der anderen der Überlapp der Hütchen (dort zählt, wie sehr sich die Funktionen überdecken) — und das für \(x\) und \(y\) addiert. Das ist die ganze Rechnung. Machen wir eine Zeile von Hand.
11.4.1 Eine Zeile von Hand
Wir nehmen ein Träger-Rechteck: Breite \(a = 0{,}5\ \mathrm{m}\) (Länge einer Zelle), Höhe \(b = 0{,}05\ \mathrm{m}\). Die Knoten gegen den Uhrzeigersinn: 1 = unten links, 2 = unten rechts, 3 = oben rechts, 4 = oben links. Wir rechnen die erste Zeile aus — die Kopplungen von Knoten 1 zu allen vieren. Der Vorfaktor ist \(\lambda\,d = 50 \cdot 0{,}1 = 5\ \tfrac{\mathrm{W}}{\mathrm{m\,K}}\cdot\mathrm{m}\).
Die 1D-Bausteine für \(a = 0{,}5\) und \(b = 0{,}05\): Steigung mal Steigung ist \(\pm 1/a = \pm 2\) bzw. \(\pm 1/b = \pm 20\); der Hütchen-Überlapp ist auf der Diagonale \(2a/6 = a/3\) bzw. \(b/3\) und daneben \(a/6\) bzw. \(b/6\). Damit die vier Einträge der ersten Zeile (Knoten 1 ist in \(x\) das linke, in \(y\) das untere Hütchen):
Die Probe ist dieselbe wie immer: \(16{,}83 + 8{,}17 - 8{,}42 - 16{,}58 = 0\) — die Zeile summiert sich zu null, weil ein gleichmäßiges Aufheizen aller vier Knoten keinen Wärmestrom erzeugen darf (wie bei Feder und Dreieck). Alle sechzehn Einträge zusammen ergeben den Steckbrief. Lassen wir das Programm ihn ausrechnen und die Probe machen:
Code
import osimport syssys.path.insert(0, os.path.join("..", "programme", "gemeinsam"))from rechtecke import baue_rechteck_matrix# Träger-Rechteck 0,5 m x 0,05 m, Knoten 1-2-3-4 gegen den Uhrzeigersinn.ecken = [(0.0, 0.0), (0.5, 0.0), (0.5, 0.05), (0.0, 0.05)]steckbrief = baue_rechteck_matrix(ecken, 50.0, 0.1)print("4x4-Steckbrief des Träger-Rechtecks (W/K):")for zeile in steckbrief: summe = zeile[0] + zeile[1] + zeile[2] + zeile[3]print(" [ %7.2f%7.2f%7.2f%7.2f ] Zeilensumme = %.2f"% (zeile[0], zeile[1], zeile[2], zeile[3], summe))
Interpretation der Ausgabe: Zahl für Zahl die Handrechnung, und jede Zeilensumme null. Zwei Dinge fallen auf, und beide kommen vom Nadel-Zuschnitt des Rechtecks (10-mal so lang wie hoch):
Die Kopplung quer über die kurze Höhe (\(K_{14} = -16{,}58\), zu Knoten 4 direkt darüber) ist mit Abstand die stärkste — genau wie bei den Dreiecken in Kapitel 10 die \(-25\) die kurze Höhe überbrückte. Kurze Strecke, steile Ansatzfunktion, große Zahl.
Die Kopplung längs der Länge (\(K_{12} = +8{,}17\), zu Knoten 2 daneben) ist sogar positiv. Das ist ungewöhnlich — normalerweise sind Nachbarkopplungen negativ. Es ist ein Warnzeichen des extremen Seitenverhältnisses: Bei so einer Nadel überwiegt der \(y\)-Beitrag den \(x\)-Beitrag so stark, dass das Vorzeichen kippt. Für unser gutmütiges Problem schadet das nicht (die Lösung stimmt), aber es ist ein erster Hinweis, dass entartete Elemente ihre Tücken haben — mehr dazu im Kleingedruckten.
HinweisDer Rechteck-Steckbrief für beliebiges Seitenverhältnis
Für ein Rechteck mit Breite \(a\) und Höhe \(b\) hat der Q1-Steckbrief eine feste Gestalt, in der nur die beiden Seitenverhältnisse \(\tfrac{b}{a}\) (Längs-Anteil) und \(\tfrac{a}{b}\) (Quer-Anteil) auftauchen. Für ein Quadrat (\(a = b\)) wird er besonders schön: \[
\mathbf{K}_\text{Quadrat} = \frac{\lambda\,d}{6}
\begin{pmatrix}
4 & -1 & -2 & -1\\
-1 & 4 & -1 & -2\\
-2 & -1 & 4 & -1\\
-1 & -2 & -1 & 4
\end{pmatrix}.
\] Auf der Diagonale die 4, zu den beiden Kantennachbarn \(-1\), und zur diagonal gegenüberliegenden Ecke \(-2\). Diese \(-2\) ist der entscheidende Unterschied zum Dreieck: Das Rechteck koppelt jeden Knoten auch mit der Eck-Diagonale. Genau daher kommt der Sattel — und gleich der 9-Punkt-Stern.
11.5 Der Rechteck-Träger: gleiche Lösung, anderes System
Jetzt vernetzen wir den ganzen Träger mit Rechtecken und vergleichen ihn mit dem Dreiecksnetz aus Kapitel 10 — auf demselben 3×3-Knotengitter. Der Bauplan ist dieselbe Knotenliste wie in Kapitel 10, nur bleibt jede der vier Gitterzellen jetzt ein Rechteck, statt in zwei Dreiecke geteilt zu werden.
Interpretation der Ausgabe: ein deutlich volleres Band als beim Dreiecksnetz. Vergleiche die mittlere Zeile (Knoten 5, die Trägermitte): Beim Dreiecksnetz aus Kapitel 10 hatte sie nur fünf Einträge (Knoten 5 und seine vier direkten Kantennachbarn), alle Diagonalfelder waren leer. Hier ist die Zeile von Knoten 5 komplett voll — Knoten 5 koppelt mit allen acht Nachbarn, auch den vier Eck-Diagonalen. Abbildung 11.6 stellt beide Kopplungsmuster nebeneinander.
Code
import matplotlib.pyplot as plt# 3x3-Gitter der Knotenpositionen (schematisch, gleichmaessig)pos = {}nr =0for gy inrange(3):for gx inrange(3): pos[nr] = (gx, gy) nr +=1mitte =4fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10.5, 4.2))# Links: Dreieck, 5-Punkt-Stern (nur Kantennachbarn 1,3,5,7)kanten_nachbarn = [1, 3, 5, 7]diagonalen = [0, 2, 6, 8]for n in kanten_nachbarn: ax1.plot([pos[mitte][0], pos[n][0]], [pos[mitte][1], pos[n][1]], color="tab:blue", lw=2.5, zorder=2)for n in diagonalen: ax1.plot([pos[mitte][0], pos[n][0]], [pos[mitte][1], pos[n][1]], color="0.7", lw=1.0, ls="--", zorder=1)for n, (x, y) in pos.items(): farbe ="tab:orange"if n == mitte else"white" ax1.plot(x, y, "o", color=farbe, ms=20, markeredgecolor="black", zorder=3) ax1.text(x, y, str(n +1), ha="center", va="center", fontsize=9, zorder=4)ax1.set_title("Dreiecksnetz: 5-Punkt-Stern\n(4 Kantennachbarn, Diagonalen heben sich weg)", fontsize=9)# Rechts: Rechteck, 9-Punkt-Stern (alle acht)for n in kanten_nachbarn: ax2.plot([pos[mitte][0], pos[n][0]], [pos[mitte][1], pos[n][1]], color="tab:blue", lw=2.5, zorder=2)for n in diagonalen: ax2.plot([pos[mitte][0], pos[n][0]], [pos[mitte][1], pos[n][1]], color="tab:red", lw=2.5, zorder=2)for n, (x, y) in pos.items(): farbe ="tab:orange"if n == mitte else"white" ax2.plot(x, y, "o", color=farbe, ms=20, markeredgecolor="black", zorder=3) ax2.text(x, y, str(n +1), ha="center", va="center", fontsize=9, zorder=4)ax2.set_title("Rechtecknetz: 9-Punkt-Stern\n(alle acht Nachbarn, Ecken rot)", fontsize=9)for ax in (ax1, ax2): ax.set_xlim(-0.5, 2.5); ax.set_ylim(-0.5, 2.5) ax.set_aspect("equal"); ax.axis("off")plt.tight_layout()plt.show()
Abbildung 11.6: Zwei Kopplungsmuster für denselben Mittelknoten. Links das Dreiecksnetz (Kapitel 10): der innere Knoten 5 koppelt nur mit seinen vier direkten Kantennachbarn — ein 5-Punkt-Stern. Die Kopplungen zu den vier Eck-Diagonalen heben sich exakt weg (Diagonalen als graue gestrichelte Linien, aber keine Verbindung). Rechts das Rechtecknetz: derselbe Knoten koppelt mit allen acht Nachbarn, Ecken eingeschlossen — ein 9-Punkt-Stern. Die vier Eck-Kopplungen (rot) sind der Unterschied.
Was man hier sieht: links koppelt der Mittelknoten mit vier Nachbarn, rechts mit acht. Der Unterschied sind die vier Eck-Kopplungen (rot) — genau die Diagonalnachbarn, die der \(x\,y\)-Term des Rechtecks ins Spiel bringt und die dem ebenen Dreieck fehlen. Beim Dreiecksnetz auf diesem regelmäßigen Gitter heben sich die Diagonalbeiträge sogar exakt weg (deshalb der schlanke 5-Punkt-Stern); beim Rechteck bleiben sie stehen. Mehr Kopplungen heißt: ein etwas volleres Gleichungssystem, das aber derselbe Löser aus Kapitel 4 knackt.
WichtigVorhersage-Punkt
Bevor wir lösen: Wir halten wie in Kapitel 10 die linke Kante auf 20 °C und die rechte auf 300 °C. Das Dreiecksnetz lieferte damals die Mittelspalte auf exakt 160 °C. Jetzt rechnet das Rechtecknetz dasselbe Problem. Erwartest du wieder 160 °C — oder muss durch die andere Interpolation und die neun Kopplungen etwas anderes herauskommen? Leg dich fest.
Knoten | Ort (x, y) | Temperatur
-------+-----------------+-----------
1 | (0.00, 0.000) m | 20.0 °C
2 | (0.50, 0.000) m | 160.0 °C
3 | (1.00, 0.000) m | 300.0 °C
4 | (0.00, 0.050) m | 20.0 °C
5 | (0.50, 0.050) m | 160.0 °C
6 | (1.00, 0.050) m | 300.0 °C
7 | (0.00, 0.100) m | 20.0 °C
8 | (0.50, 0.100) m | 160.0 °C
9 | (1.00, 0.100) m | 300.0 °C
Interpretation der Ausgabe: wieder 160 °C in der ganzen Mittelspalte — Zahl für Zahl dasselbe Ergebnis wie beim Dreiecksnetz. Das ist die Auflösung:
WarnungVermutung aufgelöst
Gleiche Lösung, verschiedenes System. Bei diesem symmetrischen Rand (links überall kalt, rechts überall heiß) ist die wahre Temperatur eine Gerade in \(x\), unabhängig von der Höhe. Und eine Gerade in \(x\) stellen Dreiecke und Rechtecke exakt dar — beim Rechteck ist auf jeder waagerechten Linie das Profil ja gerade, und der krümmende \(x\,y\)-Term wird nur gebraucht, wenn die Ecken über Kreuz stehen. Deshalb dieselben 160 °C.
Verschieden ist nur der Weg dorthin: neun Kopplungen statt fünf, ein volleres Band, ein anderer Steckbrief. Bei der geraden Lösung sieht man den Unterschied im Ergebnis nicht — aber sobald die Wahrheit krumm wird (eine beflammte Ecke, ein Loch, ein runder Rand), interpolieren Rechteck und Dreieck verschieden, und dann zählt, welche Familie die Wirklichkeit besser trifft. Das ist die Frage von Kapitel 12.
Das Temperatur-Farbbild bestätigt die Streifen — wie bei den Dreiecken hängt die Temperatur nur von der Länge ab, nicht von der Höhe.
Code
import matplotlib.pyplot as pltknoten = [(0.0, 0.0), (0.5, 0.0), (1.0, 0.0), (0.0, 0.05), (0.5, 0.05), (1.0, 0.05), (0.0, 0.10), (0.5, 0.10), (1.0, 0.10)]rechtecke = [(0, 1, 4, 3), (1, 2, 5, 4), (3, 4, 7, 6), (4, 5, 8, 7)]temperaturen = [20.0, 160.0, 300.0, 20.0, 160.0, 300.0, 20.0, 160.0, 300.0]stufen =16kleinste, groesste =20.0, 300.0fig, ax = plt.subplots(figsize=(9.0, 3.0))for r in rechtecke: eckwerte = [temperaturen[r[k]] for k inrange(4)] x0, y0 = knoten[r[0]] breite = knoten[r[1]][0] - x0 hoehe = knoten[r[3]][1] - y0for ix inrange(stufen):for iy inrange(stufen): s = (ix +0.5) / stufen t = (iy +0.5) / stufen unten = eckwerte[0] + s * (eckwerte[1] - eckwerte[0]) oben = eckwerte[3] + s * (eckwerte[2] - eckwerte[3]) wert = unten + t * (oben - unten) farbe = plt.cm.inferno((wert - kleinste) / (groesste - kleinste)) ax.add_patch(plt.Rectangle( (x0 + ix * breite / stufen, y0 + iy * hoehe / stufen), breite / stufen, hoehe / stufen, color=farbe))xs = [p[0] for p in knoten]; ys = [p[1] for p in knoten]ax.plot(xs, ys, "o", color="white", ms=6, markeredgecolor="black")for i inrange(9): ax.annotate("%.0f"% temperaturen[i], xy=(knoten[i][0], knoten[i][1]), xytext=(0, 7), textcoords="offset points", ha="center", fontsize=8, color="white")ax.set_xlim(-0.02, 1.02); ax.set_ylim(-0.01, 0.13)ax.set_xlabel("Länge x (m)"); ax.set_ylabel("Höhe y (m)")ax.set_title("Temperaturfeld: waagerechte Streifen (Rechtecke)")ax.set_aspect("equal")plt.tight_layout()plt.show()
Abbildung 11.7: Das Temperaturfeld des Rechteck-Trägers. Die Farbe wächst gleichmäßig von 20 °C links auf 300 °C rechts, die Höhenlinien stehen senkrecht — waagerechte Streifen, Mittelspalte 160 °C. Ununterscheidbar vom Dreiecks-Farbbild in Kapitel 10, obwohl das System darunter ein anderes ist.
Was man hier sieht: senkrechte Farbübergänge, waagerechte Streifen — dasselbe Bild wie in Kapitel 10. Die Rechteck-Zellen sind bilinear gefärbt, aber bei diesem geraden Feld sieht man die Krümmung nirgends, weil es keine gibt. Erst ein unsymmetrischer Rand (eine beflammte Ecke) würde Rechteck und Dreieck sichtbar auseinandertreiben.
11.6 Die interaktive Einheit: das Rechteck-Labor
Jetzt bist du dran. Das Rechteck-Labor hat zwei Teile. Teil 1 lässt dich vier Eckwerte und einen Punkt setzen und vergleicht den bilinearen Wert direkt mit beiden Dreiecks-Antworten (je eine pro Diagonale). Teil 2 ist der ganze Träger mit einem Umschalter zwischen Dreiecken und Rechtecken auf demselben Randwertproblem.
11.6.1 Teil 1 — bilinear gegen beide Dreiecke
WichtigVorhersage-Punkt
Bevor du es laufen lässt: Setze die Eckwerte über Kreuz (20/300/20/300) und den Punkt ins Zentrum. Der bilineare Wert wird 160 °C sein. Und die beiden Dreiecks-Antworten? Liegt der bilineare Wert über beiden, unter beiden oder zwischen ihnen? Leg dich fest, bevor du die Zahlen siehst.
Setze ECKWERTE (gegen den Uhrzeigersinn ab links unten) und den PUNKT (Anteile in \(x\) und \(y\), je 0 bis 1). Probiere die Kreuz-Belegung, dann eine gleichmäßig steigende — wann sind sich alle drei Antworten einig?
Abbildung 11.8: Vorgerenderte Fassung von Teil 1: über Kreuz (20/300/20/300) im Zentrum liefert das Rechteck 160 °C, Dreieck A 20 °C, Dreieck B 300 °C. Der bilineare Wert liegt exakt ZWISCHEN den beiden Dreiecks-Antworten. Im Browser ersetzt dein eigenes Ergebnis dieses Bild.
Die Antwort auf die Vorhersage: Der bilineare Wert liegt zwischen den beiden Dreiecks-Antworten — im Kreuz-Fall genau in der Mitte (160 zwischen 20 und 300). Das Rechteck mittelt gerade das aus, worüber die zwei Dreiecke sich streiten.
11.6.2 Teil 2 — der Träger mit Elementtyp-Umschalter
Jetzt der ganze Träger. Setze ELEMENTTYP auf "dreiecke" oder "rechtecke" und die Randtemperaturen — das Labor baut das passende System, löst es und zählt die Kopplungen des Mittelknotens. Achte darauf: Die Lösung ändert sich beim Umschalten kaum, die Kopplungszahl springt von 5 auf 9.
Abbildung 11.9: Vorgerenderte Fassung von Teil 2: der Träger mit Rechtecken, Rand 20/300, Mittelspalte 160 °C, Mittelknoten mit 9 Kopplungen. Schaltet man im Browser auf „dreiecke”, bleibt die Lösung 160 °C, aber die Kopplungszahl fällt auf 5.
Was man sieht: Schalte zwischen "dreiecke" und "rechtecke" hin und her — die Mittelspalte bleibt auf 160 °C, aber die Kopplungszahl springt zwischen 5 und 9. Genau das ist die Botschaft: gleiche Lösung, verschiedenes System. Im Finale (Kapitel 15) sitzt derselbe Umschalter, dann darfst du für ein echtes Problem entscheiden, welche Familie du nimmst.
11.7 Das Kapitel-Programm
Das vollständige, eigenständig lauffähige Skript liegt in programme/kap11/kap11_rechtecke_fem.py. Es baut das 4-Rechtecke-Netz, rechnet den Steckbrief eines Träger-Rechtecks vor, druckt die assemblierte 9×9-Matrix, zählt die Kopplungen im Vergleich zum Dreiecksnetz und löst das Randwertproblem — dieselben Schritte wie im Kapitel, an einem Stück. Die Rechteck-Bausteine (bilineare_interpolation, baue_rechteck_matrix, assembliere_rechtecke) liegen im gemeinsamen Modul programme/gemeinsam/rechtecke.py, das Kapitel 12 und das Finale Kapitel 15 über den Elementtyp-Umschalter mitbenutzen. Das Streich-Rezept für Randwerte teilt es sich mit dem Dreiecks-Modul — es ist ja elementtyp-unabhängig.
11.8 Ausblick und Kleingedrucktes
11.8.1 Was Profi-Programme mit schiefen Vierecken tun
Wir haben uns strikt auf achsparallele Rechtecke beschränkt. Das war kein Zufall, sondern die tragende Vereinfachung dieses Kapitels — und sie hat einen Preis, den wir ehrlich benennen.
HinweisPanorama: isoparametrische Elemente
Ein echtes Bauteil hat krumme Ränder und schiefe Ecken; da passt kein achsparalleles Rechteck mehr. Profi-Programme (OGS, Abaqus, ANSYS & Co.) benutzen deshalb schiefe Vierecke — und einen eleganten Trick, um sie trotzdem zu berechnen:
Man rechnet nie auf dem schiefen Viereck selbst, sondern auf einem Referenzquadrat mit den bequemen Koordinaten von \(-1\) bis \(+1\). Dort sehen die vier Ansatzfunktionen genauso aus wie bei uns.
Dieselben vier bilinearen Funktionen bilden das Referenzquadrat auf das schiefe Viereck ab — die Geometrie wird mit demselben Ansatz beschrieben wie die Lösung. Daher der Name isoparametrisch (griechisch isos = gleich): gleiche Parameter für Form und Feld.
Beim Umrechnen der Integrale vom Quadrat aufs Viereck taucht ein Dehnungsfaktor auf, die Jacobi-Determinante, und die Integrale löst man nicht mehr von Hand, sondern mit Gauß-Quadratur (ein paar geschickt gewählte Stützstellen, wie die Streifen aus Kapitel 5, nur cleverer).
Für unseren rechteckigen Träger ist all das unnötig — die Jacobi-Determinante wäre eine Konstante, die Gauß-Quadratur exakt, und wir bekämen genau die Matrix, die wir oben von Hand gerechnet haben. Für krumme Ränder aber ist es unverzichtbar. Es ist der Standardweg jedes ernsthaften FEM-Codes und ein schönes Thema für ein weiterführendes Buch. Merke nur: dieselben vier Hütchen-Produkte stecken auch dort drin — wir haben den Kern schon in der Hand.
11.8.2 Lumping: der Eimer, geviertelt
In Kapitel 9 haben wir die Massenmatrix (den Speicherterm der Zeit) durch Lumping auf die Diagonale geklumpt: Jeder Knoten bekam seinen eigenen „Eimer” Wärmekapazität. Beim 1D-Träger teilte sich jedes Element hälftig auf seine zwei Knoten auf. Beim Rechteck ist es genauso einfach, nur durch vier:
TippQ1-Lumping — jeder Ecke ein Viertel
Die verteilte Wärmekapazität eines Rechtecks wird beim Lumping zu gleichen Teilen auf seine vier Ecken geschoben — ein Viertel je Ecke. Für eine Trägerzelle (\(0{,}5\ \mathrm{m} \times 0{,}05\ \mathrm{m} \times 0{,}1\ \mathrm{m}\) Tiefe) ist die Zellkapazität \[
\rho\,c \cdot V = 7850 \cdot 460 \cdot (0{,}5 \cdot 0{,}05 \cdot 0{,}1)
= 9027{,}5\ \tfrac{\mathrm{J}}{\mathrm{K}},
\] also bekommt jede der vier Ecken \(9027{,}5/4 = 2256{,}875\ \tfrac{\mathrm{J}}{\mathrm{K}}\). Ein innerer Knoten, an dem vier Rechtecke zusammenstoßen, sammelt viermal ein Viertel — eine volle Zellkapazität. Das ist dasselbe Rezept wie in Kapitel 9 (Gesamtmasse bleibt erhalten, nur die Verteilung wird diagonal), nur eben durch vier statt durch zwei geteilt. Damit wird der explizite Zeitschritt auch beim Rechteck-Träger eine simple Division je Knoten.
11.8.3 Drei ehrliche Feinheiten
Erstens — die Nadel rächt sich langsam. Unsere Träger-Rechtecke sind mit 10 : 1 stark langgestreckt, und das trieb die Elementmatrix zu extremen Zahlen (bis zur positiven Nachbarkopplung \(K_{12} = +8{,}17\)). Für unser gerades, gutmütiges Feld schadet das nichts. Aber wie bei den „Nadel”-Dreiecken in Kapitel 10 gilt: Sehr langgestreckte Elemente verschlechtern bei krummen Lösungen die Genauigkeit. Faustregel wie dort — je gedrungener, desto besser; Kapitel 12 misst es.
Zweitens — nur bilineare Elemente. Wir benutzen ausschließlich das Q1-Rechteck mit vier Ecken und bilinearer Interpolation. Elemente höherer Ordnung (mit Zusatzknoten auf den Kanten, gekrümmte Ansätze) können mit weniger Elementen mehr, sind aber ein Thema für sich und kommen hier nur als Ausblick vor.
Drittens — die Exaktheit ist wieder geliehen. Dass die Mittelspalte exakt 160 °C traf, liegt wie in Kapitel 7 und Kapitel 10 daran, dass die wahre Lösung selbst eine Gerade in \(x\) ist — und die stellt das Q1-Rechteck exakt dar. Sobald die Wahrheit krumm ist (eine beflammte Ecke, ein runder Rand), trifft die FEM nur näherungsweise, und dann zeigt sich, ob Rechteck oder Dreieck näher an der Wirklichkeit liegt. Genau das ist die Frage von Kapitel 12.
11.9 Die Namensschilder
Wie in Kapitel 10 haben wir zuerst die Sache gebaut und die Fachwörter weggelassen. Jetzt die Schilder.
TippDie Fachwörter, jetzt nachgereicht
Bilineare Interpolation: das „zweimal linear” — erst in \(x\), dann in \(y\). Bi (lateinisch „zwei”) plus linear: in jeder der beiden Richtungen einzeln geradlinig, im Inneren durch das gemischte \(x\,y\)-Glied gekrümmt.
Q1-Rechteck (bilineares Viereckselement): das Rechteck mit einem Knoten je Ecke und bilinearer Interpolation. Das „Q” steht für quadrilateral (Viereck), die „1” für Grad 1 in jeder Richtung. Es ist das Gegenstück zum P1-Dreieck aus Kapitel 10.
Sattelfläche (hyperbolisches Paraboloid): die gekrümmte Form der bilinearen Ansatzfläche — in der einen Diagonale durchhängend, in der anderen aufgewölbt, wie ein Reitsattel oder Kartoffelchip. Sie entsteht allein aus dem \(x\,y\)-Glied.
Isoparametrisch: der Trick der Profi-Programme, schiefe Vierecke mit denselben Ansatzfunktionen zu berechnen, mit denen sie das Feld darstellen (nur als Ausblick — dieses Buch braucht ihn nicht).
Alle diese Wörter stehen im Glossar.
TippMerkkasten
Bilinear = zweimal linear: erst auf Unter- und Oberkante in \(x\) interpolieren, dann dazwischen in \(y\). Drei Strecken-Interpolationen, kein neues Werkzeug.
Die vier Ansatzfunktionen sind Produkte zweier Hütchen (eins in \(x\), eins in \(y\)). Auf jeder Kante linear (darum kantenkompatibel, sogar mit Dreiecken), im Inneren gekrümmt (der Sattel, vom \(x\,y\)-Glied).
Ein Dreieck-Paar hat eine Diagonalen-Willkür (bis 280 Grad Unterschied im Zentrum); das Rechteck kennt sie nicht.
Die Elementmatrix ist \(4\times 4\) und zerfällt in Produkte von 1D-Bausteinen: Steigung mal Steigung in der einen Richtung, Hütchen-Überlapp in der anderen. Zeilensummen null, wie immer.
Der Rechteck-Träger liefert dieselben 160 °C wie der Dreieck-Träger, aber mit 9 statt 5 Kopplungen pro innerem Knoten (der 9-Punkt-Stern, weil die Eck-Diagonalen mitkoppeln).
Roter Faden
Zurück: Die bilineare Interpolation ist dreimal das Hütchen aus Kapitel 7; die Elementmatrix baut auf den 1D-Bausteinen „Steigung mal Steigung” (Kapitel 7) und „Hütchen-Überlapp” (die Massenmatrix aus Kapitel 9) auf, beide im Produkt. Die Kantenkompatibilität ist wortgleich die aus Kapitel 10, und die 160 °C-Lösung ist dieselbe wie dort — nur das System darunter hat sich geändert. Assemblieren, Streich-Rezept (Kapitel 8) und Gauß-Seidel (Kapitel 4) liefen unverändert weiter.
Vor:Kapitel 12 fragt, welche Familie — Dreieck oder Rechteck — die Wirklichkeit genauer trifft, wenn die Lösung nicht mehr zufällig gerade ist (Netzkonvergenz), und wie man das ehrlich misst. Und im Finale Kapitel 15 sitzt der Elementtyp-Umschalter aus dem Rechteck-Labor: Dann entscheidest du für ein echtes Problem, ob du mit Dreiecken oder Rechtecken pflasterst.
Übungen
Ü 11.1 (Verstehen). Ein Rechteck hat die Eckwerte unten links 100 °C, unten rechts 200 °C, oben rechts 400 °C, oben links 300 °C. Berechne von Hand mit dem Zwei-Schritt-Rezept die Temperatur am Punkt bei \(x\)-Anteil \(\tfrac12\) und \(y\)-Anteil \(\tfrac14\). Kontrolliere im Rechteck-Labor (Teil 1).
HinweisMusterlösung zu Ü 11.1
Schritt 1, in \(x\) bei Anteil \(\tfrac12\): Unterkante \(100 + \tfrac12(200-100) =
150\ °\mathrm{C}\), Oberkante \(300 + \tfrac12(400-300) = 350\ °\mathrm{C}\). Schritt 2, in \(y\) bei Anteil \(\tfrac14\): \(150 + \tfrac14(350-150) = 150 + 50 =
200\ °\mathrm{C}\). Kontrolle im Labor mit ECKWERTE = [100, 200, 400, 300], PUNKT_X = 0.5, PUNKT_Y = 0.25 → 200 °C.
Ü 11.2 (Verändern). Suche die vier Eckwerte (nur Werte 20 °C oder 300 °C erlaubt), die den Unterschied zwischen Rechteck und Dreiecken im Zentrum maximal machen. Bei welcher Belegung ist er am größten, und wie groß wird er? Das Skript loesungen/kap11_ue2.py probiert es durch.
HinweisMusterlösung zu Ü 11.2
Der Sattel ist am stärksten, wenn diagonal gegenüberliegende Ecken gleich sind und die beiden Diagonalen so verschieden wie möglich — die Belegung über Kreuz: unten links 20, unten rechts 300, oben rechts 20, oben links 300 (oder umgekehrt). Dann liefert Diagonale A (die beiden 20-Ecken verbindend) im Zentrum 20 °C, Diagonale B 300 °C, das Rechteck 160 °C — eine Spanne von 280 Grad zwischen den Dreiecksvarianten. Der Grund: Die Spanne ist genau \(|e|/2\) mit dem Verwindungsterm \(e = \text{unten links} - \text{unten rechts} + \text{oben
rechts} - \text{oben links}\), und der wird über Kreuz betragsmäßig maximal (\(|{-560}|\)). Das Skript bestätigt die Tabelle.
Ü 11.3 (Übertragen). Skizziere von Hand ein gemischtes Netz für einen Träger mit schrägem rechten Ende: Rechtecke im regelmäßigen Inneren, Dreiecke am schrägen Rand. Begründe, warum an der Grenze zwischen einem Rechteck und einem angesetzten Dreieck kein Sprung entsteht. Das Skript loesungen/kap11_ue3.py prüft die Kantenkompatibilität numerisch nach.
HinweisMusterlösung zu Ü 11.3
Skizze: zwei bis drei achsparallele Rechtecke bilden den geraden Teil des Trägers; das schräge Ende wird mit Dreiecken aufgefüllt, deren Grundkante genau eine Rechteckkante ist und deren Spitzen zum schrägen Rand zeigen. Warum es passt: Auf der gemeinsamen Kante ist der Verlauf für beide Elementtypen linear und hängt nur von den zwei geteilten Knotenwerten ab — beim Rechteck, weil dort \(x\) (oder \(y\)) konstant ist und der \(x\,y\)-Term wegfällt; beim Dreieck, weil die dritte Ecke (die Spitze) auf der Kante den Anteil null hat. Beide interpolieren also dieselbe Gerade zwischen denselben zwei Werten — kein Sprung, keine Überlappung. Das Skript kap11_ue3.py legt ein Rechteck und ein Nachbardreieck an eine gemeinsame Kante und zeigt, dass die Kantenwerte auf jede Nachkommastelle übereinstimmen (größte Differenz: null).