Schwierigkeiten beim Auffinden von Fehlern in wissenschaftlichen Anwendungen

    Dies ist eine Fortsetzung des Hinweises, warum Komponententests in wissenschaftlichen Anwendungen nicht gut funktionieren. und in diesem Artikel möchte ich über die Schwierigkeiten beim Auffinden von Fehlern und beim Debuggen (wissenschaftliche Anwendungen) sprechen, auf die ich in meiner Zeit gestoßen bin und von denen viele für mich als Webentwickler erstaunlich waren.


    Der Artikel wird aus mehreren Abschnitten bestehen:
    1. Einleitung, zur Bestellung
    2. Es ist schwierig, Fehler zu finden
      • Parallelität
      • Nichtlokalität von Fehlern
      • Typo Nicht-Offensichtlichkeit
      • Auswirkung der Einstellung auf das Ergebnis
      • Identifizierung von Fehlern: Fehler oder nicht?

    3. Fazit

    Einleitung


    Der Hauptzweck dieses Artikels ist es, Ihre eigenen Erfahrungen in der Hoffnung zu beschreiben, dass jemand interessiert und ungewöhnlich wird (insbesondere, wie mir scheint, für Industrieprogrammierer); Vielleicht kann sich jemand besser auf das Schreiben von Diplomen / Kursen / Labors vorbereiten. Die Präambel, die Erklärung des wissenschaftlichen Problems, eine kurze Beschreibung des Algorithmus finden Sie in dem genannten Artikel [1]. Ich werde mich daher sofort der Darstellung dieser ungewöhnlichen (zum Beispiel für Webentwickler) Schwierigkeiten bei der Fehlersuche zuwenden, um den Horizont der Leser und des Bewusstseins insgesamt zu erweitern.

    Es ist schwierig, Fehler zu finden


    Parallelität

    Dies ist ein außergewöhnlich kurzer Punkt, um das Bild zu vervollständigen, in dem ich noch einmal erwähnen werde, dass es viel schwieriger ist, in parallelen Programmen nach Fehlern zu suchen und Fehler zu beheben, als in Singlethread-Programmen. Und die meisten ressourcenintensiven wissenschaftlichen Programme verlaufen parallel.

    Nichtlokalität von Fehlern

    Hiermit meine ich, dass sich ein Fehler im Code einer Klasse an völlig unerwarteten Stellen manifestieren kann. Dabei geht es nicht um die schlechte Anwendungsarchitektur und die hohe Konnektivität der Module, sondern um die Funktionen von Aufgaben und Modellierung. Wenn beispielsweise das Geschwindigkeitsprofil bei der Simulation des Flüssigkeitsstroms in einem Rohr in der Nähe der Wände verzerrt ist, bedeutet dies keineswegs, dass der Fehler genau im Algorithmus zur Berechnung der Wände liegt, sondern überall liegen kann. Umgekehrt bedeutet eine merkwürdige Verteilung der Dichte in der Dicke der Flüssigkeit nicht, dass es sich nicht um einen Wandberechnungsalgorithmus handelt.

    Vergleichen Sie dies mit einem typischen Geschäftsanwendungsszenario: Wenn bei der Verarbeitung eines Einkaufs in einem Online-Shop die Rabatte auf Waren nicht korrekt berechnet werden, ist der Fehler mit ziemlicher Sicherheit im Code zur Berechnung der Rabatte auf Waren verborgen.

    Es kann beanstandet werden, dass es einfach ist, die Fehlerquelle aus dem Änderungsverlauf zu ermitteln. Sobald die Anwendung nicht mehr funktioniert, müssen Sie nach dem Fehler im geänderten Code suchen. Dieser Ansatz gilt jedoch nicht für Teile des Programms, die zum ersten Mal hinzugefügt wurden (z. B. beim Hinzufügen von Wärmeübertragung, neuen Randbedingungen usw.), da es keine vorherige Arbeitsversion gibt (Wärmeübertragung, gegebene Randbedingungen usw.).

    Darüber hinaus können Fehler in wissenschaftlichen Anwendungen für eine lange Zeit nicht auftreten. Wenn beispielsweise beim Hinzufügen eines neuen Typs von Randbedingungen der Poiseuille-Fluss [2], der von einer Kraft und nicht von einem Druckgradienten angetrieben wird, plötzlich nicht mehr korrekt modelliert wird, stellt sich möglicherweise heraus, dass es sich nicht um einen neuen Algorithmus für die Randbedingungen handelt, sondern um die Logik der Berücksichtigung externer Kräfte vorher war der fehler nicht kritisch. (Siehe auch den Abschnitt „Langsame Fehleranstiegsrate“ in [1]).

    Typo Nicht-Offensichtlichkeit

    Eines der Probleme wissenschaftlicher Algorithmen ist, dass sie oft nicht offensichtlich sind. Selbst wenn Sie ein Programm mit einer schönen Architektur erstellen, eine spezielle Klasse für den Algorithmus wählen, es gut entwerfen und schreiben, können Sie wahrscheinlich ein paar Probleme nicht vermeiden.

    Erstens sind dies bedeutungslose Variablennamen (da es sich um Hilfsvariablen aus dem ursprünglichen wissenschaftlichen Artikel handelt, die keine semantische Last tragen). Zweitens sind dies nicht offensichtliche Operationen mit Klassenvariablen (da sie auch dem Originalartikel entnommen wurden, der mit Methoden der Dunklen Magie wie der Optimierung der Standardabweichung, der Fredholm-Alternative, der Berechnung der Harmonischen der räumlichen Dichte usw. erhalten wurde).

    Wenn Sie eine Geschäftsanwendung belasten und eine Zeile wie beobachten
    bool categoryIsVisible = categoryIsEnabled || productsCount> 0;
    dann werden Sie sofort einen Tippfehler bemerken, da die Bedingung ein logisches "UND" sein muss.

    Stellen Sie sich aber vor, Sie stießen auf eine Linie (aus einem realen Projekt).
    Double odds = latticeVectorWeight * density * (1,0 + 3,0 * dotProduct + 9,0 / 2,0 * dotProduct * dotProduct - 3,0 / 2,0 * velocitySquare);
    Es ist unwahrscheinlich, dass Sie feststellen, dass Sie irgendwo Plus und Minus vertauscht haben. Übrigens sind hier die Variablennamen aussagekräftig.

    Auswirkung der Einstellung auf das Ergebnis

    In diesem Abschnitt werde ich versuchen zu erklären, dass die Arbeit von wissenschaftlichen Anwendungen (im Vergleich zu Geschäftsanwendungen) viel stärker von den Eingabedaten, den Parametern des Systems und seinem Anfangszustand abhängt, dh von der Einstellung des Systems.

    Die Hauptquellen für die Einstellungsabhängigkeit sind folgende.

    1. Systemparameter wirken sich sehr stark (qualitativ) auf das Ergebnis der Programmarbeit aus, im Gegensatz zu Geschäftsanwendungen, bei denen die Parameter normalerweise nur quantitative Auswirkungen haben (z. B. hängt die Funktionsweise des CMS nicht wesentlich davon ab, ob der Administrator der Seite fünf oder fünf Texte hinzufügt zehn Zeilen)

    2. Ein kleinerer Stabilitätsbereich der Algorithmen gemäß den Eingabedaten. In Geschäftsanwendungen besteht die Haupteinschränkung für Daten in der Abwesenheit von Überlauffehlern (und wer achtet darauf?!). In wissenschaftlichen Algorithmen (einer der Unterschiede besteht darin, mit Mengen höherer Potenzen zu arbeiten) muss man die Stabilität (und danach die Starrheit von Differentialgleichungen, Stabilitätstheorie, Lyapunov-Exponenten usw.) abrufen und überwachen. Darüber hinaus sind in Geschäftsanwendungen alle Einschränkungen festgelegt (ein Name darf bei der Registrierung nicht länger als 100 Zeichen sein, eine E-Mail muss einem bestimmten regulären Ausdruck entsprechen). Bei wissenschaftlichen Problemen müssen Sie jedoch häufig den Arbeitsbereich der Eingabedaten durch Ausprobieren ermitteln.

    3. Alles andere (für mich bisher schwer zu formalisieren). Insbesondere ist es die Umwandlung von Maßeinheiten von physischen in Maßeinheiten für ein Programm.

    Um diese Aspekte zu veranschaulichen, zeige ich eine Checkliste, die ich nach wochenlangem erfolglosen Debugging einer Anwendung zur Modellierung der Hydrodynamik für mich selbst zusammengestellt habe. Wenn ich den Fehler in ein paar Stunden / Tagen der schrittweisen Ausführung nicht finden konnte, habe ich dies anhand dieser Checkliste überprüft.

    Achtung! Es ist etwas weit vom Thema Habr und den Interessen der meisten Leser entfernt, sodass Sie es überspringen können, wenn Sie dies wünschen, und zum nächsten Absatz übergehen können.
    Also Checkliste:
    1. Überprüfen Sie die Inkomprimierbarkeit
    2. Überprüfen Sie Reynolds Zahlen
    3. Überprüfen Sie die Übersetzung

    Der erste Punkt bedeutet, dass der Algorithmus nur in einem schwach komprimierbaren Fluid arbeitet, was seinen niedrigen Geschwindigkeiten entspricht (viel weniger als die Schallgeschwindigkeit in einem Fluid) (da der Fluss durch einen Dichtegradienten induziert wird). Als ich diese Einschränkung zum ersten Mal vergaß, suchte ich mehrere Tage lang nach Fehlern im Code, da das Programm von außen fast korrekt funktionierte.

    Der zweite Punkt entspricht der Überprüfung des Stabilitätsbereichs des Algorithmus. Tatsache ist, dass die Reynoldszahl bestimmt, wie turbulent und instabil die Flüssigkeitsbewegung ist [3]. Je größer es ist, desto instabiler ist die Strömung, desto kleiner ist die "Viskosität". Es stellt sich heraus, dass selbst wenn die Bewegung niemals physisch turbulent ist (wieder in der Poiseuille-Strömung), die Berechnungen bei ausreichend großen Reynolds-Zahlen zu divergieren beginnen. Bis ich auf diesen Rechen getreten bin (und ihn eine Woche lang nicht mochte), habe ich natürlich nicht daran gedacht, den Stabilitätsbereich zu verfolgen.

    Der dritte Punkt ist nur für physikalische Berechnungen und einige Algorithmen spezifisch. Das verwendete Verfahren verwendet physikalische Eingangsgrößen in speziellen Einheiten des Gitters (wenn die Längeneinheit die Stufe des gleichförmigen räumlichen Gitters ist und die Zeiteinheit proportional dazu ist). Bis ich auf einen speziellen Artikel [4] stieß, der sich mit der Übersetzung von Mengen bei dieser Methode befasste, versuchte ich einige Wochen lang erfolglos zu verstehen, warum sich das Programm nicht richtig verhielt.

    Es ist anzumerken, dass der zweite und dritte Absatz kaum eine automatische Überprüfung zulassen.

    Identifizierung von Fehlern: Fehler oder nicht?

    Dieses Problem ist in Geschäftsanwendungen völlig unvorstellbar. und es besteht darin, dass es oft unmöglich ist, sicher zu sagen, ob eine Abweichung im Verhalten des Programms (vom erwarteten) ein Fehler ist.

    Beispielsweise ist bekannt, dass das Geschwindigkeitsprofil während des Fließens eines viskosen Fluids durch ein zylindrisches Rohr parabolisch ist [2]. Nehmen wir jedoch an, dass die Flüssigkeit bei der Simulation an den Rohrwänden etwas schneller fließt, als sie sollte. Optionen, die häufig in Betracht gezogen werden, sind:
    1. das ist eigentlich ein fehler
    2. Dies ist ein Merkmal des Algorithmus
    3. Dies ist eine Folge falscher oder unangemessener Eingabedaten für den Algorithmus (Anfangsbedingungen, physikalische Parameter) (siehe „Auswirkung der Einstellung auf das Ergebnis“).

    Die Überprüfung durch Komponententests des ersten Punkts wird durch die Schwierigkeiten beim Schreiben von Komponententests in solchen Anwendungen erschwert [1].

    Das zweite Element in diesem Beispiel lässt sich leicht überprüfen, indem der Wandberechnungsalgorithmus ersetzt wird. Es kann sich jedoch herausstellen, dass die Modellierung mit der neuen Methode auch zu verzerrten Ergebnissen führt. In diesem Fall können Sie einige weitere Algorithmen ausprobieren (sofern diese im Prinzip verfügbar sind und Sie Zeit zum Suchen, Zerlegen und Implementieren haben).

    Das Überprüfen des dritten Absatzes ist leider alles andere als trivial. Eine Möglichkeit besteht darin, die Eingabeparameter und die Systemeinstellung zu ändern, um festzustellen, ob der Phasenraum der ursprünglichen Daten, in denen das Programm arbeitet, einen Bereich enthält. Dies ist leider nicht so einfach, da die Anzahl der Freiheitsgrade unter den Anfangsbedingungen während der komplexen Modellierung sehr groß ist (Sie können verschiedene physikalische Parameter wie Viskosität und Wärmeleitfähigkeit einstellen; die Anfangsverteilung von Geschwindigkeiten, Kräften, Dichten im gesamten System usw.). . Bei einem Test mit Flüssigkeit, die durch ein Rohr fließt, habe ich zum Beispiel mehrere Tage gebraucht, um zu versuchen, die Modellierung nicht mit einer stationären Geschwindigkeitsverteilung, sondern mit einer stationären Flüssigkeit zu beginnen, die anschließend mit konstanter Kraft beschleunigt wurde - und der Fehler verschwand!

    Fazit


    Hier in der Tat alle Schwierigkeiten, Fehler zu finden, über die ich sprechen wollte. Wenn jemand darüber nachdenkt, wie er solche Auswirkungen vermeiden oder effektiv damit umgehen kann, würde ich mich freuen, sie zu hören.

    Danke fürs Lesen!

    Referenzen:

    [1] Warum Unit-Tests in wissenschaftlichen Anwendungen nicht funktionieren
    [2] Poiseuille-Flow
    [3] Reynolds-Zahl
    [4] Umrechnung von Mengen in LBM

    Jetzt auch beliebt: