13  Traue keinem bunten Bild

Am Ende von Kapitel 12 stand ein vollständiges Modell: ein Netz über die Ferse (Kapitel 10), festgehalten am Talus, belastet von Boden, Achillessehne und Faszie. Drückt man auf „Rechnen”, kommt ein buntes Spannungsbild heraus. Das Problem: Auch ein falsches Modell liefert ein buntes Bild. Ein vergessener Rand, ein Einheitenfehler, ein zu grobes Netz — nichts davon macht das Bild grau. Dieses Kapitel gibt die drei Fragen, mit denen man jeder Simulation auf den Zahn fühlt (Löse ich die Gleichungen richtig? Ist das Netz fein genug? Passen die Randbedingungen zur Wirklichkeit?), und die Werkzeuge dazu: Prüffälle, Netzkonvergenz, Bilanzkontrolle. Es schließt Teil IV ab. Der Aufhänger ist ein Widerspruch, den dieses Buch selbst erzeugt: dasselbe Modell, dieselbe Last, derselbe Löser — und zwei Netze, die für dieselbe Größe zwei Zahlen melden, die um mehr als das Dreifache auseinanderliegen.

Lernziele

Nach diesem Kapitel kannst du

  1. Verifikation („löse ich die Gleichungen richtig?“) von Validierung („löse ich die richtigen Gleichungen?“) unterscheiden,
  2. eine Netzkonvergenzstudie lesen — eine Kennzahl über mehrere Netzstufen verfolgen und erkennen, wann sie sich einem festen Wert nähert (die Buchschranke: Änderung unter 0,5 % zwischen den zwei feinsten Netzen) und wann sie weiterkriecht; dazu eine Richardson-Extrapolation lesen, die aus drei Netzstufen schätzt, wohin die Folge läuft,
  3. das Druck-Paradoxon auflösen — warum ein gemessener Fersen-Spitzendruck (188 kPa, Burnfield und andere 2007), ein unter ganz anderem Protokoll bestimmter zweiter Spitzendruck (509 bis 912 kPa aus einer FE-Schuhstudie, Yang und andere 2022) und ein daraus abgeleiteter mittlerer Druck (rund 711 bis 1067 kPa) einander nicht unmittelbar widersprechen,
  4. eine Spannungssingularität erkennen — an einer singulären Lasteinleitung (Punktlast), an einer Traktionskante (Ende einer verteilten Last) oder an einer Lagerkante (harter Randbedingungswechsel) wächst die berechnete Spitzenspannung mit jedem feineren Netz weiter und ist keine belastbare Zahl; die verwandte geometrische Kerbsingularität (einspringende Ecke, Rissspitze) hat die glatte Fersenkontur dagegen nicht.

Bevor das erste Bild entsteht, richten wir das Rechenwerk dieses Kapitels ein. Zwei Zellen tun das, und beide sind eingeklappt: Wer wissen will, woher ein Name in einem späteren Block kommt, klappt sie auf und findet ihn. Die erste sammelt die Zeichenwerkzeuge — die echte Kalkaneus-Kontur, das mittlere Buchnetz, die Orientierungszeile mit Maßstab, die Farbskala — und lädt die sieben offline gerechneten Netzstufen der Vergleichsrechnung, bis 29 093 Knoten, an denen dieses Kapitel die Netzkonvergenz vorführt. Was diese Vergleichsrechnung ist, sagt der Abschnitt „Die Vergleichsrechnung und die Buchnetze” weiter unten.

Das Rechenwerk dieses Kapitels — Kontur, Netz, Farbskala und die sieben Netzstufen der Vergleichsrechnung, zum Nachlesen aufklappen
# --- Nur Zeichenhilfen (numpy/matplotlib): echte Kontur, echtes Buchnetz,
# Orientierung, Farbskala, die offline vorberechneten Netzstufen der
# Vergleichsrechnung. Diese Zelle wird beim Bauabgleich übersprungen (sie
# importiert numpy/matplotlib). KEINE Lehr-Mathematik — die steht in der reinen
# Python-Zelle darunter.
import json
import pathlib

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter

_kontur = json.loads(
    pathlib.Path("../geometrie/kalkaneus_kontur.json").read_text())
KONTUR = np.array(_kontur["punkte"]) * 1000.0        # m -> mm

NETZ_MITTEL = json.loads(pathlib.Path("netze/netz_mittel.json").read_text())

# Die offline vorberechneten Netzstufen der Vergleichsrechnung — sieben Stufen
# bis 29 093 Knoten, im Browser NICHT rechenbar. Herkunft:
# programme/kap13/referenzleiter.json (Deckung < 1e-9; Eck-Spitze ergänzt).
LEITER = json.loads(
    pathlib.Path("programme/kap13/referenzleiter.json").read_text())

def orientierung(ax, mit_massstab=True):
    """„oben ↑"-Pfeil, hinten/vorn und 10-mm-Maßstabsbalken."""
    ax.text(-13, 43, "hinten (Ferse)", fontsize=8, color="#666")
    ax.text(44, 43, "vorn (Zehen)", fontsize=8, color="#666")
    ax.annotate("oben", xy=(-11, 40), xytext=(-11, 26), fontsize=8, color="#444",
                ha="center", arrowprops=dict(arrowstyle="->", color="#444", lw=1.4))
    if mit_massstab:
        ax.plot([54, 64], [-2, -2], color="#333", lw=2.4, solid_capstyle="butt")
        ax.plot([54, 54], [-3.2, -0.8], color="#333", lw=1.2)
        ax.plot([64, 64], [-3.2, -0.8], color="#333", lw=1.2)
        ax.text(59, -5.4, "10 mm", ha="center", fontsize=8, color="#333")

def farbskala_mpa(fig, ax, tpc, maximum):
    """Werte-Legende (turbo) — Farbbalken nie höher als das Bild."""
    cb = fig.colorbar(tpc, ax=ax, fraction=0.046, pad=0.03, extend="max")
    cb.set_label("Von-Mises (MPa)", fontsize=8)
    return cb

Die zweite Zelle ist der sichtbare Lehrcode dieses Kapitels: reines Python ohne Bibliotheken. In ihr stehen der FEM-Kern aus den Kapiteln 10 und 11 (Zeltsteigungen, Elementmatrix, Assemblierung, Gauß-Löser, feste Lagerung, verteilte Last), das Handnetz mit den Werten aus dem Zahlenanhang und die beiden Prüfwerkzeuge dieses Kapitels — hand_nulltest und hand_bilanz. Jede Zahl, die dieses Kapitel später in einer Tabelle zeigt, kommt aus diesen Funktionen; sie ist gerechnet, nicht hingeschrieben. Eingeklappt bleibt die Zelle, weil sie den Vorhersagefragen weiter unten nichts vorwegnehmen soll.

Der Lehrcode dieses Kapitels — FEM-Kern, Nulltest und Bilanzkontrolle, zum Aufklappen
# Reines Python (KEINE Bibliotheken): der sichtbare Lehrcode dieses
# Kapitels. Eingeklappt gehalten — er darf rechnen, nimmt aber
# keiner Vorhersage etwas vorweg; die Tabellen weiter unten rufen diese
# Funktionen erst nach Frage, Darstellung, Deutung und Formel. Der FEM-Kern
# (Zeltsteigungen, Elementmatrix, Assemblierung, Gauß, feste Lagerung, verteilte
# Last) ist derselbe wie in den Kapiteln 10 und 11; hier kommen die zwei
# Prüfwerkzeuge Nulltest und Bilanzkontrolle dazu. Numerisch gegen den
# schnellen Löser hinter den Reglern (programme/kap13/konvergenz.py) und gegen
# scikit-fem gehalten, mit einer Schranke von 10⁻¹⁰.
import math

def komma(x, stellen=2):
    """Deutsche Kommadarstellung mit Endnullen-Trimmung; Minuszeichen −."""
    s = f"{x:.{stellen}f}"
    if "." in s:
        s = s.rstrip("0").rstrip(".")
    return s.replace("-", "−").replace(".", ",")

def zehnerpotenz(x, stellen=1):
    """Deutsche Zehnerpotenz m,mm·10ⁿ (ohne e-Notation) — für Rundungsreste."""
    if x == 0.0:
        return "0"
    e = math.floor(math.log10(abs(x)))
    m = x / 10.0 ** e
    hoch = str(e).translate(str.maketrans("-0123456789", "⁻⁰¹²³⁴⁵⁶⁷⁸⁹"))
    return f"{m:.{stellen}f}".replace("-", "−").replace(".", ",") + "·10" + hoch

def komma_sig(x, n=3):
    """Deutsche Darstellung mit n signifikanten Stellen (ohne e-Notation).
    NUR exakt 0 wird als „0" gezeigt; sehr kleine Nichtnullwerte (Rundungsreste)
    als deutsche Zehnerpotenz — nie stillschweigend nullgeschnappt."""
    if x == 0.0:
        return "0"
    if abs(x) < 1e-4:
        return zehnerpotenz(x)
    s = f"{x:.{n}g}"
    if "e" in s or "E" in s:
        s = f"{x:.12f}".rstrip("0").rstrip(".")
    return s.replace("-", "−").replace(".", ",")

def rest(x, einheit):
    """Residuum/Abweichung: exakt 0 → „0"; Rundungsreste (< 10⁻⁴) als
    Zehnerpotenz mit „(≈ 0)"; sonst der Wert mit Einheit."""
    if x == 0.0:
        return "0 " + einheit
    if abs(x) < 1e-4:
        return zehnerpotenz(x) + " " + einheit + " (≈ 0)"
    return komma_sig(x) + " " + einheit

# --- FEM-Kern (wie Kapitel 10/11) ------------------------------------------
def zeltsteigungen(ecken):
    (xa, ya), (xb, yb), (xc, yc) = ecken[0], ecken[1], ecken[2]
    zwei = xa * (yb - yc) + xb * (yc - ya) + xc * (ya - yb)
    if zwei == 0.0:
        raise ValueError(f"Dreieck entartet (Fläche null): {ecken}")
    b = [(yb - yc) / zwei, (yc - ya) / zwei, (ya - yb) / zwei]
    c = [(xc - xb) / zwei, (xa - xc) / zwei, (xb - xa) / zwei]
    return b, c, abs(zwei) / 2.0

def materialtabelle(e_modul, nu):
    if e_modul <= 0.0:
        raise ValueError(f"E-Modul muss positiv sein: {e_modul}")
    if not (0.0 <= nu < 0.5):
        raise ValueError(f"Querkontraktion ν muss in [0; 0,5) liegen: {nu}")
    faktor = e_modul / (1.0 - nu * nu)
    schub = (1.0 - nu) / 2.0
    return [[faktor, faktor * nu, 0.0],
            [faktor * nu, faktor, 0.0],
            [0.0, 0.0, faktor * schub]]

def b_tabelle(ecken):
    b, c, _ = zeltsteigungen(ecken)
    tab = [[0.0] * 6, [0.0] * 6, [0.0] * 6]
    for e in range(3):
        tab[0][2 * e] = b[e]
        tab[1][2 * e + 1] = c[e]
        tab[2][2 * e] = c[e]
        tab[2][2 * e + 1] = b[e]
    return tab

def elementmatrix(ecken, e_modul, nu, tiefe):
    B = b_tabelle(ecken)
    C = materialtabelle(e_modul, nu)
    _, _, flaeche = zeltsteigungen(ecken)
    cb = [[0.0] * 6 for _ in range(3)]
    for z in range(3):
        for s in range(6):
            summe = 0.0
            for k in range(3):
                summe = summe + C[z][k] * B[k][s]
            cb[z][s] = summe
    Ke = [[0.0] * 6 for _ in range(6)]
    for i in range(6):
        for j in range(6):
            summe = 0.0
            for k in range(3):
                summe = summe + B[k][i] * cb[k][j]
            Ke[i][j] = summe * tiefe * flaeche
    return Ke

def leeres_system(dof):
    return [[0.0] * dof for _ in range(dof)]

def assembliere(knoten, dreiecke, e_modul, nu, tiefe):
    K = leeres_system(2 * len(knoten))
    for dr in dreiecke:
        ecken = [knoten[dr[0]], knoten[dr[1]], knoten[dr[2]]]
        Ke = elementmatrix(ecken, e_modul, nu, tiefe)
        dofs = []
        for e in range(3):
            dofs.append(2 * dr[e])
            dofs.append(2 * dr[e] + 1)
        for a in range(6):
            for b in range(6):
                K[dofs[a]][dofs[b]] = K[dofs[a]][dofs[b]] + Ke[a][b]
    return K

def gauss_loese(A, rhs):
    n = len(rhs)
    a = [zeile[:] for zeile in A]
    b = rhs[:]
    for s in range(n):
        p = s
        for r in range(s + 1, n):
            if abs(a[r][s]) > abs(a[p][s]):
                p = r
        if a[p][s] == 0.0:
            raise ValueError("System nicht lösbar (Pivot null)")
        if p != s:
            a[s], a[p] = a[p], a[s]
            b[s], b[p] = b[p], b[s]
        for r in range(s + 1, n):
            faktor = a[r][s] / a[s][s]
            if faktor != 0.0:
                for c in range(s, n):
                    a[r][c] = a[r][c] - faktor * a[s][c]
                b[r] = b[r] - faktor * b[s]
    x = [0.0] * n
    for r in range(n - 1, -1, -1):
        summe = b[r]
        for c in range(r + 1, n):
            summe = summe - a[r][c] * x[c]
        x[r] = summe / a[r][r]
    return x

def feste_dofs(knoten_liste):
    feste = []
    for k in knoten_liste:
        feste.append(2 * k)
        feste.append(2 * k + 1)
    return feste

def verteilte_last(n_knoten, facetten, kraft_xy):
    """Verteilte Last: eine Gesamtkraft (fx, fy) konsistent über die Facetten
    (i, j, L) — jede trägt den Anteil L/L_gesamt, halb auf jeden Endknoten."""
    f = [0.0] * (2 * n_knoten)
    laenge_gesamt = 0.0
    for fac in facetten:
        laenge_gesamt = laenge_gesamt + fac[2]
    if laenge_gesamt <= 0.0:
        raise ValueError("Randgruppe ohne Facetten")
    fx, fy = kraft_xy
    for (i, j, laenge) in facetten:
        anteil = 0.5 * laenge / laenge_gesamt
        f[2 * i] = f[2 * i] + anteil * fx
        f[2 * i + 1] = f[2 * i + 1] + anteil * fy
        f[2 * j] = f[2 * j] + anteil * fx
        f[2 * j + 1] = f[2 * j + 1] + anteil * fy
    return f

def einzelkraft(n_knoten, knoten_index, kraft_xy):
    """Einzelkraft (Punktlast): die ganze Kraft (fx, fy) an EINEM Knoten."""
    f = [0.0] * (2 * n_knoten)
    f[2 * knoten_index] = kraft_xy[0]
    f[2 * knoten_index + 1] = kraft_xy[1]
    return f

def loese_randwert(K, kraefte, feste_liste):
    """Löst K·u = f mit fester Lagerung: die festen Freiheitsgrade ausbauen und
    das Restsystem lösen. Ohne äußere Last (f = 0) ist u exakt null."""
    dof = len(K)
    feste = set(feste_liste)
    frei = [d for d in range(dof) if d not in feste]
    Kr = [[K[i][j] for j in frei] for i in frei]
    fr = [kraefte[i] for i in frei]
    loesung = gauss_loese(Kr, fr) if frei else []
    u = [0.0] * dof
    for stelle in range(len(frei)):
        u[frei[stelle]] = loesung[stelle]
    return u

def vonmises_hand(K_ecken_liste, knoten, dreiecke, u, e_modul, nu):
    """Von-Mises-Vergleichsspannung je Dreieck (ebener Spannungszustand)."""
    werte = []
    for dr in dreiecke:
        ecken = [knoten[dr[0]], knoten[dr[1]], knoten[dr[2]]]
        b, c, _ = zeltsteigungen(ecken)
        ux = [u[2 * dr[0]], u[2 * dr[1]], u[2 * dr[2]]]
        uy = [u[2 * dr[0] + 1], u[2 * dr[1] + 1], u[2 * dr[2] + 1]]
        eps_xx = b[0] * ux[0] + b[1] * ux[1] + b[2] * ux[2]
        eps_yy = c[0] * uy[0] + c[1] * uy[1] + c[2] * uy[2]
        gamma = (c[0] * ux[0] + c[1] * ux[1] + c[2] * ux[2]
                 + b[0] * uy[0] + b[1] * uy[1] + b[2] * uy[2])
        faktor = e_modul / (1.0 - nu * nu)
        sxx = faktor * (eps_xx + nu * eps_yy)
        syy = faktor * (nu * eps_xx + eps_yy)
        txy = e_modul / (2.0 * (1.0 + nu)) * gamma
        werte.append(math.sqrt(sxx * sxx - sxx * syy + syy * syy + 3.0 * txy * txy))
    return werte

def lagerreaktion(K, u, kraefte, knoten_liste, knoten_xy):
    """Lagerreaktion R = K·u − f an den festen Freiheitsgraden, als Kraft (fx,
    fy) UND Moment um den Ursprung. So schließt die Bilanzkontrolle Kraft und
    Moment zugleich."""
    fx, fy, m = 0.0, 0.0, 0.0
    for k in knoten_liste:
        rx, ry = -kraefte[2 * k], -kraefte[2 * k + 1]
        for j in range(len(K)):
            rx = rx + K[2 * k][j] * u[j]
            ry = ry + K[2 * k + 1][j] * u[j]
        fx = fx + rx
        fy = fy + ry
        m = m + knoten_xy[k][0] * ry - knoten_xy[k][1] * rx
    return {"fx": fx, "fy": fy, "m": m}

# --- Das Handnetz (13 Knoten, 13 Dreiecke) — identisch mit Kapitel 10/11 ----
# Doppelfächer: zwei innere Knoten 8 (links) und 11 (rechts),
# zwischen ihnen ein Verbindungsband (Dreiecke (1,11,8) und (5,8,11)). Der
# plantare Fächerteil 0 → 9 → 10 → 1 bildet den vorderen unteren Abhang nach:
# Knoten 9 (21,8/0,0 mm) ist der tiefste Punkt, Knoten 10 (25,9/7,1 mm) das
# obere Ende des Abhangs; die Facette 9 → 10 ist die Enthese am realen
# Sporn-Ort. Am hinteren Rand sitzt Knoten 12 (4,0/22,0 mm) zwischen
# den Knoten 6 und 7, mit den Dreiecken (6,12,8) und (12,7,8).
# Identisch mit dem Handnetz der Vergleichsrechnung.
HANDNETZ_KNOTEN = [
    (0.006, 0.0000), (0.033, 0.0134), (0.052, 0.006), (0.066, 0.018),
    (0.050, 0.033), (0.030, 0.032), (0.012, 0.032), (0.001, 0.012),
    (0.016, 0.015), (0.0218, 0.0000), (0.0259, 0.0071), (0.036, 0.024),
    (0.004, 0.022)]
HANDNETZ_DREIECKE = [
    (7, 0, 8), (0, 9, 8), (9, 10, 8), (10, 1, 8),
    (5, 6, 8), (6, 12, 8), (12, 7, 8),
    (1, 2, 11), (2, 3, 11), (3, 4, 11), (4, 5, 11),
    (1, 11, 8), (5, 8, 11)]
HAND_LAGER = (4, 5, 6)          # feste Lagerung: die Talus-Gelenkfläche oben
                                #   (dieselben Knoten wie in Kapitel 11 und 12)
HAND_BODEN_KANTEN = [(0, 7), (0, 9), (9, 10)]   # die drei Bodenfacetten
HAND_BODEN = (0, 7, 9, 10)      # die Knoten der Auftrittsfläche
E_KORTIKAL = 17.0e9            # Pa, kortikaler Knochen (Zahlenkanon)
NU_KNOCHEN = 0.30             # Querkontraktion Knochen (Zahlenkanon)
TIEFE = 0.033                 # m, Ersatzdicke der 2D-Scheibe (Zahlenkanon)
KG = 736.0                   # N, Körpergewicht der Referenzperson (Zahlenkanon)
F_BODEN = 2.5 * KG           # N, aktive Bodenreaktion 2,5 · KG (Zahlenkanon)

# Die drei Bodenfacetten des Handnetzes, jede mit ihrer Länge.
def _kantenlaenge(i, j):
    (xa, ya), (xb, yb) = HANDNETZ_KNOTEN[i], HANDNETZ_KNOTEN[j]
    return math.sqrt((xb - xa) ** 2 + (yb - ya) ** 2)

HAND_BODEN_FAC = [(i, j, _kantenlaenge(i, j)) for (i, j) in HAND_BODEN_KANTEN]
HAND_K = assembliere(HANDNETZ_KNOTEN, HANDNETZ_DREIECKE,
                     E_KORTIKAL, NU_KNOCHEN, TIEFE)
