Simulation ist mehr als Software

Kostenlose Testversion
0
Wunschliste
0 0
Warenkorb

Direktkontakt
DE

Tech Article | 23/07

Python-Scripting in Ansys Discovery – Nur was für Nerds?

Kennen Sie das? Sie bearbeiten Ihre Geometrie in Ansys Discovery und wiederholen dabei immer wieder die gleiche Abfolge an Operationen. Ganz schön nervig, oder? Wäre es nicht schön, wenn eine Automatisierung solche Aufgaben erledigen könnte? Ich zeige Ihnen in Form einer Klickanleitung, wie Sie den Einstieg ins Scripting in Ansys Discovery finden können und Sie entscheiden am Ende selbst, wie hoch der Nerdfaktor für Sie ist.

Von der Idee zum ersten Pythonskript

Wenn wir an Programmierung denken, kommen uns Bilder von haufenweise Codezeilen auf dem Bildschirm in den Kopf. Gerade wenn man bisher wenig Berührungspunkte mit Python oder einer beliebigen anderen Programmiersprache hatte, können die Hürden groß sein, überhaupt mit der ersten Codezeile anzufangen. Mit diesem Artikel möchte ich Sie durch den Entstehungsprozess eines Pythonskriptes für die Geometrieerstellung führen und würde mich freuen, wenn Sie es beim Lesen des Artikels direkt in Ansys Discovery ausprobieren.

Stellen wir uns vor, wir hätten einen Hydraulikzylinder mit Tellerfedern zu befüllen. Der Bauraum ist vorgegeben und die beste Konfiguration aus Anzahl, Anordnung und Dicke der Federn soll simulativ ermittelt werden. Da sehr viele verschiedene Designs durchgerechnet werden sollen, ist es viel zu aufwendig, jedes Federpaket manuell neu zu erstellen. Der erste Schritt bei der automatisierten Geometrieerstellung ist immer, sich Gedanken darüber zu machen, wie wir manuell in der Software vorgehen würden. Wir würden eine Tellerfeder zeichnen, dann eine zweite mit neuem Mittelpunkt, diese eventuell auf den Kopf drehen, und mit mehrfacher Wiederholung so das Federpaket zusammenstellen. Diese Schritte werden wir nun programmatisch umsetzen.

Welches Pythonwissen brauche ich für das Scripting in Discovery? Für den Anfang reichen die absoluten Grundlagen:

  • For-Schleifen
  • If-Anweisungen
  • Listen

Wer noch weiß, was eine Funktion ist, kann seinen Code besser strukturieren. Dass es sich hierbei um IronPython 2.7 handelt, ist zunächst nur eine Randbemerkung wert, da sich die verschiedenen Pythonvarianten in den Grundlagen kaum unterscheiden.

disc spring construction discovery

Der Skripteditor in Discovery

Für das Scripting in Discovery benötigen wir den Skripteditor, der standardmäßig mitinstalliert wird. Gehen Sie dazu in das Hauptmenü von Discovery und öffnen Sie den Skripteditor. Der Skripteditor ist in zwei Bereiche unterteilt. Im oberen Bereich wird das Skript geschrieben, im unteren Bereich befindet sich die Konsole. Die Konsole gibt uns Feedback zu unserem Skript. Das können Ausgabewerte, aber auch Fehlermeldungen sein.

Für eine erste Fingerübung geben wir in den Skriptbereich einen print-Befehl ein:

print("Hello World!")

Spielen wir das Skript über das grüne Dreieck in der oberen rechten Ecke ab, so erscheint unser Text als Ausgabe in der Konsole.

Der Aufnahmebutton des Skripteditors – dein Freund und Helfer

Jetzt wollen wir unsere erste Tellerfeder vom Skript konstruieren lassen. Fassen wir kurz zusammen, wie wir manuell vorgehen würden. Wir würden

  1. in den Skizziermodus wechseln
  2. ein Parallelogramm zeichnen
  3. in den Solid-Modus wechseln
  4. über das Pull-Tool die entstandene Fläche um 360° rotieren

Beim Öffnen des Skripteditors ist der Aufnahmebutton bereits aktiviert. Nun fangen wir an, die Tellerfeder zu zeichnen und beobachten, was der Skripteditor aufnimmt. Der Wechsel vom Solidmodus in den Skizziermodus ist noch gut lesbar:

sectionPlane = Plane.PlaneXY
result = ViewHelper.SetSketchPlane(sectionPlane, None)

Wir nehmen die XY-Ebene und setzen darauf unsere Skizzierebene. Fangen wir an das Parallelogramm zu zeichnen, dann sieht das Skript auf den ersten Blick recht wild aus, da auch alle automatisch generierten Constraints mit aufgezeichnet werden. Die Constraints können wir aber ausschalten und wir erhalten ein gut lesbares Skript. Es werden zwei Punkte erstellt und zu einer Linie verbunden. Das Ganze wiederholt sich viermal.

start = Point2D.Create(MM(10), MM(10))
end = Point2D.Create(MM(10), MM(6))
result = SketchLine.Create(start, end)

Der Skripteditor arbeitet in SI-Einheiten. Um uns Umrechnungen zu ersparen, können wir die richtige Einheit direkt im Skript angeben. Im nächsten Schritt wechseln wir zurück in den Solidmodus.

mode = InteractionMode.Solid
result = ViewHelper.SetViewMode(mode, None)

Danach bekommt die Tellerfeder über die Pullfunktion ihr endgültiges Design. Auf die ersten drei Zeilen des Codeschnipsels gehen wir im nächsten Abschnitt noch etwas genauer ein.

selection = Face1
axisSelection = Axis1
axis = RevolveFaces.GetAxisFromSelection(selection, axisSelection)
options = RevolveFaceOptions()
options.ExtrudeType = ExtrudeType.Cut
result = RevolveFaces.Execute(selection, axis, DEG(360), options)

Das Einzige, was noch fehlt, ist ganz an den Anfang des Skriptes einen Befehl zu setzen, um die Graphik zu bereinigen. Dann startet das Skript immer mit einer leeren Discoveryoberfläche.

ClearAll()

Das Gute ist, dass wir die meisten dieser Befehle nicht auswendig lernen oder nachschlagen müssen, sondern der Skripteditor über die Aufzeichnenfunktion uns fast alle Befehle liefert und wir davon ausgehend unsere Skripte entwickeln können. Aber es empfiehlt sich immer, das Aufgezeichnete nochmal genauer zu betrachten und aufzuräumen.

Refaktorisierung des Skriptes – mit dem Besen durch den Code

Als Refaktorisierung wird in der Software-Entwicklung das Bereinigen und Sortieren von Quellcode bezeichnet, um die Lesbarkeit und Wartbarkeit von Code zu erhöhen. Ich möchte Ihnen das Vorgehen an unserem Beispiel zeigen. Im Skizziermodus werden Punkte erstellt, um Linien zu zeichnen. Hier ist es sinnvoll, die Point2D Definitionen zu bündeln und über Variablen für die Abmessungen flexibler zu gestalten. Damit sieht das Skript für den Skizzierteil schon übersichtlicher aus:

D = MM(10)
D1 = MM(20)
H = MM(1)
H1 = MM(2)

ClearAll()
sectionPlane = Plane.PlaneXY
result = ViewHelper.SetSketchPlane(sectionPlane, None)

point1 = Point2D.Create(D/2, H1)
point2 = Point2D.Create(D1/2, H1-H)
point3 = Point2D.Create(D1/2, 0)
point4 = Point2D.Create(D/2, H)

result = SketchLine.Create(point1, point2)
result = SketchLine.Create(point2, point3)
result = SketchLine.Create(point3, point4)
result = SketchLine.Create(point4, point1)

Der zweite Teil des Skriptes behandelt die Pulloperation. Dafür benötigen wir die Fläche, die beim Wechsel in den Solidmodus aus den vier Linien entsteht. Zum einen können wir über die Smartvariablen auf die Fläche zugreifen (das sind die magentafarbenen Variablen im Skript). Zum anderen könnten wir die Selektion über die Position im Strukturbaum definieren, indem wir die Liste der Körper und davon die Liste der Faces durchgehen. Da Python immer bei null anfängt zu zählen, ist der erste Körper im Strukturbaum auf Listenplatz 0. GetRootPart() ist immer die oberste Ebene im Strukturbaum:

face_selection = FaceSelection.Create(GetRootPart().Bodies[0].Faces[0]

Die indexbasierte Selektion zeigt zwar im Gegensatz zu den Smartvariablen transparent im Skript, wo man sich gerade im Strukturbaum befindet, ist aber instabil gegenüber Änderungen des Strukturbaums, wenn Körper hinzukommen oder gelöscht werden. Dann ändert sich unter Umständen der Index. Es gibt noch eine dritte Variante, um auf Objekte zuzugreifen, die meines Erachtens die stabilste Variante ist. Bei aufgezeichneten Skripten steht sehr oft „result = “ vor den Befehlen und diese result-Variablen sind keine toten Variablen, sondern enthalten oft nützliche Informationen, die wir weiterverwenden können. In unserem Fall können wir aus dem Wechsel in den Solidmodus direkt die entstandene Fläche mitnehmen.

mode = InteractionMode.Solid
result= ViewHelper.SetViewMode(mode, None)
body =result.CreatedBodies[0]

Die Pulloperation benötigt noch die Drehachse. Im aufgezeichneten Skript wird zunächst die Achse selektiert, um dann aus dieser Selektion wiederum die geometrische Achse abzuleiten. Das kriegen wir auch direkter hin. Wenn wir mit der Maus über das Execute des RevolveFaces.Execute rüberfahren, sehen wir, dass als axis eine „Line“ erwartet wird. Sehr häufig kann man auf gut Glück „Line.Create(“ in den Skripteditor eintippen und wird dann von den Hinweistexten der Autovervollständigung geleitet.

selection = FaceSelection.Create(body.Faces[0])
axis = Line.Create(Point.Origin, Direction.DirY)
options = RevolveFaceOptions()
options.ExtrudeType = ExtrudeType.Cut
result = RevolveFaces.Execute(selection, axis, DEG(360), options)

Mit for-Schleifen zum Hochstapler werden

Wir hatten uns vorgenommen, mit dem Skript mehrere Tellerfedern übereinander zu stapeln. Eine Einzelne kann ja jeder, dafür brauchen wir kein Skript. Die Tellerfedern sollen auf der gleichen Achse liegen, lediglich die Höhe soll variieren. Wenn wir n Federn übereinanderstapeln, dann hat die i-te Feder die Höhe x +i*H1.

Am besten ist es, wenn wir die Federerstellung in eine Funktion schreiben. Funktionen in Python sind dadurch gekennzeichnet, dass sie mit def beginnen, gefolgt von einem Funktionsnamen und eventuell Variablen in einer Klammer. Am Ende der Zeile steht ein Doppelpunkt. Anders als in C++ oder anderen Programmiersprachen verzichtet Python auf geschweifte Klammern oder ähnliches, um Beginn und Ende einer Funktion zu kennzeichnen. Stattdessen wird alles, was zur Funktion gehört, mit einem Tabstopp (entspricht vier Leerzeichen) eingerückt.

Nun können wir eine for-Schleife um unsere Funktion herumstricken. Unsere for-Schleife beginnt mit „for i in range(n):“. range(n) ist eine Standard-Pythonfunktion, um Listen zu erstellen. Diese Listen gehen von 0 bis n-1, hat also n Elemente. Gleiches Prinzip, wie bei der Funktion: alles, was zur for-Schleife gehört, wird um einen Tabstopp eingerückt. Je nachdem, wie groß wir n wählen wird unser Tellerfederpaket höher oder tiefer. Probieren Sie nachfolgendes Skript gerne direkt in Discovery aus:

ClearAll()

def create_disc_spring(i):
    D = MM(10)
    D1 = MM(20)
    H = MM(1)
    H1 = MM(2)

    sectionPlane = Plane.PlaneXY
    result = ViewHelper.SetSketchPlane(sectionPlane, None)

    point1 = Point2D.Create(D/2, H1+i*H1)
    point2 = Point2D.Create(D1/2, H1-H+i*H1)
    point3 = Point2D.Create(D1/2, 0+i*H1)
    point4 = Point2D.Create(D/2, H+i*H1)

    result = SketchLine.Create(point1, point2)
    result = SketchLine.Create(point2, point3)
    result = SketchLine.Create(point3, point4)
    result = SketchLine.Create(point4, point1)

    mode = InteractionMode.Solid
    result = ViewHelper.SetViewMode(mode, None)
    body = result.CreatedBodies[0]

    selection = FaceSelection.Create(body.Faces[0])
    axis = Line.Create(Point.Origin, Direction.DirY)
    options = RevolveFaceOptions()
    options.ExtrudeType = ExtrudeType.Cut
    result = RevolveFaces.Execute(selection, axis, DEG(360), options)

n = 10
for i in range(n):
    create_disc_spring(i)

Mit if-Anweisungen das Federpaket optimieren

Um abwechselnd gegengerichtete Federn zu stapeln, müssen wir jede zweite Feder umgekehrt zeichnen. Wir müssen also schauen, ob i im aktuellen Funktionsdurchlauf gerade oder ungerade ist. Mathematisch lässt sich das relativ einfach mit Modulo erledigen und auch in Python gibt es dafür das Sonderzeichen %. Ist unsere Zahl gerade, so ergibt 4%2 = 0, ist sie ungerade, so ist 5%2 = 1.

Mit der if-Anweisung verhält es sich, wie mit der for-Schleife. Alles, was an Code eingerückt folgt, gehört zur if/else Anweisung.

ClearAll()

def create_disc_spring(i):
     D = MM(10)'
     D1 = MM(20)
     H = MM(1)
     H1 = MM(2)

    sectionPlane = Plane.PlaneXY
    result = ViewHelper.SetSketchPlane(sectionPlane, None)

    if i%2 == 0: # i is even
        point1 = Point2D.Create(D/2, H1+i*H1)
        point2 = Point2D.Create(D1/2, H1-H+i*H1)
        point3 = Point2D.Create(D1/2, 0+i*H1)
        point4 = Point2D.Create(D/2, H+i*H1)

    else:        # i is odd
       point1 = Point2D.Create(D/2, H1-H+i*H1)
       point2 = Point2D.Create(D1/2, H1+i*H1)
       point3 = Point2D.Create(D1/2, H+i*H1)
       point4 = Point2D.Create(D/2, 0+i*H1)

    result = SketchLine.Create(point1, point2)
    result = SketchLine.Create(point2, point3)
    result = SketchLine.Create(point3, point4)
    result = SketchLine.Create(point4, point1)

    mode = InteractionMode.Solid
    result = ViewHelper.SetViewMode(mode, None)
    body = result.CreatedBodies[0]

    selection = FaceSelection.Create(body.Faces[0])
    axis = Line.Create(Point.Origin, Direction.DirY)
    options = RevolveFaceOptions()
    options.ExtrudeType = ExtrudeType.Cut
    result = RevolveFaces.Execute(selection, axis, DEG(360), options)

n = 10
for i in range(n):
    create_disc_spring(i)

Ausblick auf Parameter und Userbuttons in Ansys Discovery

Wie geht es nun mit dem Skript weiter? Das Federpaket muss noch in den Hubraum eingebaut werden. Die Höhe des Hubraumes können wir auch über einen Skriptbefehl messen. Wenn z.B. acht Tellerfedern verbaut werden sollen, dann muss noch ein wenig Mathematik betrieben werden, um die passende Höhe H1 auszurechnen. Noch interessanter wird es, wenn wir anfangen, das Ganze zu parametrisieren. Es gibt die Möglichkeit Skriptparameter zu definieren, die wir auch über den Parametermanager auf der Workbench Projektseite steuern können. Durch die Parametrisierung wird auch eine Verknüpfung zu optiSLang möglich.

Eine weitere Möglichkeit ist, sich das Skript als Userbutton fest in der Discovery Toolbar zu hinterlegen. Dann haben Sie es immer zur Hand, wenn Sie es brauchen. Außerdem können Sie für Userbuttons über den sogenannten InputHelper auch Eingabeaufforderungen schreiben. Dann kann der Anwender nach dem Buttonklick z.B. die Anzahl an Tellerfedern über die GUI angeben. Die Userbuttons können Sie auch an Kollegen weitergeben. Das hat den Vorteil, dass nicht jeder, der solche Helferlein verwenden möchte, sich mit Skripting in Discovery auskennen muss.

Und, wie nerdig fanden Sie es? Wenn Sie sagen, es ging eigentlich, dann fühlen Sie sich gerne eingeladen, bei der Anwendung von Discovery den Skripteditor mitlaufen zu lassen. Beobachten Sie, welche Befehle aufgezeichnet werden und ob Sie das für sich nutzen können. Werfen Sie auch gerne einen Blick auf die unten verlinkten Seminare, die Ihnen die Möglichkeit bieten, mit anderen Teilnehmern zusammen Python zu erlernen. Und wenn Sie den Nutzen von Automatisierung zwar wertschätzen, es Ihnen aber doch zu nerdig ist, die Programmierung selbst in die Hand zu nehmen, dann sprechen Sie uns an. Wir werden gemeinsam eine Lösung finden.

Autor

Berechnungsingenieurin

Veröffentlicht: Oktober 2023

Redaktion
Dr.-Ing. Marold Moosrainer
Head of Professional Development

Titelbilder:
Rechts: © CADFEM Germany GmbH
Links: © Adobe Stock

WEITERE BEITRÄGE ZUM THEMA