# Der „vergessene" Phantom-Term der Sabotage (ein Einheitenfehler): eine kleine
# senkrechte Kraft, die auf JEDEM Knoten stehen bleibt — rund 6 % der Bodenkraft,
# gleichmäßig verteilt. Auf einer Anzeige-Schwelle NICHT gesetzt, sondern aus der
# Bodenkraft abgeleitet.
PHANTOM_JE_KNOTEN = 0.06 * F_BODEN / len(HANDNETZ_KNOTEN)

def hand_phantom(phantom_je_knoten):
    """Ein senkrechter Phantom-Last-Anteil je Knoten (der Einheitenfehler)."""
    f = [0.0] * (2 * len(HANDNETZ_KNOTEN))
    for k in range(len(HANDNETZ_KNOTEN)):
        f[2 * k + 1] = f[2 * k + 1] + phantom_je_knoten
    return f

def hand_nulltest(phantom_je_knoten=0.0):
    """Nulltest: NULL äußere Last (nur ein etwaiger Phantom-Fehler). Ein
    fehlerfreies Modell liefert exakt u = 0 und Von-Mises 0; jede Abweichung
    verrät einen Programm- oder Randfehler."""
    f = hand_phantom(phantom_je_knoten)
    u = loese_randwert(HAND_K, f, feste_dofs(HAND_LAGER))
    max_u = 0.0
    for wert in u:
        if abs(wert) > max_u:
            max_u = abs(wert)
    vm = vonmises_hand(None, HANDNETZ_KNOTEN, HANDNETZ_DREIECKE, u,
                       E_KORTIKAL, NU_KNOCHEN)
    return {"max_u_mm": max_u * 1000.0, "max_vm_mpa": max(vm) / 1e6}

def hand_bilanz(phantom_je_knoten=0.0):
    """Zwei GETRENNTE Prüfungen, beide in Kraft UND Moment:

      * internes Gleichgewicht (Last + Reaktion): das gilt IMMER, wenn das
        System gelöst wurde — auch bei falscher Last; es prüft nur, dass der
        Löser konsistent gerechnet hat. Residuum ≈ 0.
      * Soll-Last-Abgleich (Reaktion + bekannte Soll-Bodenlast): findet den
        Phantom-Fehler, weil die Reaktion dann mehr trägt als die bekannte
        Bodenlast. Ein Last-/Einheitenfehler bricht das interne Gleichgewicht
        NICHT, aber diesen Abgleich schon."""
    f_soll = verteilte_last(len(HANDNETZ_KNOTEN), HAND_BODEN_FAC, (0.0, F_BODEN))
    f_ist = f_soll[:]
    phantom = hand_phantom(phantom_je_knoten)
    for d in range(len(f_ist)):
        f_ist[d] = f_ist[d] + phantom[d]
    u = loese_randwert(HAND_K, f_ist, feste_dofs(HAND_LAGER))
    reaktion = lagerreaktion(HAND_K, u, f_ist, HAND_LAGER, HANDNETZ_KNOTEN)
    # aufgebrachte Last (f_ist) und bekannte Soll-Last (f_soll), je Kraft + Moment.
    last_fx, last_fy, last_m = 0.0, 0.0, 0.0
    soll_fx, soll_fy, soll_m = 0.0, 0.0, 0.0
    for k in range(len(HANDNETZ_KNOTEN)):
        x, y = HANDNETZ_KNOTEN[k]
        last_fx = last_fx + f_ist[2 * k]
        last_fy = last_fy + f_ist[2 * k + 1]
        last_m = last_m + x * f_ist[2 * k + 1] - y * f_ist[2 * k]
        soll_fx = soll_fx + f_soll[2 * k]
        soll_fy = soll_fy + f_soll[2 * k + 1]
        soll_m = soll_m + x * f_soll[2 * k + 1] - y * f_soll[2 * k]
    return {"last_fy": last_fy, "reaktion_fy": reaktion["fy"],
            "residuum_fx": last_fx + reaktion["fx"],
            "residuum_fy": last_fy + reaktion["fy"],
            "residuum_m": last_m + reaktion["m"],
            "abweichung_fx": reaktion["fx"] + soll_fx,
            "abweichung_fy": reaktion["fy"] + soll_fy,
            "abweichung_m": reaktion["m"] + soll_m}

13.1 Der Aufhänger: eine Größe, zwei Zahlen

Dasselbe Modell, dieselbe Last, derselbe Löser — nur das Netz ist ein anderes. Auf dem gröbsten der sieben Netze, die dieses Kapitel gleich vorführt, meldet die höchste Spannung im Knochen 52,1 Megapascal, auf dem feinsten 164,2. Welche Zahl stimmt? Vom Ansehen der zwei Bilder: keine Antwort. Beide sind bunt, beide sehen richtig aus, und das feinere sieht sogar vertrauenswürdiger aus.

Die Auflösung sei vorweggenommen, damit klar ist, worauf dieses Kapitel hinausläuft: keine von beiden. Diese Zahl gibt es in diesem Modell nicht — sie wächst mit jedem feineren Netz weiter, und zwar aus einem Grund, den man kennen und benennen kann. Eine andere Zahl aus derselben Rechnung, auf denselben sieben Netzen, steht dagegen ab der dritten Stufe fest und rührt sich danach nur noch in der dritten Stelle. Der Unterschied zwischen diesen beiden Zahlen ist der Inhalt dieses Kapitels: Am Ende weißt du, welche Sorte Zahl aus einer Simulation man aufschreiben darf und welche nicht.

13.2 Die drei Fragen an jede Simulation

Bevor man einem Spannungsbild traut, stellt man ihm drei Fragen — und für jede gibt es ein Werkzeug.

HinweisVerifikation und Validierung — zwei verschiedene Fragen

Verifikation fragt: Löse ich die Gleichungen richtig? Rechnet das Programm das Modell fehlerfrei — richtig assembliert, richtig gelagert, fein genug vernetzt? Das prüft man im Modell selbst: mit Prüffällen (Nulltest), mit der Bilanzkontrolle und mit der Netzkonvergenz. Alle drei kommen in diesem Kapitel vor.

Validierung fragt: Löse ich die richtigen Gleichungen? Bildet das Modell die Wirklichkeit ab — stimmen seine Vorhersagen mit einer Messung überein? Das prüft man gegen die Welt, mit unabhängigen experimentellen Daten für dieselbe Zielgröße und dasselbe Protokoll (patientenspezifisch nur dann, wenn das Modell einen patientenspezifischen Anspruch erhebt). Solche Daten lagen diesem Buch nicht vor; Validierung bleibt deshalb ein Ausblick über sein Ende hinaus. Ein verifiziertes Modell kann sauber die falschen Gleichungen lösen — deshalb braucht es beide. Die Vergleichsrechnung, deren sieben Netzstufen dieses Kapitel zeigt, ist entsprechend eine numerisch geprüfte Rechnung — geprüft im Sinne der linken Spalte, nicht gegen Messdaten geprüft im Sinne der rechten.

Die ersten beiden Werkzeuge — Nulltest und Bilanzkontrolle — laufen auf dem kleinen Handnetz aus Kapitel 10 (dreizehn Knoten, dreizehn Dreiecke), damit man sie von Hand nachvollziehen kann. Die Ränder sind dieselben wie in Kapitel 11 und Kapitel 12: fest gelagert ist die Talus-Gelenkfläche oben, also die Knoten 4, 5 und 6; die Bodenlast sitzt auf den drei plantaren Facetten (0, 7), (0, 9) und (9, 10). Last- und Lagerknoten berühren sich damit nicht — was oben eingespannt ist, wird unten nicht belastet, und beim Streichen der festen Zeilen geht kein Newton verloren. Anders als in Kapitel 11 zieht hier nur der Boden: Achillessehne und Faszie bleiben weg, damit die zwei Prüfungen an einer einzigen bekannten Last vorgeführt werden können.

13.3 Prüffall Nulltest: die unbelastete Ferse muss spannungsfrei sein

Der schärfste Prüffall ist der einfachste. Nimmt man dem Modell jede äußere Last und hält es nur an der Talus-Gelenkfläche fest, dann darf sich nichts verformen und nirgends darf Spannung entstehen: null Last, null Verschiebung, null Spannung. Als Maß der Beanspruchung dient dabei die Von-Mises-Spannung — eine skalare Vergleichsspannung, die den mehrachsigen Spannungszustand zu einer einzigen Zahl je Element zusammenfasst (hier ein Vergleichsmaß, kein geprüftes Versagenskriterium für Knochen). Das folgt aus der Linearität aus Kapitel 5\(K \cdot 0 = 0\). Kommt trotzdem etwas heraus, steckt ein Fehler im Programm oder am Rand. Der Lehrcode löst genau das auf dem Handnetz — festgehalten an den drei Talus-Knoten, ohne jede äußere Last — und misst die größte Verschiebung und die größte Von-Mises-Spannung, die dabei herauskommen (Tabelle 13.1):

Tabelle 13.1: Der Nulltest am Handnetz: feste Lagerung an der Talus-Gelenkfläche (Knoten 4, 5, 6), aber keine äußere Last. Ein fehlerfreies Modell muss hier exakt Null liefern.
Kennzahl des Nulltests Wert
größte Verschiebung (mm) 0
größte Von-Mises-Spannung (MPa) 0

Deutung unter der Tabelle. Beide Werte sind exakt null — keine gerundete Näherung, sondern die Null selbst: ohne Last löst das Gleichungssystem \(K\,u = 0\) mit \(u = 0\), und aus null Verschiebung folgt null Spannung. Das ist wenig spektakulär und trotzdem das schärfste Werkzeug: Jeder Fehler, der aus dem Nichts eine Kraft erzeugt — ein vergessener Term, ein falsch stehen gebliebener Wert, eine verrutschte Einheit — macht aus dieser Null eine Zahl ungleich null und wird sofort sichtbar. Genau das nutzt der Modellzustand-Regler am Kapitelende.

13.4 Die Bilanzkontrolle: Last gleich Reaktion, in Kraft und Moment

Das zweite Werkzeug läuft immer mit — aber es kann zweierlei prüfen, und die zwei muss man auseinanderhalten. Die Bilanzkontrolle rechnet die Lagerreaktion als \(R = K\,u - f\) an den festen Talus-Knoten aus. Damit prüft man erstens das interne Gleichgewicht: Summieren sich die tatsächlich aufgebrachte Last und die Reaktion zu null (in waagerechter Kraft, senkrechter Kraft und Drehmoment)? Das gilt allerdings immer, sobald das Gleichungssystem gelöst wurde — auch bei falscher Last; es zeigt nur, dass der Löser konsistent gerechnet hat. Zweitens gleicht man die Reaktion mit der unabhängig bekannten Soll-Last ab: Trägt das Lager genau die Last, die man aufbringen wollte? Dieser Soll-Last-Abgleich fängt einen vergessenen oder falsch eingetragenen Lastterm — das interne Gleichgewicht nicht (zweite Prüfstufe). Abbildung 13.1 zeigt beides am Buchnetz; die Reaktion ist dabei kein Einzelpfeil, sondern die verteilten Auflagerkräfte entlang der Talus-Fläche (eine Kraft plus ein Moment).

Code
import sys
import pathlib

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrow

sys.path.insert(0, str(pathlib.Path("programme/kap13").resolve()))
sys.path.insert(0, str(pathlib.Path("programme/gemeinsam").resolve()))
import konvergenz

modell = konvergenz.neue_pruefung(NETZ_MITTEL)
lb = modell.bilanz()

fig, ax = plt.subplots(figsize=(7.0, 5.0))
ax.fill(KONTUR[:, 0], KONTUR[:, 1], color="#f0e2d0", ec="#8a6a4a", lw=1.6, zorder=0)
sk = 8.0 / 3200.0                      # Pfeil-Längenmaßstab: mm je Newton

def pfeil(x, y, fx, fy, farbe, width=0.5, head=2.6):
    ax.add_patch(FancyArrow(x, y, fx * sk, fy * sk, width=width, head_width=head,
                 length_includes_head=True, color=farbe, zorder=4))

# aufgebrachte Lasten (Resultierende) an ihren Angriffsorten (Konturanker).
pfeil(8.59, 2.24, lb["teile"]["boden"]["fx"], lb["teile"]["boden"]["fy"], "#1f6fb4")
pfeil(1.34, 23.28, lb["teile"]["achilles"]["fx"], lb["teile"]["achilles"]["fy"], "#1f6fb4")
pfeil(24.07, 3.35, lb["teile"]["faszie"]["fx"], lb["teile"]["faszie"]["fy"], "#1f6fb4")
# Talus-Reaktion als DAS, was sie ist: die verteilten Auflager-Knotenkräfte
# (kleine Pfeile je Talus-Knoten) — nicht ein Einzelpfeil an falscher Wirkungslinie.
for kn in lb["lager_knoten"]:
    pfeil(kn["x_mm"], kn["y_mm"], kn["fx"], kn["fy"], "#2a7d2a", width=0.25, head=1.6)
# ihre Resultierende (dicker) plus das Moment M_R getrennt angeschrieben.
rx0 = float(np.mean([kn["x_mm"] for kn in lb["lager_knoten"]]))
ry0 = float(np.mean([kn["y_mm"] for kn in lb["lager_knoten"]]))
pfeil(rx0, ry0, lb["reaktion_fx"], lb["reaktion_fy"], "#146a14", width=0.6, head=3.0)
ax.annotate("Talus-Reaktion: verteilte Auflagerkräfte\n(Resultierende "
            + komma(lb["reaktion_fy"], 0) + " N + Moment M$_R$ = "
            + komma(lb["reaktion_m"], 1) + " N·m)",
            xy=(rx0, ry0), xytext=(24, 44), color="#146a14", fontsize=8)
ax.text(6, -8, "aufgebrachte Lasten (blau): Bodenreaktionskraft, Achilles, Faszie",
        color="#1f6fb4", fontsize=9)
ax.plot([40, 40 + 1000 * sk], [-11, -11], color="#333", lw=2.4)
ax.text(40 + 500 * sk, -13.6, "1000 N", ha="center", fontsize=8, color="#333")
ax.plot([54, 64], [-11, -11], color="#333", lw=2.4)
ax.text(59, -13.6, "10 mm", ha="center", fontsize=8, color="#333")

orientierung(ax, mit_massstab=False)
ax.set_xlim(-16, 70); ax.set_ylim(-16, 52)
ax.set_aspect("equal"); ax.axis("off")
plt.tight_layout()
plt.show()

print("Aufgebrachte Last:  Fx =", komma(lb["last_fx"], 1), "N,  Fy =",
      komma(lb["last_fy"], 1), "N,  Moment =", komma(lb["last_m"], 3), "N·m")
print("Talus-Reaktion:     Fx =", komma(lb["reaktion_fx"], 1), "N,  Fy =",
      komma(lb["reaktion_fy"], 1), "N,  Moment =", komma(lb["reaktion_m"], 3), "N·m")
print("Internes Gleichgewicht (Last + Reaktion):")
print("  Fx =", rest(lb["residuum_fx"], "N"), " Fy =", rest(lb["residuum_fy"], "N"))
print("  Moment =", rest(lb["residuum_m"], "N·m"))
print("Soll-Last-Abgleich (Reaktion + bekannte Soll-Last):")
print("  Fy =", rest(lb["abweichung_fy"], "N"))
print("  Moment =", rest(lb["abweichung_m"], "N·m"))
Abbildung 13.1: Bilanzkontrolle im Gleichgewicht (mittlere Standphase, live auf dem Buchnetz gerechnet mit programme/kap13/konvergenz.py). Blau die drei aufgebrachten Lasten — Bodenreaktionskraft (Resultierende der verteilten Bodentraktion), Achillessehnenzug, Faszienzug — als Resultierende an ihren realen Angriffsorten. Grün die GERECHNETE Talus-Reaktion R = K·u − f, und zwar als das, was sie wirklich ist: die verteilten Auflager-Knotenkräfte entlang der Talus-Gelenkfläche (kleine grüne Pfeile). Ein einzelner Reaktionspfeil wäre irreführend, denn das Lager überträgt eine Kraft PLUS ein Moment; ihre Resultierende (dicker grüner Pfeil) und das Moment M_R sind getrennt angeschrieben. Unten der Kraftmaßstab (1000 N) und der Geometriemaßstab (10 mm). Kraft- UND Momentenbilanz gehen bis auf Rundungsreste zu null auf. Sagittalschnitt, x nach vorn, y nach oben.
Aufgebrachte Last:  Fx = −6,6 N,  Fy = 3167,4 N,  Moment = 30,372 N·m
Talus-Reaktion:     Fx = 6,6 N,  Fy = −3167,4 N,  Moment = −30,372 N·m
Internes Gleichgewicht (Last + Reaktion):
  Fx = −1,7·10⁻¹⁰ N (≈ 0)  Fy = 2,5·10⁻¹⁰ N (≈ 0)
  Moment = 2,2·10⁻¹² N·m (≈ 0)
Soll-Last-Abgleich (Reaktion + bekannte Soll-Last):
  Fy = 2,5·10⁻¹⁰ N (≈ 0)
  Moment = 2,2·10⁻¹² N·m (≈ 0)

Deutung unter der Ausgabe. Beim korrekten Modell gehen beide Prüfungen auf: das interne Gleichgewicht (Last + Reaktion) ist bis auf Rundungsreste null in Kraft und Moment, und der Soll-Last-Abgleich (Reaktion gegen die bekannte Soll-Last) ebenfalls. Wichtig ist, wie die Reaktion entsteht: nicht als umgedrehte Last, sondern als \(R = K\,u - f\) aus der Lösung — und sie ist eine über die Talus-Fläche verteilte Kraft mit einem Moment, kein Einzelpfeil. Am Handnetz lässt sich derselbe Wächter von Hand nachrechnen: Der Lehrcode stellt die verteilte Bodenlast (\(2{,}5 \cdot\) KG) der Lagerreaktion gegenüber und führt beide Prüfungen getrennt aus — internes Gleichgewicht und Soll-Last-Abgleich, je in Kraft und Moment (Tabelle 13.2):

Tabelle 13.2: Bilanzkontrolle am Handnetz: die verteilte Bodenlast gegen die gerechnete Lagerreaktion, geprüft in zwei getrennten Stufen — internes Gleichgewicht (Last + Reaktion) und Soll-Last-Abgleich (Reaktion + bekannte Bodenlast), je in Kraft und Moment. Rundungsreste stehen als deutsche Zehnerpotenz mit „(≈ 0)“, nicht als glatte Null.
Größe Wert
aufgebrachte Bodenlast senkrecht 1840 N
Lagerreaktion senkrecht −1840 N
internes Gleichgewicht, \(F_y\) −1,1·10⁻¹² N (≈ 0)
internes Gleichgewicht, Moment −4,3·10⁻¹⁴ N·m (≈ 0)
Soll-Last-Abgleich, \(F_y\) −1,1·10⁻¹² N (≈ 0)
Soll-Last-Abgleich, Moment −4,3·10⁻¹⁴ N·m (≈ 0)

Deutung unter der Tabelle. Das feste Lager trägt exakt die aufgebrachte Bodenlast — internes Gleichgewicht und Soll-Last-Abgleich sind bis auf Rundungsreste null (die als deutsche Zehnerpotenz mit „(≈ 0)” ausgewiesen sind, nicht als glatte Null verschluckt). Dass der sichtbare Lehrcode, der schnelle Löser hinter den Reglern und ein unabhängiges Rechenprogramm hier dieselbe Zahl liefern, prüft das Buch bei jedem Bau mit einer Schranke von \(10^{-10}\). Der Bilanz-Wächter allein beweist noch nichts über die Physik — aber der Soll-Last-Abgleich fängt eine ganze Klasse von Fehlern, bei denen die Reaktion nicht zur bekannten Last passt.

13.5 Die Vergleichsrechnung und die Buchnetze

Bis hierher hat dieses Buch zwei Sorten Rechnung benutzt, ohne sie auseinanderzuhalten. Das wird jetzt nachgeholt, denn die nächste Abbildung zeigt Zahlen aus der zweiten Sorte.

Die Buchnetze sind die Netze, die im Browser rechnen: das Handnetz mit seinen dreizehn Knoten und drei größere Netze über dieselbe Kontur — grob, mittel und fein, das feinste mit 2199 Knoten. Sie rechnen die Ferse als einen einzigen, homogen gedachten Knochen mit dem E-Modul der harten Außenschale (Kapitel 10, Absatz „Welcher Knochen hier steckt”), fest gelagert an der Talus-Gelenkfläche. Jedes Bild, das ein Regler dieses Buches zeigt, kommt von ihnen; sie müssen in einer halben Sekunde fertig sein.

Die Vergleichsrechnung lief außerhalb des Browsers, ohne Zeitdruck: dieselbe Ferse, aber auf sieben immer feineren Netzen bis 29 093 Knoten, mit einem ausgewachsenen Rechenprogramm statt mit Lehrcode und — je nach Frage — mit geschichtetem Material statt mit einem einzigen. Aus ihr stammt jede Zahl, die dieses Buch als belastbar bezeichnet, denn nur bei ihr lässt sich überhaupt zeigen, dass eine Zahl beim Verfeinern zur Ruhe kommt. Geprüft ist sie zweifach: Ihre Ergebnisse wurden gegen zwei unabhängig geschriebene Rechenprogramme gehalten, die bis in die dreizehnte Stelle dasselbe liefern, und jede Kennzahl, die dieses Buch aus ihr zitiert, musste die Netzstudie bestehen, die gleich folgt. Nicht geprüft ist sie gegen Messungen — das ist die rechte Spalte des Kastens oben, und die bleibt in diesem Buch leer.

Beide rechnen dieselbe Ferse, aber nicht dasselbe Modell. Ihre Zahlen darf man nebeneinanderlegen, nicht gleichsetzen. Tabelle 13.3 hält den Unterschied fest — dazu die beiden Abwandlungen der Buchnetze, mit denen Teil VI arbeitet, und die Literaturzahlen des Zahlenanhangs, die weder das eine noch das andere sind.

Tabelle 13.3: Die Rechnungen dieses Buches nebeneinander. Alle rechnen dieselbe Ferse im Sagittalschnitt und lagern sie an derselben Gelenkfläche; sie unterscheiden sich im Netz, im Material und in dem, wofür ihre Zahlen taugen.
Rechnung rechnet in Netz Material Lager Zahlen, die das Buch daraus nimmt
Buchnetze Kapitel 10 bis 15, hinter jedem Regler Handnetz 13 Knoten; grob 330, mittel 768, fein 2199 Knoten homogen kortikal: 17 GPa, \(\nu = 0{,}30\), Ersatzdicke 33 mm Talus-Gelenkfläche fest Von-Mises-Felder bis 10 MPa; plantare Zonenspannung rund 3,1 MPa
Buchnetze mit Dichtefeld Kapitel 16 und 17 Buchnetze Spongiosa: Dichte 0,2 bis 1,0 g/cm³, E daraus nach Morgan; Kapitel 16 zeigt den gleichmäßigen Startzustand 0,50 g/cm³ Talus-Gelenkfläche fest Reiz der plantaren Zone im Startzustand rund 4,6 J/kg; Sollwert des Umbaulaufs rund 8,9 J/kg
Buchnetze mit dem Aufbau der Vergleichsrechnung Kapitel 18 Buchnetze kortikale Schale 17 GPa (wird nicht umgebaut), spongiöser Kern, weiche Enthese ab 0,20 g/cm³ Talus-Gelenkfläche fest Reize nahe dem Sollwert 4,84 J/kg; Abstand der beiden Aufbauorte rund 17 mm
Vergleichsrechnung (außerhalb des Browsers) zitiert in den Kapiteln 13, 15, 16, 17, 18 bildbasierte Kontur, sieben Stufen von 777 bis 29 093 Knoten für die Netzstudie homogen kortikal 17 GPa (das isoliert den reinen Netzfehler); für die Umbauläufe Schale, Kern und Enthese wie in der Zeile darüber Talus-Gelenkfläche fest Zonenspannung 6,18 MPa; Eck-Spitze 52 bis 164 MPa; Sollwerte 5,2 und 4,84 J/kg
Zahlenanhang Kapitel 1, dieses Kapitel, Anhang keine Rechnung, sondern Literatur Spitzendruck unter der Ferse 139 kPa im Stehen, 188 kPa beim Laufen — Drücke unter der Sohle, keine inneren Spannungen

Drei Stellen, an denen die Tabelle Verwirrung erspart. Erstens: Die Spannungsfelder in Kapitel 12 reichen bis 10 MPa, der Zahlenanhang nennt 0,188 MPa. Das eine ist eine innere Spannung im homogen kortikalen Modellknochen, das andere ein gemessener Druck zwischen Fuß und Schuh — zwei verschiedene Größen an zwei verschiedenen Orten, nicht zwei Antworten auf dieselbe Frage. Zweitens: Die Vergleichsrechnung nennt gleich 6,18 MPa, Kapitel 15 nennt 3,1 MPa. Das sind zwei verschiedene Auswertezonen desselben Knochens — die eine liegt im Inneren der Tuber-Region, die andere plantar unter \(y = 6\) mm. Drittens: Der Reiz heißt in Kapitel 16 rund 4,6 J/kg, in Kapitel 17 rund 8,9 J/kg und in der Vergleichsrechnung 5,2 J/kg. Alle drei rechnen auf Spongiosa, aber der erste ist ein Mittel der plantaren Zone im gleichmäßigen Startzustand, der zweite ein Mittel über das ganze Netz, der dritte stammt vom feinsten Netz der Vergleichsrechnung. Sie liegen deshalb nahe beieinander, ohne dasselbe zu sein. Keine dieser Zahlen ist falsch. Keine zwei von ihnen darf man voneinander abziehen.

Ein Wort zur Auswertezone der nächsten Abbildung, weil ihr Name in die Irre führen kann: Sie heißt „im spongiösen Kern”, und das ist eine Ortsangabe — der Bereich, in dem beim wirklichen Fersenbein die Spongiosa liegt. Die Netzstudie selbst rechnet, wie die Tabelle sagt, mit homogenem Material. Genau darum: Wer den reinen Netzfehler messen will, hält alles andere fest.

13.6 Netzkonvergenz: was konvergiert — und was nicht

Die dritte Frage — ist das Netz fein genug? — beantwortet die Netzkonvergenz. Man verfolgt eine Kennzahl über immer feinere Netze und sieht zu, ob sie sich einem festen Wert nähert. Der Rest zwischen der Näherung auf einem groben Netz und dem Grenzwert heißt Diskretisierungsfehler; Verfeinern verkleinert ihn. Die Vergleichsrechnung wurde dafür über sieben Netzstufen bis 29 093 Knoten gefahren — im Browser nicht machbar, deshalb außerhalb vorberechnet. Der Regler unten zeigt zwei Kennzahlen über diese sieben Stufen. Die erste ist die flächengewichtete Zonenspannung: die Von-Mises-Spannung, gemittelt über einen festen Kasten im Inneren der Tuber-Region, jedes Dreieck so schwer gewichtet, wie es groß ist. Die zweite ist die Zusammendrückung der Auftrittszone: der Betrag der senkrechten Verschiebung, gemittelt über alle Netzknoten in einem festen Kasten unten am Tuber, dort, wo Boden und Faszie angreifen. Kein Absinken unter Last also, sondern das Stück Weg, das die Unterseite auf das feste Lager zu zurücklegt.

WichtigVorhersage-Punkt

Bevor du den Regler bewegst: Zwei Kennzahlen laufen über die sieben Netzstufen — die flächengewichtete Zonenspannung und die Zusammendrückung der Auftrittszone. Nähern sich beide mit feinerem Netz einem festen Wert, oder kriecht eine von beiden weiter, während die andere einläuft? Lege dich fest, dann schiebe.

Der folgende sichtbare Block liest die sieben vorberechneten Netzstufen und trägt beide Kennzahlen über die Knotenzahl auf. Sichtbar bleibt, welche Reihen gelesen werden und was aus ihnen abzulesen ist; die reine Zeichenmechanik (zwei Achsen untereinander, Richardson-Linie, Achsenformat) liegt in zeichne_konvergenz unter programme/kap13/.

Zonenspannung und Zusammendrückung aus den sieben Netzstufen lesen
from konvergenzbild import zeichne_konvergenz

v = LEITER["verlauf"]
knoten = [stufe["knoten"] for stufe in v]           # x-Achse: Netzgröße
zone = [stufe["zonen_vm_mpa"] for stufe in v]       # läuft sie ein?
rand = [stufe["senkung_mm"] for stufe in v]         # oder kriecht sie weiter?
d_zone = LEITER["konvergiert"]["d_vm_prozent"]      # Δ der zwei feinsten Netze
d_rand = LEITER["konvergiert"]["d_senkung_prozent"]
grenz = LEITER["richardson"]["grenzwert_mm"]        # Richardson-Grenzwert
d_23 = 100.0 * abs(zone[2] - zone[1]) / zone[2]     # Änderung Stufe 2 → Stufe 3

zeichne_konvergenz(knoten, zone, rand, d_zone, d_rand, grenz, komma_sig)

print("Zwischen den zwei feinsten Netzen: Zonenspannung", komma_sig(d_zone, 3),
      "% (konvergiert),  Zusammendrückung", komma_sig(d_rand, 3), "% (kriecht weiter)")
print("Beobachtete Ordnung", komma(LEITER["richardson"]["p_beobachtet"], 2),
      "→ Richardson-Grenzwert", komma_sig(grenz, 4), "mm (Restabstand",
      komma_sig(LEITER["richardson"]["restabstand_prozent"], 2), "%)")
Abbildung 13.2: Zwei Kennzahlen der Vergleichsrechnung über sieben vorberechnete Netzstufen (777 bis 29 093 Knoten), untereinander. Oben die flächengewichtete Von-Mises-Spannung in der Auswertezone im Inneren der Tuber-Region (x 6–26 / y 10–24 mm): sie läuft ein und unterschreitet die 0,5-%-Schranke. Unten die Zusammendrückung der Auftrittszone (Knotenmittel des Betrags der senkrechten Verschiebung im Kasten x 4–24 / y 0–9 mm): sie bleibt über der Schranke. Die rote gestrichelte Linie ist der Richardson-Grenzwert. Beide Achsen sind schmale Ausschnitte (Null nicht gezeigt); die Prozent-Änderung steht an der Kurve. Herkunft: programme/kap13/referenzleiter.json.
Zwischen den zwei feinsten Netzen: Zonenspannung 0,156 % (konvergiert),  Zusammendrückung 0,724 % (kriecht weiter)
Beobachtete Ordnung 1,27 → Richardson-Grenzwert 0,01994 mm (Restabstand 1,3 %)

Deutung. Das ist die Antwort auf die Vorhersagefrage: Die beiden Kennzahlen verhalten sich verschieden. Die flächengewichtete Zonenspannung läuft sauber ein — zwischen den zwei feinsten Netzen ändert sie sich nur noch um 0,156 %, sie unterschreitet die Schranke und darf ins Buch. Die Zusammendrückung der Auftrittszone aber kriecht weiter (0,724 %, über der Schranke).

Der Grund steht am Rand des Lagers. Dort, wo die feste Einspannung aufhört und der freie Rand beginnt, wechselt die Randbedingung abrupt — und an einem solchen Wechsel ist die Lösung nicht glatt. Das ist die Lagerkantensingularität, und sie bremst nicht nur die Spannung an dieser einen Kante, sondern die Genauigkeit der ganzen Verschiebungslösung, auch weit weg davon. Messen lässt sich das an der Konvergenzordnung: Wie schnell schrumpft der Fehler, wenn man die Netzweite halbiert? Kapitel 9 hat am glatten eindimensionalen Zugstab die Ordnung zwei gefunden — halbe Netzweite, ein Viertel des Fehlers — und dazugesagt, dass das der Bestfall ist. Hier misst dieselbe Rechnung nur 1,27. Halbe Netzweite drückt den Fehler also nicht auf ein Viertel, sondern nur auf gut zwei Fünftel. Genau das sieht man an der unteren Kurve, die sich Stufe um Stufe nur noch zäh bewegt.

Woher kommt die Richardson-Extrapolation, die als rote Linie im Bild steht? Sie macht aus drei aufeinanderfolgenden Netzstufen zwei Zahlen. Aus den drei Werten und ihren Netzweiten lässt sich erstens ablesen, wie schnell die Folge kleiner wird — das ist die beobachtete Ordnung. Und ist die einmal bekannt, kann man zweitens ausrechnen, wo die Folge landen würde, wenn man das Netz beliebig weiter verfeinerte: der Grenzwert. Hier sind das 0,01994 mm; das feinste gerechnete Netz liegt noch 1,3 % davon entfernt. Das ist keine Zauberei und kein Ersatz für ein feineres Netz — es ist eine Schätzung, die genau so gut ist wie die Annahme, dass die drei Stufen schon im gleichmäßigen Bereich liegen. Aber sie beziffert, was noch fehlt, statt es zu verschweigen.

Ein Wort zur Vorsicht gehört dazu: Diese Kennzahl ist ein Mittel über die Knoten in einem festen Kasten, und wie viele Knoten dort liegen, ändert sich mit dem Netz. Ein Teil der Zähigkeit geht auf die Vorschrift selbst und nicht auf die Physik. Der Hauptteil aber ist die Lagerkante — das zeigt die gemessene Ordnung, die deutlich unter zwei liegt. Die Lehre bleibt: Konvergenz ist keine Selbstverständlichkeit — man muss hinsehen, was konvergiert.

13.7 Spannungssingularitäten: wenn Verfeinern nicht hilft

Die Netzkonvergenz hat eine Kehrseite, und sie ist der häufigste Grund, warum ein buntes Bild in die Irre führt.

WarnungFeiner ist nicht immer richtiger

Verbreitete Vermutung: „Je feiner das Netz, desto genauer — irgendwann stimmt es dann.”

Warum sie naheliegt: Für die brave Zonenspannung war es ja gerade so.

Was stattdessen gilt: Verfeinern heilt nur den Diskretisierungsfehler. An gewissen Stellen aber wächst die berechnete Spitzenspannung mit jedem feineren Netz weiter, ohne Grenze, weil das Kontinuumsmodell dort unendliche Spannung vorhersagt — eine Spannungssingularität. Vier Sorten muss man auseinanderhalten. Zwei stecken im Modell dieses Buches selbst, eine dritte baut das Kapitel gleich absichtlich ein, um sie vorzuführen, und die vierte kommt an der Ferse gar nicht vor:

  • Singuläre Lasteinleitung — eine endliche Kraft auf einen Punkt (eine Punktlast): endliche Kraft auf eine Fläche null wäre ein unendlicher Druck. Im Modell dieses Buches kommt sie nicht vor, weil jede Last verteilt aufgebracht wird; der Regler gleich baut sie absichtlich ein.
  • Lagerkantensingularität — das Ende einer harten Einspannung, ein Wechsel der Randbedingung. Sie steckt im Modell: Genau sie ließ oben die Zusammendrückung kriechen — die Kante der Talus-Einspannung.
  • Traktionskantensingularität — das abrupte Ende einer verteilten Last an der Kante der Kontaktfläche. Auch sie steckt im Modell, dort, wo die Auftrittsfläche aufhört.
  • Kerbsingularität — eine geometrische Kerbsingularität: eine einspringende Ecke, eine scharfe Kerbe, eine Rissspitze. Die glatte Fersenkontur hat keine. Dieser vierte Fall kommt an unserem Modell nicht vor; er steht hier nur als der verwandte Begriff.

Jede solche Spitze ist ein Netzartefakt, keine belastbare Zahl. Das heißt aber nicht, dass das ganze Ergebnis verloren wäre — und das ist der Trost, ohne den dieser Kasten unvollständig bliebe. Die Spannung wächst an der Singularität zwar über jede Grenze, aber sie tut es so langsam, dass ihr Mittelwert über eine Fläche endlich bleibt: Die Spitze ist unendlich hoch und zugleich unendlich schmal. Deshalb laufen Verschiebungen und flächengemittelte Spannungen ein, während das punktweise Maximum davonläuft. Genau darum darf die Zonenspannung ins Buch — nicht weil man die Singularität wegdiskutiert, sondern weil die Zone über sie hinwegmittelt.

Und ein Fehler ganz anderer Art — eine falsche Randbedingung, eine verrutschte Einheit — bleibt auf jedem Netz falsch und sieht auf feinen Netzen nur vertrauenswürdiger aus. Genau deshalb ist das Druck-Cluster nahe der Talus-Lagerkante (Vorschau Kapitel 18) mit Vorsicht zu lesen.

Am Regler stellst du zwei Auswertegrößen gegeneinander — dieselbe Bodenkraft, einmal über die Auftrittsfläche verteilt (die flächengewichtete plantare Zonenspannung), einmal auf einen Knoten konzentriert (die Spitzenspannung einer singulären Lasteinleitung). Zwei Dinge vorweg, damit die Zahlen nicht mit denen von eben verwechselt werden: Hier rechnen die Buchnetze live, nicht die Vergleichsrechnung, und die Auswertezone ist eine andere — plantar, mit dem Schwerpunkt unter \(y = 6\) mm, statt im Inneren der Tuber-Region (\(x\,6\)\(26\), \(y\,10\)\(24\) mm). Verglichen werden also zwei Größen miteinander, nicht Zahlen mit Zahlen von oben. Vorher die Vorhersage.

WichtigVorhersage-Punkt

Bevor du schaltest: Dieselbe Bodenkraft, einmal über die Auftrittsfläche verteilt (Zonenspannung), einmal auf einen Knoten konzentriert (Spitzenspannung). Welche der beiden Größen darf ins Buch — welche bleibt über die Netzstufen stabil, welche wächst ohne Grenze? Lege dich fest, dann schalte.

Deutung. Das ist die Antwort: Die flächengewichtete plantare Zonenspannung bleibt über die drei Buchnetze fast konstant (unter 1 %) — sie darf ins Buch. Die verteilte plantare Spitze wächst langsam (rund ×1,3: eine schwache Traktionskanten-Singularität am abrupten Ende der Kontaktfläche), die Punktlast-Spitze vervielfacht sich (rund ×2,7: eine starke singuläre Lasteinleitung). Keine der beiden ist eine geometrische Kerbe — die Fersenkontur ist glatt. Wer „die höchste Spannung” ausliest, bekommt auf jedem Netz eine andere Zahl; deshalb wertet dieses Buch die Zonenspannung aus.

Über alle sieben Stufen der Vergleichsrechnung — feinere Netze, die innere Auswertezone — zeigt sich dasselbe noch schärfer. Hier steht auch die Zahl aus dem Aufhänger dieses Kapitels.

Code
import numpy as np
import matplotlib.pyplot as plt

v = LEITER["verlauf"]
knoten = [s["knoten"] for s in v]
zone = np.array([s["zonen_vm_mpa"] for s in v])
peak = np.array([s["peak_vm_mpa"] for s in v])

fig, ax = plt.subplots(figsize=(7.2, 4.4))
ax.plot(knoten, zone / zone[0], "o-", color="#1f6fb4",
        label="Zonenspannung, innere Zone (läuft ein)")
ax.plot(knoten, peak / peak[0], "s-", color="#c0392b",
        label="Eck-Spitze an der Lagerkante (divergiert)")
ax.axhline(1.0, color="#999", lw=0.8)
ax.set_xlabel("Knoten im Netz")
ax.set_ylabel("Kennzahl bezogen auf ihren Startwert")
ax.xaxis.set_major_formatter(FuncFormatter(lambda x, _p: komma_sig(x, 3)))
ax.yaxis.set_major_formatter(FuncFormatter(lambda y, _p: komma_sig(y, 2)))
ax.legend(fontsize=9); ax.grid(alpha=0.3)
plt.tight_layout()
plt.show()

print("Eck-Spitze grob → fein:", komma_sig(peak[0], 4), "→", komma_sig(peak[-1], 4),
      "MPa  (Faktor", komma_sig(LEITER["konvergiert"]["peak_faktor_grob_fein"], 3)
      + ", divergiert)")
print("Zonenspannung grob → fein:", komma_sig(zone[0], 4), "→",
      komma_sig(zone[-1], 4), "MPa  (läuft ein)")
Abbildung 13.3: Zwei Kennzahlen derselben sieben Netzstufen, beide auf ihren eigenen Startwert bezogen (grobstes Netz = 1). Blau die flächengewichtete Zonenspannung im Inneren der Tuber-Region: sie ändert sich am feinen Ende kaum noch. Rot die Eck-Spitzenspannung an der Kante der Talus-Einspannung (das globale Von-Mises-Maximum): sie steigt von Stufe zu Stufe weiter, ohne Anzeichen einzulaufen — es sind die beiden Zahlen aus dem Aufhänger dieses Kapitels. Die Zonenspannung darf ins Buch, die Eck-Spitze nicht: Sie ist eine Lagerkantensingularität, ein harter Wechsel der Randbedingung, keine geometrische Kerbe. Herkunft: programme/kap13/referenzleiter.json.
Eck-Spitze grob → fein: 52,05 → 164,2 MPa  (Faktor 3,16, divergiert)
Zonenspannung grob → fein: 6,063 → 6,178 MPa  (läuft ein)

Deutung unter der Ausgabe. Zwei Kurven, zwei Schicksale — und damit die Antwort auf die Frage vom Kapitelanfang. Die Zonenspannung flacht ab und findet ihren Wert. Die Eck-Spitze an der Lagerkante steigt mit jeder Stufe weiter, mal um zwölf, mal um zwanzig Megapascal, ohne Anzeichen zu ruhen. Welche der beiden Zahlen aus dem Aufhänger stimmt nun, die kleine oder die große? Keine. Beide sind Zwischenstände einer Folge, die nirgendwohin läuft; wer „die höchste Spannung im Modell” aufschreibt, schreibt in Wahrheit auf, wie fein sein Netz war. Deshalb wertet dieses Buch nicht die Spitze aus, sondern die flächengewichtete Zonenspannung — die Zahl, die ab der dritten Stufe steht.

Wie das Feld beim Verfeinern zugleich glatter wird, während der Fleck an der Lagerkante greller leuchtet, zeigt der Netzstufen-Umschalter — grob, mittel, fein. Drei Zustände will man nebeneinanderhalten, nicht vorbeiziehen sehen: Deshalb schaltest du hier selbst weiter und bleibst stehen, wo du vergleichen willst. Vorher eine Vorhersage.

WichtigVorhersage-Punkt

Bevor du umschaltest: Beim Verfeinern von grob zu fein — beruhigt sich das ganze Feld gleichmäßig, oder glättet sich die Fläche, während ein Fleck an der Talus-Lagerkante immer greller wird? Lege dich fest, dann schalte durch.

Deutung. Das ist die Antwort auf die Vorhersagefrage: Das Feld beruhigt sich mit jedem feineren Netz — die Farbflächen werden glatter, die Zonenspannung steht fest. Der Fleck an der Talus-Lagerkante aber leuchtet mit jedem Schritt greller: dieselbe Lagerkantensingularität wie im Diagramm, jetzt im Bild. Ruhig und divergent zugleich — deshalb genügt es nie, ein einziges buntes Bild anzusehen; man muss wissen, welche Größe man ausliest.

13.8 Die Grenzen der Wächter: drei Modellzustände

Jetzt die Probe aufs Ganze — und zugleich die Grenzen der Werkzeuge. Der folgende Regler schaltet zwischen drei Modellzuständen und prüft jeden mit vier Wächtern. Der erste Zustand ist korrekt. Der zweite baut eine Phantom-Zusatzlast ein — einen beim Aufbau des Kraftvektors vergessenen, stehen gebliebenen Term auf allen Knoten. Der dritte ist der reine Dickenfehler: die Statik ohne den Dickenfaktor gerechnet, also mit einer Scheibe von einem Meter statt von 33 Millimetern — rund 30-fach zu steif. Ein vergessener Faktor dieser Art ist der unauffälligste Fehler, den eine Rechnung haben kann: Er ändert nichts an der Form des Ergebnisses, nur an seiner Größe, und Größe sieht man einem Farbbild nicht an.

Die vier Wächter sind Nulltest, internes Gleichgewicht, Soll-Last-Abgleich und ein Referenz-/Einheitentest: eine berechnete Größe — hier die Zusammendrückung der Auftrittsfläche — gegen einen Wert gehalten, der von außen kommt. Was darf ein solcher Referenzwert sein? Eine von Hand gerechnete Lösung desselben Problems, das Ergebnis eines anderen Programms, ein veröffentlichter Prüffall, eine Messung. Was er nicht sein darf, ist dieselbe Rechnung noch einmal: Ein Modell, das man gegen sich selbst hält, besteht jede Prüfung. Im Regler hier gibt das korrekte Modell den Referenzwert ab — als Vorführung, damit man den Ausschlag des Wächters sieht. Ein Prüfmittel ist das nicht; es zeigt nur, was ein Prüfmittel täte.

WichtigVorhersage-Punkt

Bevor du schaltest: Zwei verschiedene Fehler werden eingebaut. Erkennst du sie am bunten Spannungsbild allein? Und fängt jeden Fehler derselbe Wächter — oder braucht man verschiedene? Lege dich fest, dann schalte durch.

Welcher Wächter welchen Fehler fängt, fasst diese Tabelle zusammen (die Zeilen entsprechen den drei Reglerstellungen):

Modellzustand Nulltest internes Gleichgewicht Soll-Last-Abgleich Referenz-/Einheitentest
korrekt 0 ≈ 0 erfüllt erfüllt
Phantom-Zusatzlast ≠ 0 ≈ 0 verletzt verletzt
reiner Dickenfehler 0 ≈ 0 erfüllt verletzt

Deutung. Das ist die Antwort auf die Vorhersagefrage. Das bunte Bild bleibt in allen drei Fällen fast unverändert — beim Dickenfehler nur, weil die Software es auf sein eigenes Maximum umskaliert; am Bild allein ist kein Fehler zu erkennen. Und nein, es fängt nicht ein Wächter alles: Der Phantom-Fehler verrät sich am Nulltest (bei null Last bleibt Spannung stehen) und am Soll-Last-Abgleich (die Reaktion trägt mehr als die bekannte Last, in Kraft und Moment). Der Dickenfehler dagegen besteht Nulltest, internes Gleichgewicht und Soll-Last-Abgleich — die Kraft wiegt sich korrekt aus, nur die Verschiebung ist um den Faktor 30 zu klein; ihn fängt allein der Referenz-/Einheitentest. Wichtig auch: Das interne Gleichgewicht (Last gleich Reaktion) ist bei keinem der drei Fälle verletzt — es prüft nur, dass der Löser konsistent rechnet, nicht ob Last und Einheiten stimmen. Deshalb genügen zwei Wächter nie; man braucht Prüffälle, eine Bilanz gegen die bekannte Last und eine Referenz. Ein Spannungsbild ist ein Ergebnis, kein Beweis.

Editierbare Zelle. Der folgende Block ist zum Selbstprobieren: Er rechnet das Handnetz noch einmal von Grund auf und zeigt zwei Bilder untereinander.

Oben die drei Modellzustände als gerechnete Wächter-Tafel: dieselbe Tabelle wie oben, nur nicht behauptet, sondern für jeden Zustand ausgerechnet. Jedes Feld trägt seine Zahl, und man sieht auf einen Blick, welcher Wächter welchen Fehler bemerkt — und welcher bei allen dreien schweigt.

Darunter die Gerade: wie die Abweichung des Soll-Last-Abgleichs mit dem Phantom-Term wächst, mit den ausgewählten Werten als Punkte darauf. Verändere die Liste phantom_werte oder den Wert dicken_fehler und führe die Zelle aus; Tafel und Punkte wandern mit. Die Frage, die sich damit beantworten lässt: Wie klein darf ein vergessener Term sein, damit der Soll-Last-Abgleich ihn gerade noch meldet? Wer den Block überspringt, verliert keinen Gedanken — die Aussage steht schon in der Wächter-Tabelle oben.

Deutung. Das Bild sagt dasselbe wie der Regler, nur zum Anfassen: Bei null Phantom-Term sitzt der Punkt auf der Nulllinie — der Soll-Last-Abgleich stimmt (die Abweichung ist ein bloßer Rundungsrest). Jeder stehen gebliebene Restbeitrag hebt ihn davon ab, und zwar geradlinig: Doppelter Phantom-Term, doppelte Abweichung. Genau diesen Fehler verschweigt das bunte Bild, und genau ihn fängt der Soll-Last-Abgleich.

13.9 Die andere Hälfte: drei Zahlen für einen Druck

Alle drei Werkzeuge dieses Kapitels — Prüffall, Bilanz, Konvergenz — gehören auf die Verifikationsseite. Sie fragen, ob das Programm rechnet, was das Modell sagt. Wie schwer die andere Seite ist, zeigt ein Blick auf eine einzige Größe, die jeder zu kennen glaubt: den Druck unter der Ferse. Wer nachschlägt, findet drei Zahlen — alle aus seriösen Quellen, alle verschieden. Sie sind, das sei vorausgeschickt, Drücke unter der Sohle, gemessen zwischen Fuß und Schuh, und nicht die inneren Spannungen im Knochen, um die es sonst in diesem Kapitel geht.

Die erste ist 188 kPa (regionaler Fersen-Spitzendruck beim Laufen, im Schuh gemessen an 20 gesunden Erwachsenen, Burnfield und andere 2007). Die zweite sind 509 bis 912 kPa (ebenfalls plantarer Fersen-Spitzendruck, aber aus einer Finite-Elemente-Schuhstudie: Yang und andere 2022 rechnen 18 Schuhdesign-Varianten eines 3D-Fuß-Schuh-Modells für einen Probanden bei einer Bodenreaktion von 1149 N). Die dritte sind rund 711 bis 1067 kPa — kein Messwert, sondern ein abgeleiteter mittlerer Druck: der Stützwert \(1{,}45 \cdot\) KG des Kräftefahrplans (Tabelle 2.2), verteilt über eine Fersenfläche von 10 bis 15 cm². Welche stimmt? Vom Ansehen: keine Antwort. Abbildung 13.4 stellt die drei als Balken nebeneinander, jede mit ihrer Definition und ihrem Protokoll.

Code
import numpy as np
import matplotlib.pyplot as plt

# Der mittlere Druck ist ABGELEITET: Stützwert 1,45 · KG über 10–15 cm².
KG = 736.0
kraft_aufprall = 1.45 * KG                     # N (Zahlenkanon: Stützwert)
flaeche = np.array([15.0, 10.0]) * 1e-4        # m² (10–15 cm²)
mittel_kpa = kraft_aufprall / flaeche / 1e3    # -> 711 … 1067 kPa

fig, ax = plt.subplots(figsize=(7.2, 4.2))
namen = ["gemessener\nSpitzendruck\n(im Schuh, Burnfield 2007)",
         "abgeleiteter\nmittlerer Druck\n(1,45 · KG / 10–15 cm²)",
         "FE-Spitzendruck\n(Yang 2022, Spanne)"]
tief = [188, mittel_kpa[0], 509]
hoch = [188, mittel_kpa[1], 912]
farben = ["#1f6fb4", "#e08a1e", "#2a7d2a"]
for i in range(3):
    if hoch[i] > tief[i]:
        ax.bar(i, hoch[i] - tief[i], bottom=tief[i], color=farben[i], width=0.6,
               alpha=0.85)
        ax.text(i, hoch[i] + 20, komma_sig(tief[i], 3) + "–"
                + komma_sig(hoch[i], 3) + " kPa", ha="center", fontsize=9)
    else:
        ax.bar(i, tief[i], color=farben[i], width=0.6, alpha=0.85)
        ax.text(i, tief[i] + 20, komma_sig(tief[i], 3) + " kPa", ha="center",
                fontsize=9)
ax.set_xticks(range(3))
ax.set_xticklabels(namen, fontsize=8)
ax.set_ylabel("Druck (kPa)")
ax.set_ylim(0, 1150)                            # Nullachse (kein Abschneiden)
ax.yaxis.set_major_formatter(FuncFormatter(lambda v, _p: komma_sig(v, 3)))
ax.grid(axis="y", alpha=0.3)
plt.tight_layout()
plt.show()

print("Abgeleiteter mittlerer Druck: 1,45 · KG =", komma(kraft_aufprall, 0),
      "N über 10–15 cm² →", komma_sig(mittel_kpa[1], 3), "bis",
      komma_sig(mittel_kpa[0], 3), "kPa")
Abbildung 13.4: Drei Zahlen für „den Druck unter der Ferse“, jede mit ihrer Definition und ihrem Protokoll, beides im Zahlenanhang belegt. Links und rechts sind BEIDE der plantare Fersen-Spitzendruck, nur unter nicht vergleichbaren Protokollen bestimmt: links im Schuh gemessen (188 kPa, regional, 20 Erwachsene beim Laufen, Burnfield 2007), rechts aus einer FE-Schuhstudie (509–912 kPa Spanne über 18 Schuhvarianten, ein Proband, Bodenreaktion 1149 N, „peak plantar heel pressure“, Yang 2022). Mitte der davon getrennt abgeleitete mittlere Druck (der Stützwert 1,45 · KG = 1067 N des Kräftefahrplans, geteilt durch 10–15 cm² Fersenfläche — ein hypothetischer Rechenwert, kein Messwert, hier als Balken der Spanne). Die Balken sind Drücke (kPa), keine inneren Spannungen. Kein unmittelbarer Widerspruch: zwei Spitzendruckbestimmungen unter verschiedenen Protokollen plus ein abgeleiteter Mitteldruck.
Abgeleiteter mittlerer Druck: 1,45 · KG = 1067 N über 10–15 cm² → 1067,2 bis 711 kPa

Deutung unter der Ausgabe. Der scheinbare Widerspruch löst sich, sobald man Protokoll und Definition dazunimmt. Der Spitzendruck von 188 kPa ist der höchste Wert einer kleinen Sensorregion im Schuh, gemessen beim Laufen — nicht über die Ferse gemittelt und nicht zeitgleich zur Gesamt-Bodenreaktion erhoben. Die 509 bis 912 kPa sind dieselbe Art Größe — auch ein plantarer Fersen-Spitzendruck —, nur aus einem ganz anderen Protokoll: eine FE-Schuhstudie über 18 Sohlenvarianten für einen einzigen Probanden bei einer Bodenreaktion von 1149 N. Zwei Spitzendruckbestimmungen unter nicht vergleichbaren Bedingungen dürfen verschieden ausfallen. Der mittlere Druck (rund 711 bis 1067 kPa) ist wieder etwas anderes: die ganze Kraft über die ganze Fersenfläche, ein abgeleiteter Rechenwert, kein Messwert. Zwei Spitzendruckbestimmungen unter verschiedenen Protokollen plus ein abgeleiteter Mitteldruck — kein unmittelbarer Widerspruch. Der Merksatz des Kapitels: Bunt ist kein Beweis, und eine Zahl ohne Definition und Protokoll ist keine Zahl. Genau deshalb nennt dieses Buch jede Größe beim Namen — Kraft, Druck, Spannung sind nicht dasselbe.

Und damit steht auch da, warum die rechte Spalte des Kastens vom Kapitelanfang leer bleibt. Wer das Modell dieses Buches gegen eine Messung halten wollte, bräuchte eine Messung derselben Größe, am selben Ort, unter demselben Protokoll — für die inneren Spannungen in einem lebenden Fersenbein gibt es sie nicht. Die drei Zahlen oben zeigen, wie viel Arbeit schon in der Frage steckt, welche Messung überhaupt zu welchem Modellwert gehört. Verifikation kann dieses Buch vorführen. Validierung kann es nur benennen.

Übungen

Ü 13.1 (Verstehen). Ordne die drei Druckzahlen (188 kPa; 509–912 kPa; 711–1067 kPa) ihren Definitionen und Protokollen zu und sage in einem Satz, warum sie einander nicht unmittelbar widersprechen.

188 kPa und 509–912 kPa sind beide der plantare Fersen-Spitzendruck — nur unter ganz verschiedenen Protokollen: 188 kPa im Schuh an 20 Erwachsenen beim Laufen gemessen (Burnfield 2007), 509–912 kPa aus einer FE-Schuhstudie über 18 Sohlenvarianten für einen Probanden bei 1149 N Bodenreaktion (Yang 2022). Nur 711–1067 kPa ist eine andere Größe: der abgeleitete mittlere Druck, der ganze Stützwert 1,45 · KG über die ganze Fersenfläche (10–15 cm²), ein Rechenwert. Kein unmittelbarer Widerspruch — es sind zwei Spitzendruckbestimmungen unter nicht vergleichbaren Protokollen plus ein davon getrennt abgeleiteter Mitteldruck.

Ü 13.2 (Verändern). Öffne den Netzfeinheit-Regler und protokolliere die Zonenspannung und die Zusammendrückung für die sieben Stufen. Finde die Stufe, ab der sich die Zonenspannung um unter 0,5 % ändert — und prüfe, ob die Zusammendrückung dieselbe Schranke erreicht. Sage vorher, welche zuerst einläuft.

Die Zonenspannung unterschreitet die 0,5-%-Schranke ab Stufe 3 (2188 Knoten): Die Änderung von Stufe 2 auf Stufe 3 beträgt 0,4289 %, und danach bleiben alle weiteren Zonenänderungen unter der Schranke — zwischen den zwei feinsten Netzen nur noch 0,156 %. Die Zusammendrückung dagegen bleibt bei 0,724 % über der Schranke: Sie kriecht weiter, weil die Kante der Talus-Einspannung eine Lagerkantensingularität in die Antwort trägt; die beobachtete Ordnung ist mit 1,27 deutlich kleiner als die zwei, die Kapitel 9 am glatten Zugstab gefunden hat. Die Lehre: Zwei Kennzahlen desselben Modells können ganz verschieden konvergieren — man muss hinsehen, welche man auswertet, und die Richardson-Extrapolation nutzen, wenn eine kriecht.

Ü 13.3 (Übertragen). Schalte den Modellzustand-Regler durch alle drei Stellungen. Sage für die Phantom-Zusatzlast und den reinen Dickenfehler getrennt, welcher der vier Wächter anschlägt und welcher nicht — und warum das bunte Spannungsbild bei keinem hilft.

Die Phantom-Zusatzlast verrät sich am Nulltest (bei null Last bleibt Spannung stehen, die nur ein Fehler sein kann) und am Soll-Last-Abgleich (die Reaktion trägt mehr als die bekannte Soll-Last, in Kraft und Moment). Der reine Dickenfehler besteht Nulltest, internes Gleichgewicht und Soll-Last-Abgleich — die Kraft wiegt sich korrekt aus, nur die Verschiebung ist um den Faktor 30 zu klein; ihn fängt allein der Referenz-/Einheitentest (die Zusammendrückung weicht um rund 97 % vom Referenzwert ab). Das interne Gleichgewicht schlägt bei keinem an — es prüft nur, ob der Löser konsistent rechnet. Das bunte Bild schweigt in beiden Fällen (der Dickenfehler nur, weil die Software auf sein eigenes Maximum umskaliert). Lehre: kein einzelner Wächter fängt alles; man braucht Prüffälle, eine Bilanz gegen die bekannte Last und eine Referenz. Ein Spannungsbild ist ein Ergebnis, kein Beweis.

Roter Faden

Wo kam das schon vor, wo kommt es wieder? Zurück: Der Nulltest ist die Linearität aus Kapitel 5 (\(K\,0 = 0\)), jetzt als Prüfwerkzeug; die Bilanzkontrolle setzt die Lagerreaktion aus Kapitel 12 fort und macht sie zum Dauer-Wächter; die Konvergenz-Vorschau aus Kapitel 7 und die Punktkraft-Spitze aus Kapitel 12 werden hier eingelöst; das Netz aus Kapitel 10 bekommt seine Konvergenzstudie; und die Ordnung zwei, die Kapitel 9 am glatten Zugstab als Bestfall gemessen hat, bekommt hier ihr Gegenstück am Fersenmodell — eine kleinere Ordnung, weil die Lagerkante die Lösung unglatt macht. Vor: Die flächengewichtete Zonenspannung ist ab Teil V die belastbare Auswertegröße (Kapitel 15); die Lagerkantensingularität und die Lagernähe kehren beim Druck-Sporn in Kapitel 18 als Deutungshinweis wieder; die Bilanzkontrolle läuft in jeder Umbau-Iteration mit (Kapitel 17). Der bekannte Ausweg für die Lagerkanten-Singularität — die harte Talus-Einspannung durch eine elastische Bettung (Gelenkknorpel) ersetzen (benannt in Kapitel 12) — bleibt hier ein Ausblick: benannt, nicht gerechnet.

Teil IV abgeschlossen — die Studiums-Tabelle

Damit schließt Teil IV. Die Studiums-Tabelle im Vorwort hat für diesen Teil drei Zeilen vorgesehen; hier werden sie abgehakt.

Im Buch als … Im Studium heißt es … eingelöst
Netz aus Dreiecken Diskretisierung, Ansatzfunktionen Kapitel 10 ✓, von Hand gerechnet in Kapitel 11 ✓
festhalten, ziehen, betten — was am Rand vorgegeben wird Randbedingungen: Dirichlet, Neumann, Robin Kapitel 12 ✓
„das Netz war zu grob“ Konvergenzstudie, Diskretisierungsfehler Kapitel 13 ✓

Teil V baut darauf auf: Aus dem geprüften Modell wird die Belastung eines Schrittes — fünf gewichtete Lastfälle, und die flächengewichtete Zonenspannung ist die Größe, die man dabei ausliest.

Was dieses Kapitel NICHT tut

Es entwickelt keine Fehlerabschätzungs-Theorie — keine Fehlernormen, keine Ordnungsbeweise; die beobachtete Konvergenzordnung und die Richardson-Extrapolation stammen aus der numerisch geprüften Vergleichsrechnung, die sieben Netzstufen außerhalb des Browsers durchgerechnet hat; hergeleitet werden sie hier nicht. Es betreibt keine Validierung gegen unabhängige experimentelle Messdaten (das bleibt Ausblick; die drei Druckzahlen am Ende stammen aus der Literatur und aus dem Zahlenanhang, nicht aus einer eigenen Messung). Es rechnet keine Bruchmechanik — die Spannungssingularitäten werden nur als Konvergenz-Phänomen gezeigt, nicht als Rissmodell; eine geometrische Kerbe kommt an der glatten Fersenkontur ohnehin nicht vor. Es nutzt keine adaptiven Netze (nur benannt). Die sieben Netzstufen sind außerhalb des Browsers vorberechnet und werden hier nicht neu gerechnet; die Buchnetz-Regler zeigen dasselbe Verhalten, aber an einer gröberen Rechnung — ihre Zahlen sind nicht die der Vergleichsrechnung, wie Tabelle 13.3 festhält. Die gezeigten Spannungen sind Modellwerte der Buchnetze, keine klinische Aussage. Nur die drei Prüffragen und ihre Werkzeuge an der Ferse — mehr will dieses Kapitel nicht.