Konzeption und Realisierung eines zeitgemäßen

Konzeption und Realisierung eines zeitgemäßen Programmsystems zur allgemeinen Tragwerksanalyse Diplomarbeit Kathrin Telkamp 1. Prüfer: Prof. Dr.–Ing. Uwe Starossek Matr.-Nr.: 9952 2. Prüfer: Dipl.-Ing. Lydia Thiesemann Arbeitsbereich Statik und Dynamik der Baukonstruktionen Studiengang Bauingenieurwesen und Umweltschutztechnik Technische Universität Hamburg-Harburg Hamburg, September 2001 Vorwort Diese Diplomarbeit mit dem Titel „Konzeption und Realisierung eines zeitgemäßen Programmsystems zur allgemeinen Tragwerksanalyse“ wurde im Fachbereich Statik und Dynamik der Baukonstruktionen an der Technischen Universität Hamburg-Harburg im Rahmen des Studienganges Bauingenieurwesen angefertigt. Bei der Ausarbeitung wurde ich betreut von Prof. Dr.-Ing Uwe Starossek und Dipl.Ing. Lydia Thiesemann, für deren Unterstützung ich mich an dieser Stelle herzlich bedanken möchte. Weiterhin gilt mein Dank allen, die meine Arbeit Korrektur gelesen haben und mir auch sonst auf alle erdenklichen Arten geholfen haben. Verzeichnisse I Inhaltsverzeichnis ABBILDUNGSVERZEICHNIS.......................................................................................III TABELLENVERZEICHNIS ...........................................................................................IV SYMBOLVERZEICHNIS................................................................................................. V 1 EINLEITUNG.............................................................................................................. 1 2 GRUNDLAGEN DER FINITE-ELEMENTE-METHODE.................................... 3 2.1 Allgemeine Formulierung ....................................................................................... 3 2.1.1 Lineare statische Berechnung............................................................................ 3 2.1.2 Kinetische Berechnung...................................................................................... 7 2.1.3 Nichtlineare Berechnungen ............................................................................... 8 2.1.3.1 Theorie 2. Ordnung ................................................................................. 10 2.1.3.2 Physikalisch nichtlineare Berechnung..................................................... 12 2.2 3 Das Weggrößenverfahren für ein Stabwerk ....................................................... 12 SOFTWARE-ENTWURF ........................................................................................ 20 3.1 Verschiedene Entwurfsverfahren......................................................................... 20 3.1.1 Streng hierarchisch strukturiertes Design (prozedural) ................................... 20 3.1.2 Datenorientiertes Design (funktional) ............................................................. 21 3.1.3 Objektorientiertes Design ................................................................................ 21 3.2 4 Vergleich und Auswertung ................................................................................... 22 OBJEKTORIENTIERTE ANALYSE UND DESIGN........................................... 27 4.1 Unified Modeling Language (UML)..................................................................... 27 4.1.1 Ziele der UML ................................................................................................. 27 4.1.2 Bestandteile der UML ..................................................................................... 28 4.2 Konzepte und Definitionen der objektorientierten Programmierung.............. 33 4.2.1 Basisdefinitionen ............................................................................................. 34 4.2.1.1 Objekt ...................................................................................................... 34 4.2.1.2 Klasse ...................................................................................................... 35 4.2.1.3 Methoden................................................................................................. 35 4.2.1.4 Attribute................................................................................................... 36 4.2.2 Datenabstraktion.............................................................................................. 36 4.2.3 Kapselung ........................................................................................................ 37 4.2.4 Modularität ...................................................................................................... 38 4.2.5 Hierarchie (Relationen) ................................................................................... 38 4.2.5.1 Vererbung ................................................................................................ 38 4.2.5.2 Aggregation ............................................................................................. 40 4.2.5.3 Assoziation .............................................................................................. 41 4.2.6 Polymorphie .................................................................................................... 42 4.2.7 Nebenläufigkeit ............................................................................................... 43 II Verzeichnisse 4.2.8 4.2.9 5 5.1 Persistenz......................................................................................................... 44 Generizität ....................................................................................................... 44 GLOBALES PROGRAMMKONZEPT ..................................................................46 Erläuterung des FEM-Objektmodells ................................................................. 46 5.2 Die Klassen ............................................................................................................. 54 5.2.1 Die Klasse ElementFEM ................................................................................. 54 5.2.2 Die Klasse Node .............................................................................................. 56 5.2.3 Die Klasse Dof ................................................................................................ 56 5.2.4 Die Klasse StructureFEM ............................................................................... 57 5.2.5 Die Klasse ProblemDomain............................................................................ 58 5.2.6 Die Klasse Matrix............................................................................................ 58 5.3 Rechenabläufe........................................................................................................ 59 5.3.1 Statische Berechnung ...................................................................................... 60 5.3.2 Nichtlineare Berechnung................................................................................. 60 5.4 6 Erweiterbarkeit und Wiederverwendung ........................................................... 68 PROGRAMMIERSPRACHEN................................................................................69 6.1 Prozedurale Programmiersprachen .................................................................... 72 6.1.1 Fortran ............................................................................................................. 72 6.1.2 C ...................................................................................................................... 73 6.2 Genuine objektorientierte Programmiersprachen............................................. 74 6.2.1 Smalltalk.......................................................................................................... 74 6.2.2 Eiffel................................................................................................................ 75 6.3 Hybride objektorientierte Programmiersprachen ............................................. 76 6.3.1 Ada .................................................................................................................. 76 6.3.2 C++.................................................................................................................. 77 6.3.3 Java.................................................................................................................. 78 6.4 Vergleich und Auswertung ................................................................................... 79 7 PROTOKOLLE UND DOKUMENTATION..........................................................84 8 BEISPIELPROGRAMM...........................................................................................87 8.1 Dateneingabe.......................................................................................................... 87 8.2 Datenausgabe ......................................................................................................... 91 LITERATURVERZEICHNIS ..........................................................................................92 ANHANG ............................................................................................................................95 A. Unified Modeling Language (UML 1.4) Notationsübersicht B. Quellcode des Programms AllTA C. Vergleichsrechnungen D. Fiktives Klassenprotokoll der Klasse ElementFEM III Verzeichnisse Abbildungsverzeichnis Abbildung 2-1: Beliebiger 3D-Körper K ................................................................................... 4 Abbildung 2-2: Vorzeichenkonvention und Nummerierung der globalen Freiheitsgrade ....... 13 Abbildung 2-3: Baustatische Skizze des Balkenelementes ...................................................... 13 Abbildung 2-4: Bestimmung der Festhaltekraftgrößen am Balkenelement ............................. 17 Abbildung 3-1: Datenzugriff in prozeduralen und objektorientierten Programmen (aus [1]) . 24 Abbildung 4-1: Klassen............................................................................................................ 28 Abbildung 4-2: Schnittstellen................................................................................................... 29 Abbildung 4-3: Kollaborationen............................................................................................... 29 Abbildung 4-4: Anwendungsfälle ............................................................................................ 29 Abbildung 4-5: Aktive Klassen ................................................................................................ 29 Abbildung 4-6: Komponenten .................................................................................................. 29 Abbildung 4-7: Knoten............................................................................................................. 30 Abbildung 4-8: Nachrichten ..................................................................................................... 30 Abbildung 4-9: Zustände .......................................................................................................... 30 Abbildung 4-10: Pakete ............................................................................................................ 30 Abbildung 4-11: Notizen .......................................................................................................... 31 Abbildung 4-12: Abhängigkeiten ............................................................................................. 31 Abbildung 4-13: Assoziationen................................................................................................ 31 Abbildung 4-14: Generalisierungen ......................................................................................... 31 Abbildung 4-15: Realisierungen............................................................................................... 31 Abbildung 4-16: Klasse und Objekt (Instanz) am Beispiel eines Balkenelementes ................ 37 Abbildung 4-17: Einfache Vererbungsstruktur ........................................................................ 39 Abbildung 4-18: Mehrfachvererbung....................................................................................... 40 Abbildung 4-19: Aggregation................................................................................................... 41 Abbildung 4-20: Assoziationen................................................................................................ 42 Abbildung 4-21: Generische Klasse ......................................................................................... 45 Abbildung 5-1: Klassendiagramm: Klassen des globalen FEM-Models ................................. 49 Abbildung 5-2: Klassendiagramm: Klassen für die Steuerung der Berechnung...................... 50 Abbildung 5-3: Klassendiagramm: Vererbungshierarchie für die FEM-Objekte .................... 51 Abbildung 5-4: Klassendiagramm: Delegation der Containermethoden an eine generische Klasse ............................................................................................................. 52 Abbildung 5-5: Klassendiagramm: Die Klasse Matrix ............................................................ 53 Abbildung 5-6: Aktivitätsdiagramm: Statische lineare Berechnung........................................ 62 IV Verzeichnisse Abbildung 5-7: Sequenzdiagramm: Statische lineare Berechnung.......................................... 63 Abbildung 5-8: Aktivitätsdiagramm: Berechnung nach Theorie 2. Ordnung.......................... 64 Abbildung 5-9: Sequenzdiagramm: Berechnung eines Iterationsschritts nach Theorie 2. Ordnung.......................................................................................................... 65 Abbildung 5-10: Aktivitätsdiagramm: Physikalisch nichtlineare Berechnung........................ 66 Abbildung 5-11: Sequenzdiagramm: Berechnung eines Lastschrittes, physikalisch nichtlineare Berechnung .............................................................................. 67 Abbildung 6-1: Entwicklungslinien der Programmiersprachen............................................... 70 Abbildung 6-2: Objektbasierte, klassenbasierte und objektorientierte Programmiersprachen 71 Abbildung 6-3: Abstraktionslevel in Smalltalk, C++, Fortran, C [32] .................................... 82 Tabellenverzeichnis Tabelle 4-1: Diagramme der UML........................................................................................... 32 Tabelle 6-1: Objektorientierte Konzepte der verschiedenen Hochsprachen........................... 80 Tabelle 6-2: Eignung für numerische Berechnung: Fortran77, Fortran 90, C, C++ ................ 82 V Verzeichnisse Symbolverzeichnis {x, y, z} lokale Basis {X ,Y ,Z} globale Basis ϕx, ϕy, ϕz : Verdrehungen um die lokalen Achsen x, y, z ϕ X ,ϕY ,ϕ Z : Verdrehungen um die globalen Achsen X, Y, Z λ: skalare Kraftgröße der maximalen Belastung ρ (m) : Massendichte des Elementes m l: Länge t: Zeitvariable qx, qy, qz : Linienlasten am Stabelement (lokale Basis) vx, vy, vz : Verschiebungen in die lokalen Koordinatenrichtungen x, y, z v X , vY , v Z : Verschiebungen in die globalen Koordinatenrichtungen X,Y,Z My, Mz : Biegemomente am Stabende um die Achsen y und z (lokale Basis) MT : Torsionsmoment am Stabende (lokale Basis) N: Normalkraft am Stabende (lokale Basis) Px, Py, Pz : Einzelkräfte, am Element angreifend (lokale Basis) Qy, Qz, Querkräfte am Stabende in y- und z-Richtung (lokale Basis) S(m) : Oberfläche des Elementes m SX, SY, SZ : Stabendkräfte (globale Basis) TX, TY, TZ : Stabendmomente (globale Basis) V (m) : ε(m) : (m) τ τ Vektor der Verzerrungen im Element m : I(m) : f: f : Anfangsspannungen im Element m Element-Randkraftgrößen (globale Basis) B f ,f : 0 Vektor der Spannungen im Element m Element-Randkraftgrößen (lokale Basis) f: S Volumen des Elementes m Vektor kontinuierlicher Elementlasten (lokale Basis) Festhaltegrößen (lokale Basis) VI Verzeichnisse k: Element-Steifigkeitsmatrix bezogen auf alle Element-Freiheitsgrade (lokale Basis) k: Element-Steifigkeitsmatrix bezogen auf alle Element-Freiheitsgrade (globale Basis) p0: Vektor der Linienlasten (lokale Basis) v: Vektor der Element-Freiheitsgrade (lokale Basis) v: Vektor der Element-Freiheitsgrade (globale Basis) v(m) : Verschiebungen im Element m B(m) : Verzerrungs-Verschiebungs-Matrix am Element m bezogen auf die aktiven System-Freiheitsgrade C(m) : Elastizitätsmatrix des Elementes m bezogen auf die aktiven SystemFreiheitsgrade F: Vektor der auf die Elemente wirkende äußere Kräfte bezogen auf die aktiven System-Freiheitsgrade. (globale Basis) Fi : Vektor konzentrierter Lasten F* : Pseudo-Lastvektor, der die Nichtlinearitäten berücksichtigt F: normierter Lastvektor der Knotenlasten F + F: Lastinkrement Fˆ 0 : Vektor der System-Festeinspannkraftgößen Freiheitsgrade Fo: Vektor der mit den aktiven Freiheitsgraden korrespondierenden System-Festeinspannkraftgrößen Fc0 : Vektor der mit den gefesselten Freiheitsgraden korrespondierenden System-Festeinspannkraftgrößen H(m) : Verschiebungsinterpolationsmatrix des Elementes m bezogen auf die aktiven System-Freiheitsgrade K(m) : Steifigkeitsmatrix des Elementes m (globale Basis) bezogen auf die aktiven System-Freiheitsgrade K: Gesamtsteifigkeitsmatrix bezogen Freiheitsgrade (globale Basis) Kg n : geometrische Steifigkeitsmatrix (abhängig von Vn) Ktn : tangentiale Steifigkeitsmatrix im Iterationsschritt n M: Gesamtmassenmatrix (globale Basis) bezogen auf die aktiven SystemFreiheitsgrade (globale Basis) P: Vektor der äußeren Einzelkräfte, die auf die Knoten der ElementeGruppierung wirken Pc: Lagerkraftgrößen Pˆ : Vektor der an den Knoten angreifenden äußeren Kraftgrößen (Knotenlasten und Lagerkräfte) bezogen auf alle Freiheitsgrade auf die bezogen aktiven auf alle System- VII Verzeichnisse T: Drehungsmatrix U: Vektor der Ungleichgewichtskräfte V: Vektor für die globalen Knotenpunktverschiebungen einer ElementeGruppierung bezogen auf die aktiven Freiheitsgrade ˆ: V Vektor für die globalen Knotenpunktverschiebungen einer ElementeGruppierung bezogen auf alle Freiheitsgrade && : V Vektor der Knotenbeschleunigungen Vn : Vektor der absoluten globalen Knotenverschiebungen bezogen auf die aktiven Freiheitsgrade Vc : Vektor der durch Lagerbindung gefesselten Freiheitsgrade 1 Einleitung 1 1 Einleitung Diese Arbeit diskutiert die Konzeption und Realisierung eines zeitgemäßen Programms zur allgemeinen Tragwerksanalyse. Dabei geht es zunächst um die Verwirklichung eines Finite-Elemente-Programms (FEM). Das Hauptaugenmerk liegt auf einem globalen, modular aufgebauten Programmentwurf. Das Design sollte flexibel und leicht an neue Aufgabenstellungen anzupassen sein. Die Erweiterbarkeit des Programmsystems auf andere numerische Methoden wie z.B. die Boundary-Element-Methode (BEM) oder die Methode der Finiten Differenzen (FDM) oder sogar die Berechnung von Mischformen aus diesen numerischen Methoden soll im Entwurf mitberücksichtigt werden. Die für das Verständnis notwendigen Grundlagen der Finite-Elemente-Methode werden zu Beginn der Arbeit in allgemeiner Form vorgestellt. Dabei wird auch auf die Berechnung nichtlinearer Systeme eingegangen und übliche numerische Verfahrensweisen werden erläutert. Für das Design eines komplexen Software-Systems gibt es grundsätzlich kein Universalrezept. Oft lassen sich mehrere Entwurfsverfahren für die Realisierung eines Programms einsetzen. Die Entscheidung, mit welchem Design-Konzept sich die Anforderungen an ein bestimmtes Software-System am besten erfüllen lassen, ist sehr stark abhängig von den Kriterien, die man zur Beurteilung heranzieht. Die verschiedenen gebräuchlichen Entwurfsstile für Software werden in Kapitel 3 näher erläutert und ihre Vor- und Nachteile in Bezug auf das zu entwerfende Programmsystem diskutiert. In der vorliegenden Arbeit wurde ein objektorientierter Entwurf favorisiert. In den Kapiteln 4 und 5 werden daher die Begriffe und Konzepte der Objektorientierung definiert und die Unified Modeling Language (UML) als Notation für objektorientierte Programmsysteme vorgestellt. Der Programmentwurf wird in Kapitel 5 vorgestellt. Dabei wird die Architektur mit Hilfe von Klassendiagrammen erläutert. Berechnungsabläufe werden in Sequenz- und Aktivitätsdiagrammen dargestellt. Der Entwurf wird beispielhaft in einem kleinen FEMStabwerksprogramm umgesetzt, das in Kapitel 8 beschrieben ist. Der Quellcode für das Programm ist im Anhang zu finden. Das Design eines Programmsystems setzt sich gleichermaßen aus den Kenntnissen über das numerische Verfahren, hier die Methode der Finiten Elemente, die verwendete Entwurfsmethode und die Erläuterung der grafischen Notation zusammen. Im Rahmen 2 Einleitung dieser Diplomarbeit können die angesprochenen Themengebiete nur in vereinfachter Form wiedergegeben werden, die Erläuterungen erheben keinen Anspruch auf Vollständigkeit. Zudem lassen sich die Bestandteile in den einzelnen Kapiteln nicht vollständig entkoppeln, daher beziehen sich die einzelnen Abschnitte der Arbeit sehr stark aufeinander. Bei der Gliederung konnte nicht vollständig vermieden werden, dass Begriffe und Konzepte, die in einem Absatz bereits benutzt werden, erst zu einem späteren Zeitpunkt genauer definiert werden. Die entsprechenden Verweise sind angegeben. 2 Grundlagen der Finite-Elemente-Methode 2 3 Grundlagen der Finite-Elemente-Methode In diesem Abschnitt werden die Gleichungen für die Methode der Finiten Elemente zunächst in allgemeiner Form vorgestellt. Auf dieser allgemeinen Formulierung beruht der Entwurf der Programmarchitektur in Kapitel 5. Die Beziehungen für einen beliebig geformten 3D-Körper werden in Kapitel 2.2 auf ein linear-elastisches, schubstarres Balkenelement angewendet. Dieses wird für die beispielhafte Implementierung des Stabwerkprogramms benutzt (vgl. Kapitel 8). Es liegt nicht im Rahmen der Arbeit alle dargestellten Gleichungen herzuleiten, dafür wird auf die Literatur verwiesen (Bathe [2], Krätzig [20],[21]). Vielmehr soll nur der allgemeine Ablauf einer Berechnung nach der Methode der Finiten Elemente und die dafür benötigten Gleichungen und Matrizen vorgestellt werden. 2.1 Allgemeine Formulierung Die Berechnung diskreter Systeme beruht im Allgemeinen auf vier Schritten: • der Idealisierung des Systems (Elementierung), • der Aufstellung der Gleichgewichts- bzw. Bewegungsgleichung, • der Ermittlung der Systemantwort und • der Interpretation der Ergebnisse. Im Folgenden wird hauptsächlich auf die Aufstellung der Gleichgewichts- bzw. Bewegungsgleichung und die Berechnung der Systemantwort mit numerischen Verfahren eingegangen, da diese Bestandteile des eigentlichen Rechenkerns eines FEM- Programmsystems sind. Die Elementierung und die Interpretation der Ergebnisse sind Bestandteile eines geeigneten Prä- bzw. Postprozessors und werden programmtechnisch vom Rechenkern abgekoppelt. 2.1.1 Lineare statische Berechnung Der in Abbildung 2-1 dargestellte beliebige 3D-Körper K soll sich im Gleichgewicht befinden. Auf den Körper wirken äußere Lasten: Oberflächenspannungen fS, Volumenkräfte fB und Einzelkräfte Fi. Sie umfassen alle äußeren eingeprägten und Reaktionslasten und haben – entsprechend den drei globalen Koordinatenachsen X,Y,Z – jeweils drei Komponenten. 4 Grundlagen der Finite-Elemente-Methode X Y fSX, f BX f SY, f BY Z FiX FiY y x z fSZ, f BZ FiZ Abbildung 2-1: Beliebiger 3D-Körper K Die Lastvektoren haben die Form: [ = [f = [F ] ]; ]; T f S = f XS f YS f ZS ; fB B X f YB f ZB i X FYi FZi FS T [Gl. 1] T Die auf den unbelasteten Zustand des Körpers bezogenen Verschiebungen kennzeichnet der Verschiebungsvektor V mit V = [V X VY VZ ] . T [Gl. 2] Über die Verzerrungs-Verschiebungs-Beziehungen sind dem Verschiebungsvektor V die Verzerrungen ε = [ε XX ε ZX ]T [Gl. 3] τ YY τ ZZ τ XY τ YZ τ ZX ]T [Gl. 4] ε YY ε ZZ ε XY ε YZ zugeordnet, denen die Spannungen τ = [τ XX entsprechen. In der Methode der Finiten Elemente wird der kontinuierliche Körper näherungsweise als eine Gruppierung diskreter finiter Elemente dargestellt, die in Knotenpunkten auf den Rändern der Elemente untereinander verbunden sind. 2 Grundlagen der Finite-Elemente-Methode 5 Die in einem passend zu wählenden, lokalen Koordinatensystem x,y,z gemessenen Verschiebungen innerhalb eines jeden Elementes werden als Funktionen der Verschiebung der N Knotenpunkte der finiten Elemente angenommen. Damit gilt für die Verschiebungen des m-ten Elementes: ˆ v (m) ( x,y,z ) = H (m) ( x, y, z )V mit : v(m) : [Gl. 5] Verschiebungen im Element m x,y,z: lokales Koordinatensystem (KOS) H(m): Verschiebungsinterpolationsmatrix ˆ : V Vektor für die globalen Verschiebungskomponenten aller Knotenpunkte der Elemente-Gruppierung ˆ T = [V V V K V ] V 1 2 3 n [Gl. 6] Die einzelnen Komponenten Vi des Verschiebungsvektors aus Gleichung 6 können dabei eine Verschiebung in beliebiger Richtung darstellen, die nicht notwendigerweise mit einer globalen Achse übereinstimmt, und auch eine Drehung kennzeichnen kann. Die Matrix H(m) ist die Verschiebungsinterpolationsmatrix und enthält die gewählten Formfunktionen. Das Feld der äußeren Weggrößen wird zunächst durch die - auf die lokale Basis bezogenen - Verschiebungen beschrieben, für die Polynomansätze des gewünschten Grades angenommen werden. Die Formfunktionen der Matrix H(m) erhält man durch Ersetzen der Polynomparameter durch den Vektor der Knotenverschiebungen. Die Verschiebungen und Verzerrungen innerhalb eines Elementes hängen nur von den Verschiebungen der Knoten dieses Elementes ab. Damit ergeben sich die ElementVerzerrungen zu: ˆ ε (m) ( x,y,z) = B (m) ( x, y, z )V mit : ε(m) : Verzerrungen im Element m B(m): Verzerrungs-Verschiebungs-Matrix [Gl. 7] Die Zeilen der Verzerrungs-Verschiebungs-Matrix werden durch Differenzieren und Kombinieren der Zeilen der Matrix H(m) in Gleichung 5 ermittelt. 6 Grundlagen der Finite-Elemente-Methode Die Spannungen τ(m) in einem finiten Element sind mit den Verzerrungen ε(m) und den Anfangsspannungen τI(m) des Elementes über τ (m) = C (m) ε (m ) + τ I(m) τ(m) : mit : [Gl. 8] Spannungen im Element m C(m): Elastizitätsmatrix des Elementes τI(m) : Anfangsspannungen im Element m verknüpft. Das durch C(m) für jedes Element angegebene Materialgesetz kann ein isotropes oder anisotropes Material beschreiben und kann sich von Element zu Element ändern. Über die Methode der virtuellen Verschiebungen (jeweils ein Vi wird gleich 1 gesetzt) können nun in jedem finiten Element die Gleichgewichtsbedingungen bezüglich der Knotenpunktverschiebungen der Gruppierung von finiten Elementen aufgestellt werden. Dabei wird der Verschiebungsverlauf über das Element über eine Funktion angenähert. Wenn von nun an die Knotenpunktverschiebungen einfach mit V bezeichnet werden ˆ ≡ V ), (V lauten die auf die Knotenpunktverschiebungen bezogenen Gleichgewichtsbedingungen der Element-Gruppierung: KV = F mit [Gl. 9] F : Last-Vektor mit den auf die Elemente wirkenden Kräften. F = FB + FS – FI + P [Gl. 10] P ist der Vektor der äußeren Einzelkräfte, die auf die Knoten der Elemente-Gruppierung wirken. K: Gesamtsteifigkeitsmatrix V: globaler Vektor der Knotenpunktverschiebungen Die Komponenten von Gleichung 9 und 10 errechnen sich dabei wie folgt: K = ∑ K (m ) = ∑ m ∫ B (m)T C (m) B (m) dV ( m ) [Gl. 11] m V (m) F B = ∑ F B(m) = ∑ ∫ H (m)T f B(m) dV ( m ) [Gl. 12] F S = ∑ F S(m) = ∑ ∫ H S (m)T f S(m) dS ( m ) [Gl. 13] F I = ∑ F I(m) = ∑ ∫ B(m)T τ I(m) dV ( m ) m m m m V (m) m S (m) m V (m) [Gl. 14] 2 Grundlagen der Finite-Elemente-Methode 7 Die in Gleichung 11 vorgeschriebene Summation der Volumenintegrale über die Elemente entspricht der direkten Addition der Steifigkeitsmatrizen K(m) der Elemente. Sie liefert die Steifigkeitsmatrix K der gesamten Elemente-Gruppierung. Analog werden die Kraftvektoren durch direkte Addition der Volumenkraftvektoren der einzelnen Elemente errechnet. Die Aufstellung der Gleichgewichtsbedingungen in der hier beschriebenen Weise (Bezug auf den Vektor V der globalen Freiheitsgrade bei der Elementformulierung) enthält somit die Zusammenfügung von Element-Matrizen zu einer Strukturmatrix. Dieses Vorgehen wird auch als direkte Steifigkeitsmethode bezeichnet. In der Praxis werden die finiten Element-Matrizen zunächst in kompakter Form für alle möglichen Freiheitsgrade des Elementes berechnet (Entkopplung). Für ein Element gilt: kv = f mit: [Gl. 15] k : Element-Steifigkeitsmatrix v: Vektor der Element-Freiheitsgrade f: durch Knotenverschiebungen hervorgerufene ElementRandkraftgrößen Die einzelnen Einträge in der Elementmatrix setzen sich dabei aus Randkraftgrößen zusammen, die aus einer Einheitsverschiebung in Richtung jeweils eines Freiheitsgrades resultieren. Die Berechnungsvorschriften aus den Gleichungen 11-14 behalten ihre Gültigkeit, die Element-Matrizen b und h beziehen die Verschiebungen dabei allerdings nicht mehr auf die globalen, sondern auf die lokalen Freiheitsgrade des Elementes. Die Freiheitsgrade des Elementes werden über Inzidenzen auf die Freiheitsgrade der Struktur bezogen und die entsprechenden Beiträge der Elementmatrix in die Gesamtsteifigkeitsmatrix eingelesen. 2.1.2 Kinetische Berechnung Bei der Erweiterung der erstellten Beziehungen auf dynamische Aufgabenstellungen gehen Trägheitskräfte mit in die Grundgleichung ein. Diese werden auf die Seite der inneren Größen des Systems gestellt. Die Systemantwort wird damit zeitabhängig. && (t ) + KV (t ) = F(t ) MV mit: [Gl. 16] M: Gesamtmassenmatrix K: Gesamtsteifigkeitsmatrix V(t): Vektor der Knotenverschiebungen Zeitunabhängig && (t ) : Vektor der Knotenbeschleunigungen V Zeitabhängig 8 Grundlagen der Finite-Elemente-Methode Die zusätzliche Komponente in Gleichung 16 errechnet sich nach: M = ∑ M (m) = ∑ m mit: ∫ ρ ( m ) H (m)T H (m) dV ( m ) [Gl. 17] m V (m) ρ(m) : Massendichte des Elementes m Während Gleichung 8 noch ein lineares Gleichungssystem repräsentiert und daher direkt gelöst werden kann, beschreibt Gleichung 16 eine Differentialgleichung 2. Ordnung. Das Gleichgewicht muss für jeden Zeitpunkt t erfüllt werden. In numerischen Anwendungen wird die Differentialgleichung üblicherweise mit direkten Integrationsmethoden gelöst. Dabei wird die Bewegungsgleichung in diskreten Zeitintervallen Δt erfüllt (nicht für einen beliebigen Zeitpunkt). Die Anfangsbedingungen zum Zeitpunkt t=0 sind bekannt. Von t=0 ausgehend werden für jeden Zeitschritt die effektiven Lasten zum Zeitpunkt t+Δt extrapoliert, die entsprechenden Verschiebungen zur Zeit t+Δt berechnet und die Beschleunigung zur Zeit t ermittelt. Bekannte direkte Integrationsmethoden sind z.B. die zentrale Differenzenmethode (explizites Verfahren), die Houboltsche oder die Newmark-Methode (implizit). Ebenso wie die Steifigkeitsmatrix wird auch die Massenmatrix für jedes Element entsprechend der Element-Freiheitsgrade aufgestellt, und über die Inzidenzen in die Gesamtmassenmatrix eingelesen [2]. 2.1.3 Nichtlineare Berechnungen Nichtlineares Verhalten von Tragwerken hat eine oder mehrere der folgenden Ursachen: • Geometrische Nichtlinearität; z.B. Theorie 2. Ordnung, d.h. Gleichgewicht am verformten System • Nichtlineares Materialverhalten; z.B. allg. Spannungs-Dehnungs-Diagramm • Veränderliche Systeme; z.B. Zugstäbe, die bei Druckbeanspruchung nicht mitwirken Alle diese Einflüsse haben gemeinsam, dass der Graph, der das Verhältnis zwischen Last und Verformung beschreibt, nicht mehr linear verläuft. Die Berechnung erfolgt iterativ und/oder durch schrittweises Aufbringen der Lasten. Falls in einer statischen, zeitunabhängigen Rechnung nur die Konfiguration für eine bestimmte Laststellung gesucht ist, kann die iterative Berechnung auch auf einen Schritt reduziert werden. Aus 2 Grundlagen der Finite-Elemente-Methode rechentechnischen Gründen (z.B. 9 Konvergenz) kann allerdings ebenfalls eine Inkrementallösung notwendig werden. Das gemeinsame Ziel aller numerischen Lösungsverfahren ist, den nichtlinearen LastVerformungspfad nachzufahren. Man definiert für die numerische Berechnung eine sogenannte Ungleichgewichtskraft U, die die Abweichung der approximierten Lösung vom wahren Gleichgewicht angibt (für Gleichgewicht gilt: U = 0). Gl. 9 kann damit auf die folgende Form erweitert werden: U = -KV + F + F*(V) mit: K: lineare globale Steifigkeitsmatrix V: Vektor der globalen Knotenverschiebungen F: Vektor der äußeren Lasten [Gl. 18] F*: Pseudo-Lastvektor, der die Nichtlinearitäten berücksichtigt U: Ungleichgewichtskraft Der Kraftvektor F der äußeren Lasten kann durch einen skalaren Parameter λ multipliziert mit dem normierten Vektor F ausgedrückt werden. F=λ⋅F [Gl. 19] Der Pseudo-Lastvektor F* und der Vektor der globalen Knotenverschiebungen werden ebenfalls als Funktionen von λ aufgefasst. Eine Ableitung nach λ ergibt: U ′ = −KV ′ + F + (F * (V )) ′ [Gl. 20] Bei der Ableitung des nichtlinearen Pseudo-Lastvektors gilt die Kettenregel. Die bei der Ableitung entstehende Matrix wird auch als nichtlineare Steifigkeitsmatrix KNL bezeichnet. Gleichung 20 wird damit zu: U ′ = −KV ′ + F + ( −K NL V ′) = −(K + K NL )V ′ + F [Gl. 21] Die numerischen Verfahren für die Lösung der nichtlinearen Beziehungen lassen sich in 3 Gruppen teilen: 1. Lösungsverfahren 1. Klasse versuchen für jeden Lastschritt die Gleichgewichtsbedingungen zu erfüllen Æ U = 0 Bekannter Vertreter dieser Klasse ist das Newton-Raphson-Verfahren 2. Lösungsverfahren 2. Klasse minimieren die Ungleichgewichtskraft für jedes Lastinkrement Æ U′ = 0 Bekannt ist hier die inkrementelle Steifigkeitsmethode. 10 Grundlagen der Finite-Elemente-Methode 3. Selbstkorrigierende Methoden sind Methoden, die Verfahren der 1. und 2. Klasse verbinden. Die Systemantwort wird korrigiert, wenn sie zu weit vom Gleichgewicht abweicht. Die Verwendung eines bestimmten Lösungsalgorithmus ist abhängig von einer Anzahl von Kriterien wie der Art der Nichtlinearität, dem Einfluss der Nichtlinearität auf die Systemantwort, dem Konvergenzverhalten, dem Rechenaufwand und der Genauigkeit. Da eine Diskussion der verschiedenen Verfahren den Rahmen der Arbeit sprengen würde, werden für die Berechnung nach Theorie 2. Ordnung und für physikalische Nichtlinearitäten in der Praxis übliche Berechnungsverfahren ausgewählt und vorgestellt. Dabei wird davon ausgegangen, dass diese Phänomene getrennt voneinander auftreten. Für eine gleichzeitige Berechnung von Theorie 2. Ordnung unter Berücksichtigung nichtlinearen Materialverhaltens kann z.B. eine Kombination der vorgestellten Verfahrensweisen eingesetzt werden. 2.1.3.1 Theorie 2. Ordnung Geometrisch nichtlineare Tragwerksanalysen berücksichtigen entstehende Deformationen als endliche Größen. Das Gleichgewicht wird an der verformten Konfiguration formuliert. Auch bei einem weiterhin linear-elastischem Werkstoffverhalten wird somit das Gesamtproblem nichtlinear. Ein in der Praxis häufig eingesetztes Lösungsverfahren für geometrische Nichtlinearität ist das Newton-Raphson-Verfahren. Die Gesamtlast wird in Lastschritten aufgebracht. + F= mit: λ M F = Δλ ⋅ F + [Gl. 22] F: Lastinkrement F: normierter Vektor der Knotenlasten M: Anzahl der Lastschritte, Berechnungsschritte m= 1,2...M λ: skalare Kraftgröße der maximalen Belastung Die nichtlineare Steifigkeitsmatrix reduziert sich in diesem Fall auf die geometrische Steifigkeitsmatrix Kg, die (linear) abhängig von den inneren Schnittgrößen der Elemente ist. Wie für K muss auch bei der Ableitung von Kg nur ein einziges Element eines spezifischen Typs betrachtet werden, weil sich die beherrschenden Gleichgewichtsbedingungen einer Elemente-Gruppierung mit Hilfe der direkten Steifigkeitsmethode aufstellen lassen. Die 2 Grundlagen der Finite-Elemente-Methode 11 geometrische Element-Steifigkeitsmatrix kg wird aus der Taylor-Entwicklung des Ausdruckes (f*(v))´ bis zum 2. Glied gewonnen (Æ Theorie 2. Ordnung). Die Iteration für einen Lastschritt (ausgehend von einer bereits bekannten Konfiguration F0,V0) lässt sich in der Newton-Raphson-Methode wie folgt beschreiben: U(V) n = (K + K g n ) ⋅ ΔVn +1 = K t n ⋅ ΔVn +1 und [Gl. 23] Vn +1 = Vn + ΔVn +1 mit: n: [Gl. 24] Kgn: Iterationsschritt n = 0,1,2...N, N: Gesamtzahl der Iterationsschritte geometrische Steifigkeitsmatrix (abhängig von Vn) Ktn: tangentiale Steifigkeitsmatrix im Iterationsschritt n Vn: Vektor der absoluten globalen Knotenverschiebungen U(V)n: Ungleichgewichtskraft Aus Gleichung 23 und 24 wird der Zuwachs der Verschiebung ΔVn +1 für den jeweiligen Iterationsschritt berechnet. In der Vorbereitung des nächsten Iterationsschrittes werden die jeweils letzten Näherungswerte für Vn-1 dazu verwendet, um die zugehörigen Element-Spannungen und Knotenpunktkräfte zu ermitteln. + U(V) n = F 0 + F − Fn -1 mit: U(V): Fn-1: [Gl. 25] + Ungleichgewichtskraft, für n=0 gilt U(V)0 = F . Aus den aktuellen Knotenverschiebungen Knotenpunktkräfte (Lastseite) resultierende Die Iteration wird solange fortgeführt, bis die Ungleichgewichtskraft U(V)n+1 bzw. der Zuwachs der Knotenverschiebungen ΔVn +1 für eine Iteration unter eine vorgegebene Genauigkeitsschranke fällt. Das Newton-Raphson-Verfahren konvergiert in der Regel sehr schnell. Vor allem konvergiert es auch bei einem großen Einfluss der Nichtlinearität und liefert eine vergleichsweise genaue Berechnung. Ein großer Nachteil dieses Lösungsverfahrens ist, dass es sehr rechenintensiv ist. Für jeden Iterationsschritt wird die tangentiale Steifigkeitsmatrix neu aufgestellt und invertiert. In einem modifizierten Newton-Raphson-Verfahren wird daher die tangentiale Steifigkeitsmatrix nur am Beginn eines jeden Lastschrittes aufgestellt und für die gesamte Iteration konstant gehalten. Das Newton-Raphson-Verfahren ist beschränkt auf Verfahren, in denen keine Entlastung vorkommt. 12 Grundlagen der Finite-Elemente-Methode 2.1.3.2 Physikalisch nichtlineare Berechnung Für physikalisch nichtlineare Berechnungen eignen sich die direkten (iterativen) Näherungsverfahren (U = 0) nicht, da sie um kritische Punkte des Last-Verformungspfades oszillieren oder sogar divergieren können. Für diese Berechnungen werden zumeist Verfahren 2. Klasse herangezogen. Die inkrementelle Steifigkeitsmethode geht in kleinen Lastschritten den LastVerformungspfad nach, wobei für jeden Lastschritt das System als linear angenommen wird. Der nichtlineare Anteil der tangentialen Steifigkeitsmatrix beinhaltet die plastischen Anteile der Last-Verformungsbeziehung. K t = K + K pl [Gl. 26] Für jeden Lastschritt wird U(V) minimiert ( U ′ = 0). Die Berechnung für die Lastschritte erfolgt dabei nach folgenden Formeln: + (K + K pl m ) ⋅ ΔVm +1 = Δλ ⋅ F = F und Vm +1 = Vm + ΔVm +1 [Gl. 27] [Gl. 28] Aus Gleichung 27 wird jeweils ΔVm +1 errechnet. In Abhängigkeit von Vm+1 aus Gleichung 28 wird dann der plastische Teil der Steifigkeitsmatrix für den nächsten Lastschritt neu berechnet. Die Verfahrensweise der inkrementellen Steifigkeitsmethode ist für nichtlineares Materialverhalten sehr vorteilhaft und einfach umzusetzen. Es wird keine Iteration benötigt und plastisches Materialverhalten kann problemlos berücksichtigt werden. Ein Nachteil dieser Methode ist, dass es keine wirkliche Fehlerabschätzung gibt. Da ein Lastschritt auf dem nächsten aufbaut summieren sich Fehler und die inkrementelle Lösung „driftet“ von der eigentlichen Lösung weg. Um eine Aussage über den Fehler zu erhalten, sollte das System mit verschieden großen Lastinkrementen mehrmals durchgerechnet werden. 2.2 Das Weggrößenverfahren für ein Stabwerk Im Folgenden sollen die Gleichungen und Größen aufgestellt werden, die zur statischen Berechnung eines räumlichen Stabwerkes nach der FEM benötigt werden. Dazu wird zunächst die Element-Steifigkeitsmatrix für ein gerades, räumliches und schubstarres Stabelement angeführt. Auf die Herleitung der Matrix wird an dieser Stelle verzichtet, es wird auf die Literatur verwiesen (vgl. Krätzig „Tragwerke III“ [21]). Das programmierte 2 Grundlagen der Finite-Elemente-Methode 13 Balkenelement soll die Steifigkeitsmatrix in direkter Form vorhalten. Auf die Aufstellung der Verschiebungsinterpolationsmatrix und der Verzerrung-Verschiebungsmatrix sowie die Integration über das Element wird daher nicht weiter eingegangen. Abbildung 2-2 zeigt das im Folgenden benutzte globale Koordinatensystem und die Nummerierung der Freiheitsgrade für einen (globalen) Knoten. Verschiebungen sind positiv in Richtung der Koordinatenachsen, Verdrehungen werden positiv für eine mathematisch positive Drehrichtung um die entsprechende Achse angenommen. φ y = V5 φx = V4 X Y V x = V1 V y = V2 Z φz = V6 Vz = V3 Abbildung 2-2: Vorzeichenkonvention und Nummerierung der globalen Freiheitsgrade Lokale Koordinatenachsen und Freiheitsgrade für das Stabelement werden analog zu den globalen angenommen. Abbildung 2-3 zeigt die baustatische Skizze für das räumliche, schubstarre Stabelement der Länge l. Es wird angenommen, dass sämtliche Querschnittsund Materialwerte über die Länge des Elements konstant sind, also: E, G = konstant und Iy, Iz, IT, A = konstant. Mz,l Nl Qy,l MT ,l Mz,r l My,l Qy,r x y Qz,l r MT,r z My,r Nr Qz,r l Abbildung 2-3: Baustatische Skizze des Balkenelementes Die Auswertung der allgemeinen Integralformeln nach Gleichung 11-14 führt wiederum auf das Gleichungssystem kv = f (Gleichung 15). 14 Grundlagen der Finite-Elemente-Methode Die lokale Steifigkeitsmatrix für ein schubstarres Balkenelement nach Krätzig [20] hat die folgende Form: k ⎡ EA ⎢ l ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ = ⎢⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎣⎢ − EA l 0 0 0 0 0 12 EI z l3 0 0 0 6 EI z l2 0 0 0 12 EI y l3 0 − GI T l 6 EI y l2 0 4 EI y l 0 − 12 EI z l3 − 0 0 0 0 0 0 0 0 6 EI − 2z l 4 EI z l EA l 0 0 0 0 12 EI y l3 6 EI y 0 6 EI y l2 0 2 EI y l 0 0 0 0 0 0 0 0 12 EI y symmetrisch − 0 l2 0 0 GI − T l 0 12 EI z l3 0 0 6 EI y 0 l3 GI T l l2 0 EI y l Die Vektoren v und f ⎤ ⎥ 6 EI z ⎥ ⎥ l2 ⎥ ⎥ 0 ⎥ ⎥ 0 ⎥ ⎥ ⎥ 0 ⎥ ⎥ 2 EI z ⎥ l ⎥ ⎥ 0 ⎥ ⎥ 6 EI − 2z⎥ l ⎥ ⎥ 0 ⎥ ⎥ 0 ⎥ ⎥ ⎥ 0 ⎥ ⎥ 4 EI z ⎥ l ⎦⎥ 0 [Gl. 29] beinhalten die Einträge der auf die lokalen Freiheitsgrade bezogenen Verschiebungen und Kraftgrößen: [ f ] = [N v T = [v1 K v2 ] = vx ,l f = [ f1 K T 2 l v y ,l vz , l Qy ,l Qz , l ϕ x,l ϕ y ,l ϕ z ,l M T ,l M y ,l vx , r M z ,l vy,r Nr vz , r Qy , r ϕ x, r ϕ y ,r ϕ z , r ] Qz , r M T ,r M y,r M z,r Als Formfunktionen zur Herleitung der Elementsteifigkeitsmatrix werden Hermitesche Interpolationspolynome verwendet. Für die Transformation der lokalen Freiheitsgrade auf die globalen Freiheitsgrade muss berücksichtigt werden, dass das Stabelement eine beliebige Lage im Raum haben kann. Es ist also notwendig, die lokalen Koordinatenachsen des Elementes auf das globale Koordinatensystem zu transformieren. Dieses geschieht durch eine Drehungsmatrix T, die durch die Richtungskosinus zwischen den lokalen und den globalen Achsen ausgedrückt werden. ⎡ cos( x, X ) cos( x, Y ) cos( x, Z ) ⎤ T = ⎢⎢cos( y, X ) cos( y, Y ) cos( y, Z )⎥⎥ ⎢⎣ cos( z , X ) cos( z , Y ) cos( z , Z ) ⎥⎦ [Gl. 30] In dieser Matrix bezeichnet cos(a,B) den Richtungskosinus zwischen der lokalen aAchse und der globalen B-Achse. ] 2 Grundlagen der Finite-Elemente-Methode 15 Es den Richtungscosinus gilt: cos(a,A) = cos(A,a) Daher kann die Transponierte der Drehungsmatrix auch wie folgt dargestellt werden: ⎡cos( X , x) cos( X , y ) cos( X , z )⎤ T = ⎢⎢ cos(Y , x) cos(Y , y ) cos(Y , z ) ⎥⎥ ⎢⎣ cos( Z , x) cos( Z , y ) cos( Z , z ) ⎥⎦ T [Gl. 31] Die Matrix T bezeichnet die Transformation vom globalen in das lokale Koordinatensystem, dagegen bezieht TT lokale Vektoren auf das globale System. Gleichung 15 kann mit Hilfe der Drehungsmatrix in das globale Koordinatensystem überführt werden. Das Gleichungssystem lautet damit kv = f [Gl. 32] mit den globalen Vektoren v und f , die die auf die globalen Achsen bezogenen Verschiebungen und Kraftgrößen an den Stabenden beinhalten: v T = [v1 [ K f = f1 K T v2 ] = [v X ,l ] f 2 = [S X ,l vY ,l vZ , l ϕ X ,l S Y ,l S Z ,l T X ,l ϕ Y ,l TY ,l ϕ Z ,l TZ ,l vX ,r S X ,r vY , r S Y ,r vZ , r S Z ,r ϕ X ,r T X ,r ϕY , r TY ,r TZ ,r ]. Die Berechnungsvorschrift für die Transformation ist wie folgt: ⎡T T ⎢ 0 k=⎢ ⎢0 ⎢ ⎣⎢ 0 0 TT 0 0 0 TT 0 0 ⎡T T ⎢ 0 v=⎢ ⎢0 ⎢ ⎣⎢ 0 0 TT 0 0 0 0 TT 0 0⎤ ⎥ 0⎥ ⋅v 0⎥ ⎥ TT ⎦⎥ ⎡T T ⎢ 0 f =⎢ ⎢0 ⎢ ⎣⎢ 0 0 TT 0 0 0 0 TT 0 0⎤ ⎥ 0⎥ ⋅f 0⎥ ⎥ TT ⎦⎥ ⎤ ⎡T 0 0 0 ⎤ ⎥ ⎢ ⎥ ⎥ ⋅k ⋅ ⎢0 T 0 0⎥ ⎥ ⎢0 0 T 0⎥ ⎢ ⎥ T⎥ T ⎦⎥ ⎣ 0 0 0 T⎦ 0 0 0 [Gl. 33] Um auch Stabelemente mit Stabeinwirkungen (auf den Stab wirkende Kräfte, die nicht in den Knoten angreifen) berechnen zu können, werden diese über entsprechende Volleinspannkräfte f0 als Knotenkräfte eingerechnet. ϕ Z ,r ] 16 Grundlagen der Finite-Elemente-Methode Für die Berechnung gilt (vgl. Gleichung 12) : 1 f = − ∫ H T p 0 l dξ 0 [Gl. 34] 0 mit: f0: Festhaltegrößen HT: Verschiebungsinterpolationsmatrix (Hermite-Polynome) ξ: Auf die Einheitslänge bezogene Laufvariable ξ = x/l 0 p: Vektor der Linienlasten p0 = [ qx qy qz]T Das negative Vorzeichen resultiert daraus, dass f0 die auf die Elementränder (Stabenden) wirkenden Festeinspanngrößen beschreibt, also zunächst auf der linken Seite der Gleichung 19 steht. Da bereits bei der Steifigkeitsmatrix auf die Integration verzichtet wird, soll auch der Vektor für die Festeinspannkräfte direkt vorgehalten werden. Dafür werden die Linienlasten auf bestimmte Verläufe und deren Superposition beschränkt. Die Festeinspannkräfte setzen sich (ohne Berücksichtigung von Lastausmitten oder Verformungen) wie folgt zusammen: − β x Px − ( 13 q x ,l + 16 q x ,r )l ⎡ N l0 ⎤ ⎡ ⎤ ⎡ − 13 q x l ⎤ ⎡ ⎤ ⎢ 0 ⎥ ⎢ 2 ⎥ ⎢ ⎥ ⎢ ⎥ 1 ⎢ Q y ,l ⎥ ⎢− (0,35 ⋅ q y ,l + 0,15 ⋅ q y ,r )l ⎥ ⎢ − 3 q y l ⎥ ⎢(2 β y − 3) β y Py ⎥ ⎢ Q z0,l ⎥ ⎢ − (0,35 ⋅ q z ,l + 0,15 ⋅ q z ,r )l ⎥ ⎢ − 13 q z l ⎥ ⎢ (2 β z − 3) β z 2 Pz ⎥ ⎢ 0 ⎥ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥ 0 0 ⎢ M T ,l ⎥ ⎢ ⎥ ⎢ 0 ⎥ ⎢ ⎥ ⎢ M 0 ⎥ ⎢ 1 (1,5 ⋅ q z ,l + q z ,r )l 2 ⎥ ⎢ 1 q z l 2 ⎥ ⎢ α z β z2 Pz ⋅ l ⎥ ⎢ y0,l ⎥ ⎢ 301 ⎥ ⎢ 151 ⎥ ⎢ ⎥ 2 2 2 ⎢ M z ,l ⎥ ⎢ − 30 (1,5 ⋅ q y ,l + q y ,r )l ⎥ ⎢− 15 q y l ⎥ ⎢ − α y β y Py ⋅ l ⎥ 0 f =⎢ 0 ⎥=⎢ ⎥+⎢ −1q l ⎥+⎢ ⎥ − α x Px − ( 16 q x ,l + 13 q x ,r )l Nr 3 x ⎢ ⎥ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥ 2 ⎢ Q y0,r ⎥ ⎢− (0,15 ⋅ q y ,l + 0,35 ⋅ q y ,r )l ⎥ ⎢ − 13 q y l ⎥ ⎢ (2α y − 3)α y Py ⎥ ⎢ 0 ⎥ ⎢ − (0,15 ⋅ q + 0,35 ⋅ q )l ⎥ ⎢ − 1 q l ⎥ ⎢ (2α − 3)α 2 P ⎥ z z z ⎥ z ,l z ,r ⎢ Q z ,r ⎥ ⎢ ⎥ ⎢ 3 z ⎥ ⎢ 0 ⎢ M T ,r ⎥ ⎢ ⎥ ⎢ 0 ⎥ ⎢ ⎥ 0 0 ⎢ 0 ⎥ ⎢ ⎥ ⎢ 1 ⎢ ⎥ 2 2 2⎥ 1 ⎢ M y ,r ⎥ ⎢ − 30 (q z ,l + 1,5 ⋅ q z ,r )l ⎥ ⎢ − 15 q z l ⎥ ⎢ − α z β z Pz ⋅ l ⎥ ⎢ M 0 ⎥ ⎢ 301 (q y ,l + 1,5 ⋅ q y ,r )l 2 ⎥ ⎢ 151 q y l 2 ⎥ ⎢ α y2 β y Py ⋅ l ⎥ ⎦ ⎦ ⎣ ⎦ ⎣ ⎣ z ,r ⎦ ⎣ (1) (2) [Gl. 35] (3) Hierin bezeichnet Anteil (1) linear verlaufende Streckenlasten mit dem Startwert qi,l am linken Stabende und dem Endwert qi,r am rechten Stabende. Anteil (2) berücksichtigt einen parabelförmigen Verlauf, bei dem qi den Maximalwert in Stabmitte angibt. Anteil (3) beschreibt die Festhaltegrößen für eine Last Pi, die in beliebigem Abstand a < l vom linken 2 Grundlagen der Finite-Elemente-Methode 17 Stabende entfernt ist (α = a/l, β = 1 – α). Frei im Raum angreifende Stablasten müssen zunächst auf die lokalen Stabachsen projiziert werden. Sämtliche Lasten sind positiv entlang den Stabachsen entsprechend der Vorzeichendefinition. Bei der späteren Auswertung der Schnittgrößenverläufe und Stabwerksverformungen müssen die örtlichen Stabeinwirkungen ebenfalls mitbeachtet und ausgewertet werden. az My,l0 Pz qz My,r0 qx Nl0 Qz,l0 Nr0 Px x ax Qz,r0 l z ay qy Py Mz,l0 Mz,r0 qx Nl0 Nr0 Px x ax Qy,l0 Qy,r0 y Abbildung 2-4: Bestimmung der Festhaltekraftgrößen am Balkenelement Aus Zeitgründen wurden im Beispielprogramm (Kapitel 8) nur konstant verlaufende Linienlasten berücksichtigt, d.h. Anteil (1) mit qi,l = qi,r. Für den Vektor der Festeinspanngrößen f0 gilt dieselbe Transformationsvorschrift wie für den Vektor der Randkraftgrößen f (vgl. Gleichung 33). Die globalen Festeinspanngrößen f 0 werden mit den globalen steifigkeitsinduzierten Randkraftgrößen zusammengefasst: f + f 0 = f tot ⇒ Für die Berechnung kv + f 0 = f tot des gesamten [Gl. 36] Stabwerkes werden nun die globalen Randkraftgrößen und Festeinspannkräfte sowie die Koeffizienten der Steifigkeitsmatrix aller Stabelemente – entsprechend der Inzidenzen – auf die möglichen Systemfreiheitsgrade 18 Grundlagen der Finite-Elemente-Methode bezogen. Lagerbindungen bleiben bei diesem Schritt noch unberücksichtigt. Man erhält das Gesamtgleichungssystem der Ordnung N (N = Anzahl der gesamten Systemfreiheitsgrade). ˆV ˆ + Fˆ 0 = Fˆ K tot [Gl. 37] Aus Gleichgewichtsgründen gilt: Pˆ − Fˆ tot = 0 ⇒ Fˆ tot = Pˆ [Gl. 38] mit: Pˆ : Vektor der an den Knoten angreifenden äußeren Kraftgrößen (Knotenlasten und Lagerkräfte) Daraus ergibt sich das inhomogene lineare Gleichungssystem ˆV ˆ = Pˆ − Fˆ 0 K [Gl. 39] Die Nummerierung der Systemfreiheitsgrade erfolgt so, dass zunächst alle aktiven (freien) und dann die durch Lagerbindungen gefesselten Freiheitsgrade berücksichtigt werden. Durch eine derartige Umstellung des Gleichungssystemes kann man die Vektoren der System-Freiheitsgrade, der System-Kraftgrößen wie auch die System-Steifigkeitsmatrix entsprechend partitionieren. ˆV ˆ = Pˆ − Fˆ 0 ⇒ ⎡ K K ⎢K T ⎣ c K c ⎤ ⎡ V ⎤ ⎡ P ⎤ ⎡F 0 ⎤ ⋅ = −⎢ ⎥ K cc ⎥⎦ ⎢⎣Vc ⎥⎦ ⎢⎣Pc ⎥⎦ ⎣Fc0 ⎦ [Gl. 40] mit: V: Vektor der aktiven Freiheitsgrade Vc: Vektor der durch Lagerbindung gefesselten Freiheitsgrade P: Vektor der mit den aktiven Freiheitsgraden korrespondierenden Knotenlasten. Pc: Lagerkraftgrößen. Fo: Vektor der mit den aktiven Freiheitsgraden korrespondierenden System-Festeinspannkraftgrößen Fc0 : Vektor der mit den gefesselten Freiheitsgraden korrespondierenden System-Festeinspannkraftgrößen Für ein Stabwerkssystem sind üblicherweise gegeben: • die äußeren Knotenlasten P der aktiven Freiheitsgrade, • die Verschiebungsgrößen Vc der gefesselten Freiheitsgrade und • die System-Festeinspannkraftgrößen Fo und Fc0 . 2 Grundlagen der Finite-Elemente-Methode 19 Die obere bzw. untere Zeile des partitionierten Gleichungssystems kann nun nach den unbekannten Größen aufgelöst werden. Es folgt dann für den Vektor V der aktiven Freiheitsgrade: KV + K c Vc = P − F 0 ⇒ KV = P − K c Vc − F 0 ⇒ V = K −1 (P − K c Vc − F ) [Gl. 41] Die aktiven Verschiebungsgrößen können durch Lösen des linearen Gleichungssystems oder durch Multiplikation mit der Invertierten der Matrix K ermittelt werden. Aus der unteren Seite des partitionierten Gleichungssystems kann der Vektor Pc der Lagerkraftgrößen ermittelt werden. K cT V + K cc Vc = Pc − Fc0 ⇒ Pc = K cT V + K cc Vc + Fc0 [Gl. 42] Damit sind alle unbekannten Größen des Systems bestimmt. In der Nachlaufrechnung folgt nun • die Rücktransformation der globalen System-Verschiebungsgrößen V auf die lokalen Element-Randverschiebungsgrößen v bzw. v, • die Berechnung der Element-Randkraftgrößen f durch Multiplikation von v mit der Element-Steifigkeitsmatrix k und das Einrechnen der Festeinspanngrößen • die Anpassung der Element-Randkraftgrößen an die Vorzeichenkonvention der Stabstatik (Vorzeichenwechsel am linken Stabende) und • die Konstruktion der Schnittgrößenverläufe zwischen den Knoten unter Beachtung der örtlichen Stabeinwirkungen. Mit diesen Ergebnissen können die Schnittgrößenverläufe über die einzelnen Elemente des Stabwerkes sowie die Verformungen des Gesamttragwerkes dargestellt werden. 20 Software-Entwurf 3 Software-Entwurf 3.1 Verschiedene Entwurfsverfahren In der Praxis nehmen Programme meist einen Umfang an, bei dem die Überschaubarkeit nicht mehr ohne weiteres gewährleistet ist. Deshalb ist eine Zerlegung der Gesamtaufgabe in kleinere Teile, die unabhängig voneinander verstanden und bearbeitet werden können, zweckmäßig. Für diese Zerlegung zur Bewältigung der Komplexität eines Systems wurden viele verschiedene Design- und Analysemethoden entwickelt. In der Literatur gibt es unterschiedliche Ansätze die verschiedenen Entwurfsverfahren zu klassifizieren und zu unterscheiden. Grundsätzlich kann man eine Einteilung der Designmethoden in drei Kategorien vornehmen: • Streng hierarchisch strukturiertes Design • Datenorientiertes Design • Objektorientiertes Design Wie bereits erwähnt, gibt es für das Design eines komplexen Software-Systems kein Universalrezept, und es gibt keine „beste“ Designmethode. Daher ist es nötig, sich zu überlegen, mit welchem Design-Konzept sich die Anforderungen an ein bestimmtes Software-System am besten erfüllen lassen [5]. Im Folgenden werden die verschiedenen Entwurfsverfahren kurz vorgestellt und ihre Eignung für den Entwurf eines Programmsystems zur allgemeinen Tragwerksanalyse (hauptsächlich FEM) diskutiert. Die vorgestellten Entwurfsverfahren sind mehr oder weniger eng mit verschiedenen Programmierstilen und -sprachen verbunden. Auf die Eigenschaften der verschiedenen Programmiersprachen und ihre Eignung zur Umsetzung eines Entwurfes wird in Kapitel 5 näher eingegangen. 3.1.1 Streng hierarchisch strukturiertes Design (prozedural) Die unterschiedlichen Varianten des streng hierarchisch strukturierten Designs (auch Top-Down-Entwurf) basieren auf einer algorithmischen Zerlegung. Dies bedeutet, dass das Problem in einen Baum aus Teilproblemen aufgeteilt wird, die entlang der Baumtopologie von der Wurzel aus bearbeitet werden. Die einzelnen Teilprobleme werden im Programm als Funktionen mit einer Reihe von Funktionsargumenten und einem Rückgabewert abgebildet. Das streng hierarchisch strukturierte Design ist das am meisten verbreitete und älteste der drei Entwurfsverfahren [28]. Schätzungen gehen davon aus, dass auf diese Weise 3 Software-Entwurf 21 Probleme bis zu einer Größenordnung von 100.000 Programmzeilen gut bewältigt werden können [28]. Heutzutage sind die meisten Programmiersprachen prozedural, zwei ihrer verbreitetsten Vertreter sind Fortran und C. 3.1.2 Datenorientiertes Design (funktional) Der datenorientierte Entwurf konzentriert sich hauptsächlich auf den Datenfluss innerhalb eines Problems. In einem ersten Schritt werden die einzelnen Informationsquellen und –senken einer Anwendung ermittelt. Danach werden Untersuchungen über die Datenumsätze zwischen den gefundenen Anwendungskomponenten durchgeführt. Mittels der gewonnenen Erkenntnisse über die Informationsflüsse gelangt man zu einer Programmstruktur. Ein wesentlicher Nachteil der Methode besteht darin, dass dieser Übergang nicht unmittelbar möglich ist, d.h. es existiert keine eindeutige und vollständige Umsetzungsmöglichkeit der Datenflüsse in Programmstrukturen. Allerdings können mit dieser Methode auch komplexe Systeme bewältigt werden. Das Verfahren wird besonders zum Entwurf von Informations-Managementsystemen (z.B. Flugbuchungssystemen) eingesetzt, in denen Datenflüsse gegenüber anderen Komponenten dominieren und bei denen zeitkritischen Ereignissen kaum Beachtung geschenkt werden muss. Aufgrund der Einbußen in der Ausführungsgeschwindigkeit ist das datenorientierte Design unüblich für intensive numerische Berechnungen, es wurde jedoch bereits für FE-Programme eingesetzt [28]. Eine verbreitete funktionelle Programmiersprache ist z.B. Lisp. 3.1.3 Objektorientiertes Design Objektorientierte Repräsentationen sind ein Hybrid. Objektorientierte Entwurfsverfahren versuchen Anwendungen durch eine Sammlung von miteinander kommunizierenden, hierarchischen Objekten abzubilden. Jedes Objekt ist die Instanz einer Klasse und stellt eine jeweils abgeschlossene Einheit mit gekapselten Informationsbestand und darauf operierenden Algorithmen dar. Diese Algorithmen sind für andere Objekte durch feste Schnittstellen zugänglich [10]. Die Klasse ist wiederum ein Element in einer Klassenhierarchie. Der fundamentale Baustein im objektorientierten Design ist also das Objekt, nicht die Funktion oder die Datenstruktur [5]. Das Abstraktionslevel eines Objektes ist im Vergleich zu dem eines Algorithmus ungleich höher. Das objektorientierte Design bietet sich an für Programmsysteme, bei den Daten und Funktionen gleichviel Bedeutung zukommt. Die Entwicklung von Software auf der Grundlage objektorientierter Verfahren ist vergleichsweise neu, besonders wenn ihre Verwendung in großen, industriellen Projekten 22 Software-Entwurf betrachtet wird. In den letzen Jahren wurden diese Verfahren vermehrt auch im ingenieurwissenschaftlichen Bereich propagiert, u.a. für die Realisierung von FEMProgrammen (z.B. Dubois-Pelerin et al. [11]+[12]). Populäre Vertreter von objektorientierten Programmiersprachen sind Smalltalk und C++. 3.2 Vergleich und Auswertung Grundsätzlich sind alle drei Entwurfsverfahren für ein Programmsystem zur Tragwerksanalyse denkbar und bereits verwendet worden. Jedes dieser Programmierparadigmen hat seine Vor- und Nachteile. Je nachdem welche Gewichtung man den einzelnen Kriterien zur Auswahl des Entwurfsverfahren gibt und welche Ansprüche man an das „fertige“ Software-System stellt, wird man unterschiedliche Design-Methoden wählen. Im Folgenden soll die Eignung der vorgestellten Verfahren für den Entwurf eines Programmsystems zur Tragwerksanalyse verglichen werden. Es wird vor allem auf das prozedurale Design - das übliche Verfahren für numerische Programme – und auf das objektorientierte Paradigma eingegangen. Für das zu erarbeitende Programmsystem soll vor allem die Portabilität und die Erweiterbarkeit im Vordergrund stehen, es wird ein globaler, modular aufgebauter Programmentwurf gefordert. Die Portabilität eines Programms ist hauptsächlich abhängig von der Wahl der Programmiersprache und daher nur indirekt von dem gewählten Entwurfsverfahren abhängig. Dagegen ist die Erweiterbarkeit eines Programmsystems etwas, das schon beim Design der Architektur berücksichtigt werden muss. Damit ein Entwurf ausbaubar ist, muss die bestehende Programmarchitektur modular aufgebaut sein und klar definierte Schnittstellen bereithalten. Außerdem sollte die Architektur logisch strukturiert und für jeden Benutzer einfach zu verstehen sein. Dieses lässt sich vor allem durch zwei Mittel erreichen: eine durchgehende Dokumentation der Architektur und des Programmcodes und eine sich selbst erklärende und durchschaubare Aufteilung des komplexen Systems in logische Untereinheiten. Das „sich-selbst-Erklären“ eines Programmsystems wird vor allem durch den objektorientierten Entwurf gefördert, denn: „Das beste Modell eines Problemfeldes ist das Problemfeld selbst.“ [28] Der Mensch betrachtet seine Umwelt als eine Sammlung von Personen, Gegenständen usw., die bestimmte Eigenschaften haben, und sich durch bestimmte gegenseitige Interaktionen auszeichnen. Aus diesen Überlegungen folgt, dass der einfachste Weg eine Anwendung zu entwerfen darin besteht, deren natürliche oder abstrakte Konzepte durch die 3 Software-Entwurf 23 Imitation der menschlichen Begriffsbildung zu ermitteln [28]. Für ein FEMProgrammsystem zur Tragwerksanalyse ergibt sich z.B. eine Einteilung in Objekte wie etwa Element, Knoten und Material. Diese Einteilung ist logisch nachvollziehbar und wird durch das Problemfeld bestimmt, dass heißt sie ist weitgehend unabhängig vom umsetzenden Programmierer. Die Schwierigkeit bei konventionellen (prozeduralen) Programmen ist, dass die Unterteilung in die verschiedenen Algorithmen zum großen Teil willkürlich gewählt werden kann. Zusätzlich ist ein streng sequentieller Top-Down-Entwurf meist nicht direkt umsetzbar. Einzelne Algorithmen werden durch Schleifen und GoTo – Anweisungen ineinander verschachtelt. Dadurch wird das Programmsystem schnell unüberschaubar, und ohne weitgehende Dokumentation nicht mehr nachvollziehbar. Ein weiterer großer Unterschied zwischen einem konventionellen und einem objektorientierten Programm besteht in der Behandlung und Speicherung der Daten. In einem konventionellen (hierarchisch strukturierten) Programm kann fast jede Funktion auf alle Daten zugreifen und diese manipulieren, die Daten sind passiv [1]. Das birgt große Nachteile, da durch die zwangsläufige Zuordnung einer Datenstruktur zu mehreren Funktionen ihre Beschreibung über die Systemstruktur verstreut wird. Im Lebenszyklus eines Systems sind die Funktionen im Allgemeinen die sich am häufigsten ändernden Teile der Software. Sind aufgrund veränderter Anforderungen Modifikationen der Datenstruktur nicht zu umgehen, ziehen diese durch die Verflechtung der Daten mit den Funktionen nur schwer zu übersehende Änderungen verschiedenster Systemteile nach sich. Oft ist die komplette Überarbeitung der funktionsorientierten Systemstruktur notwendig. Der Softwareentwickler hat die mühsame Aufgabe, durch alle Funktionen hindurch die Konsistenz des Programms nach Änderungen zu sichern [9]. In einem objektorientierten Programm werden die Daten gekapselt, ausgehend von der Prämisse, dass die Datenstruktur der stabilere Teil eines Programms ist. Man spricht von aktiven Daten, da sich Daten immer in Objekten manifestieren und diese nur die Ausführung spezifischer Methoden zulassen. Da alle Datenmanipulationen durch das Objekt selbst erfolgen, ist unmittelbar klar, wo die Fehlerquelle liegt, falls Dateninkonsistenz auftritt. Fehlersuche und –behebung ist auf ein einziges Objekt beschränkt. 24 Software-Entwurf Hauptprogramm Dateneingabe (Elemente, Knoten, Lasten) Gesamtsteifigkeitsmatrix erstellen Aufstellen des Lastvektors Berechnung des Systems Daten Zugriff auf Daten in einem konventionellen Programm Element Gesamtsystem Knoten Kapselung der Daten in einem objektorientierten Programm Abbildung 3-1: Datenzugriff in prozeduralen und objektorientierten Programmen (aus [1]) In einem Programm zur Tragwerksanalyse kann eine Änderung der Datenstruktur z.B. in der Umstellung der Abspeicherung einer Matrix als Bandmatrix oder Skyline-Matrix bestehen. Jede Funktion, die auf eine Matrix zugreift (Einlesen der Elementmatrizen, Lösen des Gleichungssystems etc.), muss nun abgeändert werden, um die neue Datenstruktur verarbeiten zu können. In einem objektorientierten Programm wird eine Matrix durch eine eigene Klasse implementiert. Auf die Matrixelemente kann nur mit den von der MatrixKlasse zur Verfügung gestellten Methoden zugegriffen werden. Eine Änderung der Speicherung der Matrixelemente wirkt sich daher nur in der Implementierung der Methoden aus, die Schnittstelle der Klasse an sich bleibt konstant. Das Konzept der Polymorphie (vgl. Kapitel 4.2.6) bietet darüber hinaus die Möglichkeit, Methoden bereits bestehender Klassen zu erweitern, ohne das die bereits 3 Software-Entwurf 25 vorhandene Implementierung verändert werden muss. Derselbe Methodenaufruf kann z.B. bei der Übergabe unterschiedlicher Parameter (Typ, Anzahl etc.) unterschiedliche Aktionen hervorrufen. Das Objekt ist also eine geschlossene Informationseinheit. Derart strukturiertes Wissen erhöht die Modularität und folglich auch die Transparenz und Wiederverwendbarkeit der Repräsentation [10]. Durch die objektorientierte Vorgehensweise verspricht man sich, den Entwicklungsprozess von Programmen mit einer Größe von weit über 100.000 Zeilen beherrschbar zu machen. Systeme dieser Größe sind im Bereich der Tragwerksanalyse durchaus üblich [28]. Die Konzepte der objektorientierten Programmierung beinhalten also viele vorteilhafte Strukturen, die in einem konventionellen Programm nur schwer umsetzbar sind. Software wird wiederverwendbar, Schnittstellen werden konsistenter und es entstehen geringere Wartungskosten. Zusätzlich kann durch die häufigere Verwendung und damit durch das häufigere Testen dieser Softwarekomponenten mit einer geringeren Fehlerträchtigkeit gerechnet werden. Ein großer Nachteil ist, dass die Ausführungszeit objektorientierter Programme gegenüber streng hierarchisch strukturierten ansteigt. Durch das Botschaften-Konzept und eventuell mehrfach indirektes Aufrufen von Methoden entsteht ein Overhead an zusätzlichen Operationen. Der zusätzliche interne Verwaltungsaufwand für den Zugriff auf Methoden ist nicht zu vernachlässigen. Das ist für rechenintensive Programme ein nicht zu unterschätzender Nachteil [9]. Weiterhin steigt der Programmumfang sowohl des Quelltextes als auch des übersetzten Programms an. Durch Hierarchisierung (vgl. Kapitel 4.2.5) steigt die Komplexität des Programms. Allerdings kann man festhalten, dass die Komplexität z.B. einer Vererbungsstruktur deutlich einfacher handhabbar ist als die Komplexität von hierarchisch strukturierten Funktionen oder Prozeduren. Trotz der im Vergleich zu den prozeduralen Ansätzen unbestreitbar erhöhten Flexibilität wird immer wieder festgestellt, dass in vielen Situationen die erwartete und erwünschte Flexibilität nicht erreicht werden kann. So sind beispielsweise Erweiterungen in den Klassenhierarchien, die nicht bereits in der Anfangsphase des Entwurfs berücksichtigt wurden, nur mit großem Aufwand durchzuführen. Eine zu allgemeine Konzeption von Beginn an führt jedoch zu unübersichtlichen und laufzeitineffizienten Programmen. Gleichzeitig steigt das vom Entwickler erwartete Wissen über Programmstruktur und – hierarchie überproportional an. Das Kernproblem der Anwendung objektorientierter 26 Software-Entwurf Techniken für numerische Simulationen liegt demzufolge in der angemessenen programmtechnischen Darstellung der Abhängigkeiten zwischen den Algorithmen und der zugehörigen Datenstruktur. Chudoba [8] propagiert in seinem Artikel den Einsatz generischer Techniken (algorithmusorientierter Ansatz), die dieses Problem lösen können. Er beschreibt den Einsatz von metaobjects, mit deren Hilfe z.B. die Instantiierung der Objekte oder die Festlegung der Übergabe- und Rückgabeparameter von Funktionen zur Laufzeit und von der Auswertung getrennt stattfinden kann. Somit werden z.B. alle Matrizen einer Berechnung mit den korrekten Dimensionen instanziiert, bevor die eigentliche Berechnung stattfindet. Dieser Ansatz erhöht allerdings die Komplexität des Programmsystems wieder ungemein. Im Folgenden wird der objektorientierte Ansatz für den Entwurf eines Programmsystems gewählt. Dieser bietet für ein Programmsystem zur Tragwerksanalyse viele Vorteile gegenüber dem steng hierarchisch strukturierten Design. Die Programmarchitektur wird übersichtlicher und leichter verständlich. Eine Erweiterung oder Anpassung eines bestehenden Programms für spezielle Aufgabenstellungen wird durch das dezentralisierte Konzept unterstützt. Das Einfügen von neuen Klasen wird möglich. Bestehende Klassen können in einem anderen Kontext wieder- und weiterverwendet werden ohne ihre Implementierung zu kennen, da die Schnittstellen konstant bleiben. Die Datenverwaltung wird übersichtlich, da jedes Objekt (z.B. Finites Element) seine eigenen Daten speichert und verwaltet. 4 Objektorientierte Analyse und Design 4 27 Objektorientierte Analyse und Design Als objektorientierte Analyse (OOA) wird der Prozess bezeichnet, der die Daten, Prozesse und Steuerung eines objektorientierten Programms bestimmt. Die Daten entsprechen den Objekten bzw. Klassen und deren Struktur. Prozesse beschreiben das lokale Verhalten von Methoden, die Steuerung legt das globale Verhalten fest. Die Analyse ist zunächst unabhängig von einer bestimmten Programmiersprache. Dagegen legt der objektorientierte Entwurf (OOD) die Objekte und deren Attribute fest. Er bestimmt weiterhin die Sichtbarkeit der Objekte untereinander und die Schnittstellen. In der Praxis ist eine strenge Trennung zwischen objektorientierter Analyse und objektorientiertem Entwurf kaum einzuhalten. Beide Prozesse werden unter dem Begriff objektorientierte Analyse und Design (OOAD) zusammengefasst. Den neuesten Stand der Entwicklung objektorientierter Analyse- und Entwurfsmethoden stellt die Unified Modeling Language (UML) dar. Mehrere Protagonisten namhafter Techniken (Booch, Rumbaugh und Jacobson) arbeiten inzwischen zusammen und haben sich der Entwicklung der UML verschrieben [9]. In Kapitel 4.1 wird zunächst die UML als Notation für objektorientierte Strukturen vorgestellt. Die Konzepte der Objektorientierung werden in Kapitel 4.2 dargestellt und an Beispielen erläutert, die bereits dem Problemfeld der FEM entstammen und in UML notiert sind. 4.1 Unified Modeling Language (UML) 4.1.1 Ziele der UML UML ist eine Sprache zur Spezifikation, Visualisierung, Konstruktion und Dokumentation von Softwaresystemen. Ihr Ziel ist insbesondere die Unterstützung objektorientierter und komponentenbasierter Systeme. Weitere Ziele beim Entwurf waren 1. eine ausdrucksstarke visuelle Notation von Modellen zu geben, 2. die Erweiterbarkeit und Spezialisierbarkeit der Sprache selbst zu erreichen, 3. die Unabhängigkeit von Programmiersprachen, 4. eine formale Basis für die Modellierung zu schaffen, 5. Chancen für eine Vergrößerung des Marktes für Werkzeuge in der objektorientierten Analyse und Entwurf sowie 6. die Unterstützung von Frameworks (Anwendungs-„Rahmen“), Mustern und Komponenten. 28 Objektorientierte Analyse und Design Dabei will UML die Notation und deren Semantik beschreiben, nicht jedoch bestimmen, mit welchem Prozess dieses Ziel erreicht wird. Neben den Prozessen deckt UML Programmiersprachen und Werkzeuge ausdrücklich nicht ab. Da es sich um einen Formalismus handelt, wird davon ausgegangen, dass die Transformation eines entsprechenden Modells in eine beliebige objektorientierte Programmiersprache möglich ist [9]. Programmiersprachen für die Umsetzung des Entwurfes aus Kapitel 5 werden ausführlich in Kapitel 6 diskutiert. 4.1.2 Bestandteile der UML Im Folgenden werden die Kernkonzepte der UML zusammen mit ihrer grafischen Notation kurz vorgestellt. Für die Beschreibung des Konzeptes für ein Programmsystem zur Tragwerksanalyse werden nicht alle Bestandteile der UML benötigt, der Vollständigkeit halber werden aber alle kurz vorgestellt. Es werden dabei die Darstellungen verwendet, wie sie von Booch, Rumbaugh und Jacobson 1999 in „Das UML-Benutzerhandbuch“ [6] festgelegt werden. Begriffe aus der Objektorientierung wie Objekt, Klasse, Attribute, Methoden, Hierarchie etc. werden in Kapitel 4.2 noch grundlegend definiert, hier soll zunächst die Vorstellung der grafischen Notation stattfinden. Eine Kurzübersicht über die Notationen in der UML (aus [26]) wird zusätzlich in den Anhang gestellt. Das Vokabular der UML umfasst drei Arten von Bestandteilen: Dinge, Beziehungen und Diagramme. Dinge sind die Abstraktionen des Modells, man unterscheidet zwischen den statischen und dynamischen Bestandteilen, Gruppierungen und Kommentaren. • Strukturelemente sind die statischen Teile eines Modells und repräsentieren konzeptionelle oder physische Elemente. Dazu zählen o Klassen ElementFEM stiffnessMatrix massMatrix ... computeStiffnessMatrix() computeMassMatrix() assembleStiffnessMatrix() ... Æ Name der Klasse Attribute der Klasse Methoden der Klasse Abbildung 4-1: Klassen 4 Objektorientierte Analyse und Design 29 o Schnittstellen | Interface Abbildung 4-2: Schnittstellen o Kollaborationen (Interaktionen mit strukturellen und verhaltensorientierten Dimensionen) Verantwortlichkeitskette Abbildung 4-3: Kollaborationen o Anwendungsfälle (Beschreibung einer Menge aufeinanderfolgender Aktionen, die ein beobachtbares Ergebnis hervorbringt) Auftrag erteilen Abbildung 4-4: Anwendungsfälle o aktive Klassen (Klasse deren Objekte Steuerungsaktivitäten in Gang setzen können) EreignisManager ... throw() dismiss() ... Abbildung 4-5: Aktive Klassen o Komponenten (physisches Paket von logischen Elementen wie z.B. Klassen, Schnittstellen und Kollaborationen). Profilbibliothek Abbildung 4-6: Komponenten 30 Objektorientierte Analyse und Design o Knoten (Ein zur Laufzeit vorhandenes physisches Element, das eine Rechnerresource repräsentiert und im Allgemeinen einen Speicher und oft auch Rechenkapazität besitzt.) Server Abbildung 4-7: Knoten • Verhaltensweisen sind die dynamischen Bestandteile eines Modells, mit zwei Hauptarten o Interaktion (Verhaltensweise, die eine Menge von Nachrichten umfasst, welche von einer Menge von Objekten in einem bestimmten Kontext zum Erreichen eines bestimmten Zweckes ausgetauscht werden.) Anzeigen() Abbildung 4-8: Nachrichten o Automat (Spezifikation der Folge von Zuständen eines Objektes oder einer Schnittstelle) Warten Abbildung 4-9: Zustände • Gruppierungen (Pakete zur Organisation) Geschäftsregeln Abbildung 4-10: Pakete 4 Objektorientierte Analyse und Design • 31 Kommentare (Notizen) Notiz Abbildung 4-11: Notizen In der UML gibt es vier Arten von Beziehungen: • Abhängigkeit (semantische Beziehung zwischen zwei Gegenständen, wobei eine Änderung des unabhängigen Gegenstandes die Semantik des abhängigen Gegenstandes beeinflusst.) Abbildung 4-12: Abhängigkeiten • Assoziation (Strukturbeziehung, die eine Menge von Objektbeziehungen beschreibt. Sie kann gerichtet sein, eine Beschriftung, Multiplizitäten (mögliche Anzahl der beteiligten Objekte), Rollennamen u.ä. enthalten.) 1..* Element 1 Struktur Abbildung 4-13: Assoziationen • Generalisierung (Beziehung zwischen dem Allgemeinen und dem Speziellen) Abbildung 4-14: Generalisierungen • Realisierung (z.B. zwischen Schnittstelle und ausführender Stelle) Abbildung 4-15: Realisierungen 32 Objektorientierte Analyse und Design Diagramme sind die verschiedenen Sichtweisen einer Architektur. Man unterscheidet zwischen Diagrammen, die die statischen und die dynamischen Sichtweisen eines Systems darstellen. Strukturdiagramme (statische Sichtweise) Verhaltensdiagramme (dynamische Sichtweise) 1. Klassendiagramm 1. Anwendungsfalldiagramm 2. Objektdiagramm 2. Sequenzdiagramm 3. Komponentendiagramm 3. Kollaborationsdiagramm 4. Einsatzdiagramm 4. Zustandsdiagramm 5. Aktivitätsdiagramm Tabelle 4-1: Diagramme der UML Diese neun Arten von Diagrammen definieren die UML. Dasselbe Ding kann in einem System mehrfach in demselben oder in verschiedenen Diagrammen auftreten. Jedes Diagramm bietet eine Sicht auf die Elemente, aus denen das System besteht [6]. Strukturdiagramme • Ein Klassendiagramm zeigt eine Menge von Klassen, Schnittstellen und Kollaborationen sowie deren Beziehungen, es ist der häufigste Diagrammtyp. Klassendiagramme stellen die statische Entwurfssicht eines Systems dar. Enthalten sie aktive Klassen, stellen sie die statische Prozesssicht eines Systems dar. • Ein Objektdiagramm zeigt eine Menge von Objekten und ihre Beziehungen. Es repräsentiert statische Momentaufnahmen der Instanzen von Gegenständen aus Klassendiagrammen und stellt damit wie die Klassendiagramme die statische Entwurfsoder Prozesssicht eines Systems dar, allerdings aus der Perspektive tatsächlicher oder prototypischer Fälle. • Ein Komponentendiagramm zeigt die Organisation und die Abhängigkeiten einer Menge von Komponenten. Solche Diagramme stellen die statische Implementierungssicht eines Systems dar. Sie hängen insofern mit Klassendiagrammen zusammen, als eine Komponente sich üblicherweise auf eine oder mehrere Klassen, Schnittstellen oder Kollaborationen abbilden lässt. • Einsatzdiagramme zeigen die Konfiguration der im Prozess befindlichen Knoten zur Laufzeit sowie der auf ihnen existierenden Komponenten. Solche Diagramme stellen die 4 Objektorientierte Analyse und Design statische Einsatzsicht einer 33 Architektur dar. Sie hängen insofern mit Komponentendiagrammen zusammen, als ein Knoten üblicherweise eine oder mehrere Komponenten einschließt. Verhaltensdiagramme • Ein Anwendungsfalldiagramm organisiert die Verhaltensweisen eines Systems. Es zeigt eine Menge von Anwendungsfällen sowie Akteuren und ihren Beziehungen. Anwendungsfalldiagramme stellen die statische Anwendungsfallsicht eines Systems dar. • Sequenz- und Kollaborationsdiagramme sind Interaktionsdiagramme. Sie zeigen eine Interaktion, die aus einer Menge von Objekten und deren Beziehungen einschließlich der unter ihnen versendeten Nachrichten besteht. Interaktionsdiagramme stellen die dynamische Sicht eines Systems dar. Beim Sequenzdiagramm steht die zeitliche Abfolge der Nachrichten im Vordergrund, beim Kollaborationsdiagramm die strukturelle Organisation der Objekte. • Ein Zustandsdiagramm zeigt einen aus Zuständen, Zustandsübergängen, Ereignissen und Aktivitäten bestehenden Automaten. Besondere Bedeutung kommt ihm beim Modellieren des Verhaltens einer Schnittstelle, Klasse oder Kollaboration zu. Das nach Ereignissen geordnete Verhalten eines Objektes steht im Vordergrund. Ein Aktivitätsdiagramm ist ein Sonderfall des Zustandsdiagramms, der den Fluss von einer Aktivität zur anderen innerhalb eines Systems zeigt. 4.2 Konzepte und Definitionen der objektorientierten Programmierung Um das Prinzip der Objektorientierung zu verstehen, müssen zunächst Definitionen für einige Begriffe gegeben werden. Im folgenden Abschnitt werden die wichtigsten Begriffe und Konzepte des objektorientierten Designs näher erläutert. Die Definitionen sind in der Literatur oft nicht einheitlich. Die jüngste Literatur bezieht sich zunehmend auf die Objektdefinition, die auch der UML zugrunde liegt. Diese Definition wird auch im Folgenden zugrundegelegt. Soweit notwendig soll die Anwendung der Konzepte der objektorientierten Programmierung anhand von Beispielen für die Anwendung auf die Methode der finiten Elemente erläutert werden. Die Notation der Beispiele orientiert sich an der bereits vorgestellten grafischen Darstellung der UML. 34 Objektorientierte Analyse und Design Zunächst werden die Begriffe Objekt, Klasse, Methode und Attribut definiert. Dann werden die Hauptelemente des Objektmodells vorgestellt. Diese sind nach Booch [5]: • Abstraktion • Kapselung • Modularität • Hierarchie Hauptelement bedeutet, dass ein Modell, in dem eines dieser Elemente fehlt, nicht im engeren Sinne objektorientiert ist. Dazu gibt es drei weniger wichtige Konzepte, die nicht speziell objektorientiert sind: • Typisierung • Nebenläufigkeit • Persistenz Statt der Typisierung wird das (allgemeinere) Konzept der Polymorphie erläutert, zusätzlich wird auf die Generizität eingegangen. 4.2.1 Basisdefinitionen 4.2.1.1 Objekt Ein Objekt abstrahiert einen Teil des Problembereichs. Es repräsentiert eine Gruppierung von Informationen, sowie die Beschreibung, wie diese Informationen behandelt werden sollen. Es repräsentiert beispielsweise ein Ding, eine Person, einen Begriff, einen Vorgang, einen Zusammenhang, ein Ereignis, eine Beziehung, ein abstraktes Konzept oder ein Ergebnis. Booch [5] definiert ein Objekt folgendermaßen: • Ein Objekt hat einen Status (Zustand, Daten), es weist ein wohldefiniertes Verhalten auf (Operationen, Methoden) und es besitzt eine eindeutige Objektidentität. • Ein Objekt kapselt seine Informationen (Daten) als Attribute und bietet Interaktionen als Dienste (Operationen, Methoden) an. Ein Objekt ist in der programmtechnischen Umsetzung immer die Instanz einer Klasse. Als aktive Objekte bezeichnet man Objekte, die einen Prozess oder Thread1 besitzen und Kontrollaktivitäten initiieren können . 1 Ein Prozess ist ein schwergewichtiger Kontrollfluss, der nebenläufig mit anderen Prozessen ausgeführt werden kann. Ein Thread ist ein leichtgewichtiger Kontrollfluss, der nebenläufig mit anderen Threads im gleichen Prozess ausgeführt werden kann. 4 Objektorientierte Analyse und Design 4.2.1.2 35 Klasse Unter der Klasse versteht man eine Beschreibung für alle Objekte, die dieselbe Struktur aufweisen. Eine Klasse spezifiziert demnach die gemeinsamen Eigenschaften und das gemeinsame Verhalten der von ihr erzeugten Objekte (Instanz). Eine Klassenbeschreibung umfasst: • den Namen der Klasse • den internern Aufbau der Objekte dieser Klasse • eine Beschreibung aller Methoden, die auf Objekte dieser Klasse angewendet werden können. Eine Klasse implementiert eine oder mehrere Schnittstellen. Dazu gehören insbesondere alle Methoden, die öffentlich (d.h. von anderen Klassen oder Funktionen) aufgerufen werden können. Die Implementierungen dieser Methoden, d.h. die zugrundliegenden Algorithmen, sollten privat bleiben und nur innerhalb der Klasse sichtbar sein. Klassen repräsentieren somit einen Bauplan, der angibt, wie die Objekte aufgebaut sind und welches Verhalten die Objekte besitzen werden, die zu dieser Klasse gehören [1]. Jedes Objekt, das nach dem Bauplan der Klasse erstellt wird, wird Instanz dieser Klasse genannt. Die Begriffe Objekt und Instanz werden synonym verwendet. Jede Instanz besitzt spezifische Informationen, die sie von anderen Instanzen derselben Klasse unterscheidet. Um ein Objekt eindeutig mit einer Nachricht ansprechen zu können, ist jedes Objekt singulär und durch einen Namen von anderen Objekten unterschieden. Die Anzahl der Instanzen einer Klasse ist nicht statisch und kann zur Laufzeit variieren [10]. Wenn eine Vererbungshierarchie aufgebaut wird (vgl. Kapitel 4.2.5), werden in diese Hierarchie auch Klassen eingefügt, die nur der Strukturierung der verschiedenen Klassen dienen. Von dieser Klasse ist also nicht beabsichtigt, Instanzen zu bilden. Sie werden als abstrakte Klassen bezeichnet. Ihr Gegenstück sind konkrete Klassen [9]. Eine aktive Klasse ist eine Klasse, deren Objekte aktive Objekte sind. 4.2.1.3 Methoden Methoden bezeichnen Funktionen, die von einem Objekt ausgeführt werden. Die Begriffe Methode, Operation und Dienst werden synonym verwendet und beziehen sich auf den Definitionscode der Methode [1]. Methoden werden aktiviert, wenn dem Objekt eine Nachricht gesendet wird. Jedes Objekt besitzt eine Liste, das Protokoll, in der die Nachrichten beschrieben sind, auf die das Objekt durch Auswahl einer geeigneten Methode 36 Objektorientierte Analyse und Design antworten kann. Die Sichtbarkeit einer Methode gibt an, ob sie von anderen Klasse benutzt werden kann. Die Sichtbarkeit einer Methode wird in der UML mit den Symbolen +,# und – gekennzeichnet, die wie folgt definiert sind: + public (öffentlich) Jede andere Klasse, die mit dieser Klasse in einer Beziehung steht, und für die diese Klasse sichtbar ist (vgl. Kapitel 4.2.5), kann dieses Merkmal nutzen. # protected (geschützt) Jede Spezialisierung der Klasse kann dieses Merkmal nutzen – private (privat) Nur die Klasse selbst kann dieses Merkmal nutzen. Existenzielle Methoden einer Klasse sind der Konstruktor und der Destruktor. Ein Konstruktor wird bei der Erzeugung eines Objektes einer Klasse implizit aufgerufen und initialisiert das Objekt. Der Destruktor wird implizit bei der Zerstörung des Objektes aufgerufen. Seine Aufgabe ist es, die durch das Objekt belegten Ressourcen wieder freizugeben. Virtuelle Methodentabellen (VMT) sind eine Möglichkeit, Zugriffe auf die Methoden einer Klasse auch bei mehrfacher Instantiierung zu verwalten. Sie erlauben sowohl die Behandlung statischer als auch dynamischer Methoden. Anstatt mit jedem Objekt eine Kopie der darauf anzuwendenden Methode zu erstellen (speicherplatzintensiv) wird die Methode einer Klasse an einer Stelle angelegt und die Instanzen der Klassen enthalten nur einen Verweis auf diese Stelle [9]. Virtuelle Methodentabellen sind Bestandteile mancher Programmiersprachen und werden beim Kompilieren angelegt. 4.2.1.4 Attribute Attribute bezeichnen Eigenschaften von Objekten, die in Form von Daten gespeichert werden. Die Daten sollten in der Regel nicht öffentlich, sondern in der Klasse gekapselt sein. Allerdings kann es ausnahmsweise auch sinnvoll sein, bestimmte Attribute öffentlich zu machen. Die Sichtbarkeit von Attributen wird wie bei Methoden über die Symbole + (public), # (protected) und – (private) gekennzeichnet. Attribute können selbst wieder komplexe Datenstrukturen bzw. Objekte sein [1]. 4.2.2 Datenabstraktion Hierunter versteht man das Prinzip, nur die auf ein Objekt anwendbaren Operationen nach außen sichtbar zu machen. Die tatsächliche innere Realisierung der Operationen und 4 Objektorientierte Analyse und Design 37 die innere Struktur des Objektes werden verborgen, d.h. man betrachtet abstrakt die eigentliche Semantik und lässt die tatsächliche Implementierung außer acht [9]. Das konkrete Ergebnis des Abstraktionsprozesses ist die Schnittstelle, also die Liste der öffentlich verwendbaren Methoden einer Klasse [28]. 4.2.3 Kapselung Im Inneren eines Objektes befinden sich Informationen und Mechanismen, die das vom Objekt erwartete Verhalten bewirken. Durch das Prinzip der Kapselung werden feste Klassenschnittstellen garantiert, um die Integrität und Konsistenz von Instanzen zu sichern. Der Zugriff anderer Objekte auf innere Komponenten eines Objekts ist nur über die Schnittstelle erlaubt. In der Regel kann die Abschirmung der privaten Komponenten einer Klasse durch besondere Sprachmittel gewährleistet werden. Die Einführung der Kapselung sorgt für eine maximale interne Flexibilität der Klassen: Solange die durch den Abstraktionsprozess gewonnene Schnittstelle einer Klasse unverändert bleibt, kann ihre interne Informationsrepräsentation und -verarbeitung gemäß den jeweiligen Erfordernissen ohne Einführung von Seiteneffekten modifiziert werden. Als Konsequenzen bilden die Konzepte der Abstraktion und der Kapselung ein Paar: Die Abstraktion liefert die Schnittstelle einer Klasse, die Kapselung verhindert deren Umgehung [28]. Beam3D - length : double - profileID : int # number : int # numberOfNodes : int # materialID : int # stiffnessMatrix : DoubelMatrix # rotationMatrix : DoubleMatrix # elementLoadVector : DoubleMatrix # locationMatrix : IntVector # integrationPointArray ... # computeStiffnessMatrix() # computElementLoadVector(int loadcase) # computeLocationArray() # computeLength() + assembleStiffnessMatrix() + assembleElementLoadVector(int loadcase) + giveLocationArray() + giveInternalForce() ... Balken15:Beam3D number = 15 materialID = 3 elementLoadVector = [...] integrationPointArray = [...] ... Abbildung 4-16: Klasse und Objekt (Instanz) am Beispiel eines Balkenelementes 38 Objektorientierte Analyse und Design 4.2.4 Modularität Module dienen als physikalische "Behälter", in denen die Klassen und Objekte deklariert werden. Das bedeutet, dass alle logisch miteinander in enger Beziehung stehenden Klassen und Objekte in einem Modul untergebracht werden. Anderen Modulen werden nur die Elemente über eine Schnittstelle preisgegeben, die für diese von absoluter Notwendigkeit sind. Das allgemeine Ziel der Zerlegung in Module ist die Verringerung der Software-Kosten, weil Module unabhängig voneinander entworfen, getestet und gewartet werden können. Die Struktur jedes Moduls sollte so einfach sein, dass es vollständig verstanden werden kann. Es sollte möglich sein, die Implementierung von Modulen zu verändern, ohne die Implementierung der anderen Module zu beeinflussen. Der Aufwand, eine Designänderung durchzuführen, sollte in einem vernünftigen Verhältnis zu der Wahrscheinlichkeit stehen, dass eine Änderung notwendig wird [5]. 4.2.5 Hierarchie (Relationen) Eine wichtige Rolle in der Strukturierung objektorientierter Programme spielen Relationen. Sie drücken Beziehungen zwischen Klassen bzw. Objekten aus. Definition (Relationen): Unter einer Relation versteht man das Bilden von Zusammenhängen (Beziehungen in Anwendungsmodellen; in der Objektorientierung beziehen sich Relationen auf Objekte und Klassen. Relationen lassen sich in drei Klassen unterteilen: • die Vererbung als Spezialisierung bzw. Generalisierung • die Aggregation, als Teil-Ganzes-Beziehung und • die Assoziation als allgemeinster Fall Im Folgenden werden diese Relationen im Einzelnen dargestellt. 4.2.5.1 Vererbung Definition (Vererbung): Vererbung ist der Mechanismus, nach dem Objekte einer Klasse Zugriff auf Daten und Methoden einer bereits früher definierten Klasse bekommen, ohne dass diese neu definiert werden müssen. Vererbung ist eines der mächtigsten Konzepte des objektorientierten Programmierens. Der Begriff der Vererbung ist zentral, wenn es um die Wiederverwendung von Software geht. Klassen werden miteinander in Beziehung gesetzt. Dies führt dazu, dass neue Klassen auf bereits vorhandenen Klassen und ihrer Funktionalität aufbauen können. 4 Objektorientierte Analyse und Design 39 Point IntegrationPoint Node Abbildung 4-17: Einfache Vererbungsstruktur In Abbildung 4-17 wird eine einfache Vererbungsbeziehung dargestellt. Die Beziehung der Klassen untereinander ist wie folgt: • Point ist (abstrakte) Oberklasse oder Elternklasse von Node und IntegrationPoint. Die Elternklasse ist die direkte Vorgängerklasse, von der eine Klasse erbt. Natürlich kann der Prozess der Vererbung auch mehrfach ausgeführt werden. • Node ist Unterklasse oder Kindklasse oder abgeleitete Klasse von Point Eine Kindklasse ist die Erweiterung bzw. Spezialisierung einer anderen Klasse. • Eine abgeleitete Klasse erbt alle öffentlichen oder geschützten Daten und Methoden der Elternklasse, ohne sie explizit nochmals aufzuführen. Sie greift dennoch auf diese Attribute zu. Die Klassen Node und IntegrationPoint können also alle Punktoperationen durchführen, die in Point definiert werden. • Die Beziehungen der Klassen zueinander werden in der UML in Klassendiagrammen festgehalten, die erbende Klasse ist mit der vererbenden Klasse durch eine Generalisierung verbunden (siehe Abbildung 4-14 ), wobei der Pfeil in Richtung der Generalisierung, also der Elternklasse zeigt. Die Vererbung bewirkt, dass Instanzen einer Kindklasse überall da verwendet werden können, wo Instanzen der Elternklasse gefordert sind. Neben der Vererbung gibt es auch noch den Begriff Mehrfachvererbung. Definition (Mehrfachvererbung): Mehrfachvererbung ist die Eigenschaft, die einer Klasse das Erben von mehr als einer Elternklasse erlaubt. Abbildung 4-18 zeigt das Klassendiagramm einer Mehrfachvererbung. Die Klasse Node erbt alle öffentlichen und geschützten Attribute und Methoden ihrer beiden Mutterklassen Point und Component. Das heißt, dass die Klasse Node, wenn sie z.B. die Nachrichten giveNumber() oder giveCoordinates() erhält, mit der Ausführung der in Klasse Component 40 Objektorientierte Analyse und Design bzw. Point implementierten Methode reagiert. Diese Methoden müssen in Node weder deklariert noch neu definiert werden. Point Component # dimension : int # coordinates : Matrix ... # myStructure # number : int ... + giveCoordinates() + operator[] ... + giveNumber() + instanciateYourself() ... Node Abbildung 4-18: Mehrfachvererbung Ein Problem bei der Mehrfachvererbung ist, dass in Elternklassen Attribute mit gleicher Bezeichnung auftreten können, z.B. wenn zwei Elternklassen ihrerseits Kindklasse einer gemeinsamen Elternklasse (also der „Großelternklasse“) sind. Dadurch sind Attribute doppelt vorhanden, aber eigentlich identisch. Dieses Problem wird in verschiedenen Programmiersprachen unterschiedlich gelöst, in manchen ist die Mehrfachvererbung nicht erlaubt. Allgemein wird die Kindklasse dann als Erweiterung der Großelternklasse betrachtet, d.h. sie erhält die Eigenschaften beider Elternklassen [9]. 4.2.5.2 Aggregation Definition (Aggregation): Eine Aggregation besteht dann, wenn ein Objekt (Ganzes) sich aus anderen Objekten (Teilen) zusammensetzt. Hierbei ist wichtig, dass die Bestandteile wesentlich für den Aufbau des Ganzen sind, ansonsten handelt es sich um eine Assoziation [9]. Eine Aggregation kann beschrieben werden als: 2 • das Ganze und seine Teile • der Behälter (Container2) und sein Inhalt • die Kollektion und ihre Mitglieder Container sind Listen im weiteren Sinn. Sie können Einträge über Schlüssel (keys) verwalten. Einträge in einen Container können neben einfachen Datentypen auch komplexe Objekte selbstdefinierter Klassen sein. 4 Objektorientierte Analyse und Design 41 Durch Angabe der Anzahl (Kardinalitäten) der an einer Aggregation beteiligten Objekte lässt sich die Beziehung näher kennzeichnen. Eine Aggregation wird in der UML mit einer Raute gekennzeichnet. Innerhalb der Aggregation kann es den Fall der existentiellen Abhängigkeit geben. Man spricht von Komposition. Der existenziell abhängige Teil ist an das Ganze gebunden, so dass eine Destruktion des Ganzen auch den abhängigen Teil zerstört. Eine Komposition wird durch eine gefüllte Raute gekennzeichnet. Abbildung 4-19 zeigt eine Aggregations- und eine Kompositionsbeziehung. Die Klasse ElementContainer ist existentiell abhängig von der Klasse StructurFEM. Die Destruktion einer Instanz von StructureFEM löst auch die Destruktion des in ihr enthaltenen Containers aus. Die Beziehung zwischen ElementConainer und Element FEM entspricht der Beziehung zwischen Behälter und Inhalt. StructureFEM enthält X 1 ElementFEMContainer enthält X * ElementFEM Abbildung 4-19: Aggregation 4.2.5.3 Assoziation Die Assoziation ist die allgemeinste Beziehung zwischen Klassen. Sie entsteht immer dann, wenn Objekte mit einer generellen, eventuell zusätzlich attributierten Relation verbunden werden. Definition (Assoziation): Eine Assoziation setzt zwei oder mehr Klassen miteinander in eine (attributierte) Beziehung. Im Gegensatz zur Aggregation handelt es sich bei der Assoziation um einen viel unabhängigeren Zusammenhang, der wieder lösbar ist. Zusätzlich hat die Assoziation noch eine Stelligkeit oder Multiplizität. Diese bezeichnen die Anzahl der an der Beziehung beteiligten Objekte [9]. Assoziationen werden in Abbildung 4-20 gezeigt. Die obere Darstellung zeigt die Beziehung der Klassen StructureFEM und ProblemDomain, mit einer Spezifizierung: der Art der Relation (ProblemDomain berechnet das Tragwerk in StructureFEM). Die untere Beziehung ist eine qualifizierte und gerichtete Assoziation zwischen Knoten und Element. Das Attribut besagt, dass der Knoten auf ein Element über das Attribut number zugreifen kann. Da die Beziehung gerichtet ist, hat zwar Node über diese Assoziation Zugriff auf ElementFEM aber nicht andersherum. Die Multiplizität gibt 42 Objektorientierte Analyse und Design an, dass die Identifikation eindeutig ist, d.h. dass jede Identifikationsnummer number nur einer einzigen Instanz des Objektes ElementFEM entspricht. StructureFEM * W berechnet 1 ProblemDomain 1 Node number ElementFEM Abbildung 4-20: Assoziationen 4.2.6 Polymorphie Polymorphie ist eines der wichtigsten Konzepte der objektorientierten Programmierung. Das Vererbungsprinzip sowie die dynamische Typisierung einiger Programmiersprachen oder das Interface-Konzept in Java bilden die Basis zur Polymorphie. Polymorphie bedeutet, dass eine Operation sich (in unterschiedlichen Klassen) unterschiedlich verhalten kann. Es gibt zwei Arten der Polymorphie: statische Polymorphie und dynamische Polymorphie. Definition (Statischer Polymorphismus): (1) Die Eigenschaft einer Funktion für verschiedene Parametersätze mit gleichem Namen definiert zu sein (Überladung). Dieser Aspekt der Polymorphie besteht in der Variation der Schnittstelle gleichnamiger Operationen. (2) Polymorphismus ist die Eigenschaft eines Operators, sich auf Instanzen verschiedener Klassen während der Laufzeit zu beziehen bzw. Polymorphismus ist die Fähigkeit mehrerer Klassen von Objekten, auf die gleiche Botschaft in unterschiedlicher Art und Weise zu reagieren. Diese Art des statischen Polymorphismus ist bereits aus der prozeduralen Welt bekannt, nämlich in Gestalt von Operatoren wie + oder -. Diese generischen Operationen sind sowohl auf ganze Zahlen als auch auf gebrochene Zahlen anwendbar. Objektorientierte Programmiersprachen bieten die Möglichkeit, diese Operatoren auch für selbstdefinierte Datentypen bzw. Klassen zu verwenden. Dazu gehört z.B. die Definition des Operators * für die Matrixmulitplikation. Genaugenommen sind Operatoren Methoden mit besonderen 4 Objektorientierte Analyse und Design 43 Namen. Daher kann der gleiche Effekt auch bei ganz gewöhnlichen Operationen herbeigeführt werden. Ein Beispiel für statische Polymorphie ist der Aufruf an ein Element seinen Lastvektor zu berechnen. Dieses kann für ein statisches Problem durch die Methode computeLoadVector() geschehen. Die Methode braucht keinen weiteren Parameter, da der Lastvektor zeitunabhängig ist. Für eine Modalanalyse allerdings muss der Lastvektor zu einem bestimmten Zeitpunkt t bestimmt werden, da dieser eine Funktion von der Zeit sein kann. Die Methode kann damit durch computeLoadVector(time) überladen werden. Das Programm entscheidet dann zur Laufzeit, welche der beiden Methoden ausgeführt wird. Definition (Dynamischer Polymorphismus): Polymorphismus ist die Eigenschaft von Variablen, verschiedene Typen annehmen zu können. Voraussetzung für die dynamische Polymorphie ist die sogenannte späte Bindung (vgl. Typbindung in Kapitel 5). Bei der späten Bindung wird der genaue Speicherort einer Operation erst dann ermittelt, wenn der Aufruf stattfindet, d.h. eine entsprechende Nachricht an das Objekt gesendet wird. Die Zuordnung der Nachricht zu der empfangenden Operation geschieht also nicht während der Programmübersetzung sondern dynamisch zur Laufzeit des Programms. Ob diese Eigenschaft verwendet werden kann, ist letztendlich davon abhängig, ob die Programmiersprache, mit der der Entwurf realisiert werden soll, die späte Bindung unterstützt (vgl. Kapitel 6: Programmiersprachen) [9]. Polymorphie hat den Vorteil, dass sie dem Programmierer mehr Freiheiten lässt und von Routineaufgaben entlastet. Der Nachteil besteht darin, dass die Typbestimmung und – validierung zur Laufzeit einen beträchtlichen Zusatzaufwand darstellt. Darüber hinaus werden Fehler, die aus Typverletzungen resultieren, erst zur Laufzeit erkannt. Für berechnungsintensive Anwendungen wie die FEM ist es daher günstig, eine vorwiegend statische Typbindung zu verwenden, wenn eine dynamische Bindung die Laufzeiteffizienz mehr beeinträchtigt, als das programmiertechnische Vorteile daraus resultieren [28]. 4.2.7 Nebenläufigkeit Objektorientierte Programme bestehen aus Objekten, die durch den Austausch von Botschaften deren Ablauf steuern. Dabei ist die Reihenfolge des Botschaftenaustausches im Allgemeinen durch die Ordnung im Programmtext vorgegeben. Etliche Botschaften sind allerdings voneinander unabhängig und könnten theoretisch auch auf parallelen Prozessoren bearbeitet werden. Obwohl aufgrund des numerischen Aufwands gerade im Bereich der FEM parallel arbeitende Systeme von großem Interesse sind, befinden sich die meisten 44 Objektorientierte Analyse und Design Ansätze noch im Forschungsstadium. Zusätzlich kann kaum eine der verbreiteten Hochsprachen echte Parallelkonstrukte (Nebenläufigkeit auf verschiedenen Prozessoren) vorweisen [28]. Auf diesen Aspekt wird im Programmentwurf nicht weiter eingegangen. 4.2.8 Persistenz Aus verschiedenen Gründen ist es manchmal notwendig und wünschenswert, ein Programm an einer bestimmten Stelle zu unterbrechen und es später an dieser Stelle wieder aufsetzen zu lassen. Dazu müssen die während der Laufzeit berechneten Daten (Objekte und Verbindungen) geeignet gespeichert werden [9]. Definition (Persistenz) Persistenz ist die Eigenschaft von Objekten, über die Laufzeit des Programms hinaus in ihrer Identität, ihrem Zustand und ihrer Beschreibung zu existieren. Für den Bereich der FEM hat das Konzept der Persistenz eine sehr untergeordnete Bedeutung. Obwohl die persistente Speicherung von FE-Daten mit den Mitteln der verwendeten Programmiersprache wünschenswert wäre, scheitert sie an der Tatsache, dass kaum eine Programmiersprache echte Datenpersistenz bietet. Die Benutzung von (objektorientierten) Datenbanken ist für FE-Massendaten wenig geeignet, da FEProgrammsysteme selten die für Datenbanken typischen selektiven Abfragen und Einfügungen benutzen. Maßgeblich sind hier Operationen, die sich durch große Datenumsätze innerhalb kurzer Zeit auszeichnen, z.B. beim Abfragen der Modelldaten oder beim Zurückschreiben der Berechnungsergebnisse [28]. 4.2.9 Generizität Die Generizität ist kein notwendiges Konzept der Objektorientierung. Definition (Generizität): Generizität ist die Fähigkeit, Klassen durch einen Typ zu parametrisieren. Da Klassen die Implementierung von abstrakten Datentypen sind, können sie auch generische Parameter haben. Klassen mit einem generischen Parameter erzeugen also Klassen von Klassen von Objekten. Verallgemeinert kann der Begriff der Generizität auch auf Funktionen, Prozeduren bzw. Methoden und deren Parameter angewendet werden. Noch interessanter wird die Anwendung der generischen Parameter, wenn der Parameter der generischen Klasse selbst Klasse und Elternklasse von anderen Klassen ist. Damit können dann in einem Stapel Elemente unterschiedlicher Typen abgelegt werden, wenn diese 4 Objektorientierte Analyse und Design 45 Kindklassen einer Elternklasse sind, die die Eigenschaft hat, auf einem Stapel abgelegt werden zu können. Die oben erwähnte Polymorphie ist ebenfalls eine Form der Generizität. Abbildung 2-1 zeigt eine generische Klasse. In diesem Fall ist dies ein Container, in dem alle Objekte, die Instanzen der Klasse Component oder einer ihrer Kindklassen sind, abgelegt werden können. T {T=Component} Container addComponent(Component) deleteComponent(Component) Abbildung 4-21: Generische Klasse Trotz der Mächtigkeit generischer Konstrukte sind generische Klassen in kaum einer Sprache zugelassen [9]. 46 5 Globales Programmkonzept Globales Programmkonzept Der Entwurf des globalen Programmkonzepts erfolgte auf der Basis der Objektorientierung. In Kapitel 5.1 wird zunächst die (statische) Strukturbeschreibung vorgestellt. In Kapitel 5.2 werden die Grundklassen dieses Modells mit ihren wichtigsten Attributen und Methoden vorgestellt. Der Ablauf der Berechnung wird dann in Kapitel 5.3 beispielhaft für eine statische Berechnung, eine Berechnung mit Theorie 2. Ordnung und eine Berechnung mit physikalischer Nichtlinearität beschrieben. Die Eingabe bzw. Ausgabe im Prä- und Postprozessor wird aus Zeitgründen nicht bearbeitet. Die Methoden in den Klassen werden nur anhand ihrer Schnittstelle und ihrer Verantwortlichkeiten beschrieben. Die Implementation des Entwurfes, d.h. die explizite Darstellung der in einer Methode enthaltenen Datenmanipulation, ist nicht Bestandteil der Ausführung. 5.1 Erläuterung des FEM-Objektmodells Bei den wichtigsten Abstraktionen des Anwendungsgebiets handelt es sich um die grundlegende Theorie in Form der Kontinuumsmechanik und die FEM als Werkzeug zur Lösung der resultierenden Gleichungen. Die zentralen Abstraktionen sind einerseits der Körpers selbst, andererseits Teilgebiete in Form der Finiten Elemente. Das zentrale Klassendiagramm mit der Beschreibung der Abhängigkeiten der verschiedenen Klassen untereinander wird in Abbildung 5-1 dargestellt. Elemente und Knoten sowie die Lasten auf die Struktur und das Material stellen Objektklassen dar. Alle Bestandteile des Modells erben von einer gemeinsamen Mutterklasse: Component. (Abbildung 5-3) Durch diese Oberklasse wird sichergestellt, dass jedes Objekt bei seiner Instanziierung ein Identifikationsnummer (Attribut number) bekommt und einer Struktur (Klasse Structure) zugeordnet wird. Die Klasse Structure repräsentiert das Abbild des zu berechnenden Tragwerks. In ihr werden die Instanzen der Elemente, Knoten und Lastfälle verwaltet. Die Klasse Structure ist ebenfalls eine abstrakte Klasse, die durch ihre jeweilige Kindklasse vertreten wird. Für eine Berechnung mit der Methode der Finiten Elemente ist dies die Klasse StructureFEM. Diese Klasse stellt (vor der Berechnung) sicher, das alle notwendigen Daten vorhanden sind, um die Berechnung durchzuführen. Jede FEM-Struktur besteht aus mindestens zwei Knoten, einem Element und 5 Globales Programmkonzept 47 einem Lastfall. Alle Komponenten werden in parametrisierten Container-Klassen in StructureFEM abgelegt und von der Struktur verwaltet. Die Klasse ElementFEM ist ebenfalls eine abstrakte Klasse und wird nur durch ihre Kindklassen vertreten, die verschiedene Elementtypen implementieren (z.B. Balkenelemente). Das Element wird ebenso wie die Gesamtstruktur (bei der Instantiierung) über Identifikationsnummern mit seinen zugehörigen Knoten verbunden. Genauso wird jedem Element ein Materialgesetz zugeordnet, das über die Identifikationsnummer assoziiert wird. Für die Analyse von Stabwerken ist es zusätzlich nützlich eine Klasse für Querschnitte anzulegen, durch die auf eine Bibliothek von üblichen Querschnitten (z.B. Stahlprofile) zugegriffen werden kann. Auf die Klasse Profile wird in Stabelementen – analog zu den Materialgesetzen - über ein Attribut zugegriffen, das die Identifikationsnummer des Profiles enthält. Dem Element kommt von jeher die zentrale Rolle innerhalb eines FEMProgrammsystems zu, da es alle Information für die zu lösenden differentiellen Gleichungen enthält. Diese zentrale Rolle des Elementes wird auch in einem objektorientierten Ansatz beibehalten. Sie wird tatsächlich noch bestärkt, da alle Attribute und alle Berechnungsvorschriften in der Klasse gekapselt sind. Allerdings profitiert die ElementKlasse ebenfalls von der hierarchischen Strukturierung der Objekte und delegiert einige wichtige Aufgaben wie das Management der Unbekannten an Knoten (Klasse Node) und Freiheitsgrad (Klasse Dof). Bei seiner Instantiierung erstellt ein Element die für seine Berechnung notwendigen Integrationspunkte (Klasse IntegrationPoint). Die Klassen Node und IntegrationPoint sind beide von ihrer Datenstruktur her Punkte im Raum oder in der Ebene. Daher werden sie beide als Kindklasse einer abstrakten Mutterklasse Point erstellt, die die wichtigsten Attribute und Methoden für das Management der Koordinaten vererbt (vgl. Abbildung 4-17, Abbildung 4-18 und Abbildung 5-3) Für das Verwalten der Freiheitsgrade legt jeder Knoten Instanzen der Klasse Dof (Degree of Freedom) an: Der Zugriff auf die Freiheitsgrade (Ändern, Ausgeben usw.) geschieht nur durch die Klasse Node. Jede Instanz von Dof beinhaltet jeweils einen möglichen Freiheitsgrad des Knotens. Dof speichert als Attribut seinen Zustand (isBound als Boolean) und die Gleichungsnummer, mit der der Freiheitsgrad in das Gesamtsystem eingeht (Attribut equationNumber). Die Verwaltung der Freiheitsgrade in dem Softwaresystem ist also dezentralisiert. Dof kann eine oder mehrere Unbekannte haben (z.B. Knotenverschiebung und –beschleunigung). 48 Globales Programmkonzept Die Klasse ProblemDomain ist eine abstrakte Mutterklasse, die durch Instanzen ihrer Kindklassen vertreten wird (vgl. Abbildung 5-2). Diese übernehmen die konkrete Ablaufsteuerung einer Berechnung für eine beliebige Berechnungsmethode. Die Unterklasse StaticalAnalysisFEM führt die statische Berechnung des in StructureFEM dargestellten Systems durch, NLStaticalAnalysisFEM eine nichtlineare statische Berechnung und ModalAnalysisFEM eine zeitabhängige Analyse. Die verschiedenen Lösungsmethoden für die nichtlineare oder zeitabhängige Berechnung werden wiederum als Unterklassen implementiert. Die Lasten, die auf das Tragwerk wirken, werden in der Klasse Loadcase (ebenfalls durch einen Container) verwaltet. Als Klassen werden Knotenlasten (NodalLoad) und auf das Element wirkende Lasten unterschieden (ElementLoad). Elementlasten werden noch einmal genauer aufgeteilt in Oberflächenlasten und Körperlasten, da sich die Integration über diese Lasten voneinander unterscheidet (vgl. Kapitel 2.1.1, Gleichungen 11 und 12). Die Zusammenstellung der Lasten wird von den Klassen ElementFEM bzw. Node übernommen. In Abbildung 5-1 bis Abbildung 5-4 werden die Klassendiagramme des Programmentwurfes vorgestellt. Diese Diagramme zeigen jeweils nur einen Ausschnitt des Entwurfes und die Klassen werden nur mit den für das jeweilige Diagramm notwendigen Attributen, Methoden oder Verantwortlichkeiten dargestellt. 5 Globales Programmkonzept Abbildung 5-1: Klassendiagramm: Klassen des globalen FEM-Models 49 50 Globales Programmkonzept Abbildung 5-2: Klassendiagramm: Klassen für die Steuerung der Berechnung 5 Globales Programmkonzept Abbildung 5-3: Klassendiagramm: Vererbungshierarchie für die FEM-Objekte 51 52 Globales Programmkonzept Abbildung 5-4: Klassendiagramm: Delegation der Containermethoden an eine generische Klasse 5 Globales Programmkonzept Abbildung 5-5: Klassendiagramm: Die Klasse Matrix 53 54 Globales Programmkonzept 5.2 Die Klassen In diesem Kapitel werden die grundlegenden Klassen mitsamt Methoden und Attributen beschrieben: Das Element (ElementFEM Kapitel 5.2.1), der Knoten (Node Kapitel 5.2.2), der Freiheitsgrad (Dof Kapitel 5.2.3), die „verwaltenden“ Klassen StructureFEM (Kapitel 5.2.4) und ProblemDomain (Kapitel 5.2.5) und die Klasse Matrix (Kapitel 5.2.6) für die numerische Berechnung. Es wird Aufbau und Verantwortlichkeiten der Klassen ausgearbeitet. Dabei wird auf die Implementation der vorgestellten Methoden nicht eingegangen, da diese für den globalen Programmentwurf und den Berechnungsablauf nicht entscheidend ist und stark von der Wahl der Programmiersprache abhängt. Die Attribut- und Methodenliste ist nicht vollständig. Es wird in dieser Ausführung nur auf diejenigen Attribute und Methoden eingegangen, die für die statische Berechnung eines Tragwerks benötigt werden. Für eine nichtlineare Berechnung müssen die Klassen entsprechend erweitert werden. In den Sequenzdiagrammen in Kapitel 5.3 werden die wichtigsten für eine nichtlineare Berechnung benötigten Attribute und Methoden umrissen. Zudem kann es bei der Implementierung des Systems durchaus notwendig werden weitere Attribute und Methoden einzufügen. Bei dem in Kapitel 8 vorgestellten Beispielprogramm werden einige Methoden, die in diesem Kapitel mit aufgeführt werden, nicht implementiert. So hält das dort verwendete Balkenelement seine Steifigkeitsmatrix direkt vor, so dass auf eine Integration über das Volumen des Elementes verzichtet werden kann. Da diese Methoden aber für das allgemeine Programmkonzept von Bedeutung sind, werden sie in den folgenden Abschnitten beschrieben. 5.2.1 Die Klasse ElementFEM Die Instanzen der Klasse ElementFEM bzw. ihrer Kindklassen müssen folgende Aufgaben erfüllen: • Berechnung der Element-Steifigkeitsmatrix k • Berechnung der Element-Massenmatrix m • Berechnung des Vektors der Elementlasten f S + f B • Das Einlesen seiner Daten in das globale Gleichungssystem • Identifikation und Management der Knoten und des Materialgesetzes 5 Globales Programmkonzept 55 Die Steifigkeitsmatrix k wird in der Methode computeStiffnessMatrix() erstellt. Jede Instanz eines Elementes führt diese Methode aus, wenn es eine entsprechende Nachricht bekommt. In dieser Methode integriert das Element numerisch (z.B. Gauss-Integration) seine Steifigkeitsmatrix und gibt diese zurück. Diese Integration ist theoretisch gültig für jedes Element, wird daher in der Mutterklasse implementiert. Die Matrizen b und h bzw. das Volumen (Oberfläche) über das integriert wird, sind dagegen abhängig vom jeweiligen Elementtyp. Die Erstellung dieser Matrizen mit den Methoden - giveVolume(IntegrationPoint) - giveBMatrixAt(IntegrationPoint) und - giveHMatrixAt(IntegrationPoint) wird in der Mutterklasse als abstrakt definiert und muss in den Kindklassen implementiert werden. Falls die Kindklassen die Element-Steifigkeitsmatrix auf einem andern Weg berechnen, kann die Methode computeStiffnessMatrix() auch überschrieben werden (Polymorphie). Die Massenmatrix wird analog zur Steifigkeitsmatrix erstellt. Auf die Dichte in der Klasse Material wird dabei über ein Attribut materialID zugegriffen, das den Integrationspunkten (in integrationPointContainer) zugeordnet wird (abgeleitete Assoziation). Ein Element erstellt seinen Lastvektor fS +f B wenn es die Nachricht computeElementLoadVector(loadcase) bekommt. Über die Assoziation mit einem Lastfall (Loadcase) sucht es alle Beiträge von Elementlasten die auf es bezogen sind und ermittelt den entsprechenden Lastvektor (vgl. Gleichungen 11-13). Dabei ruft es seine eigenen Methoden computeBodyForceVector(Loadcase) und computeSurfaceLoadVector(Loadcase) auf. Das Einlesen der Elementmatrizen bzw. der Lastvektoren geschieht auf Anforderung von der Klasse StructureFEM. Diese ruft (je nach Bedarf) die Methoden - assembleStiffnessMatrix(loadcase), - assembleMassMatrix(loadcase) und - assembleElementLoadVector(loadcase) des Elementes auf. Das Element benötigt dabei das Attribut locationArray, in dem die Inzidenzen gespeichert sind, die seine lokalen Freiheitsgrade auf die globalen beziehen. Dieser Vektor wird gebildet, indem das Element die locationArrays seiner Knoten aneinanderhängt. Das Element sendet seine Beiträge mit den entsprechenden Informationen zu den globalen Matrizen und Vektoren in der Klasse StructureFEM zurück, wo die Anteile 56 Globales Programmkonzept der Elementmatrizen dann - entsprechend der Inzidenzen – in die globalen Matrizen einsortiert werden. Wenn das Element eine „assemble“-Nachricht bekommt, prüft es zunächst, ob das entsprechende Attribut bereits berechnet wurde, d.h. ungleich NULL ist. Falls dies der Fall ist, wird lediglich über ein an sich selbst gerichtetes „give“ das vorhandene Attribut ausgegeben. Wenn das Attribut nicht vorhanden ist, schickt sich die Klasse selber die Nachricht „compute“ um das Attribut zu errechnen. Dieses Vorgehen wird auch als „NonAnticipation-Method“ bezeichnet, das heißt der Aufruf „assemble“ wird unabhängig vom Zustand des Objektes ausgeführt [11][12]. Dieses Vorgehen birgt Vorteile z.B. für die nichtlineare Berechnung von Tragwerken (vgl. Kapitel 5.3). 5.2.2 Die Klasse Node Die Klasse Node kapselt alle Knotendaten. Ein Element kann auf Knotendaten nur über die Methoden der Klasse zugreifen. Eine Instanz der Klasse Node hat folgende Funktion: • Management der Koordinaten • Management der Freiheitsgrade • Berechnung und Einlesen des Vektors der Knotenlasten fi Jede Instanz der Klasse Node besitzt ein Attribut namens dofContainer, in dem es die Freiheitsgrade (also die Instanzen von Dof an sich) speichert. Jeder Knoten hat eine Methode getDofs(), die er bei seiner Instantiierung ausführt. Wie Elemente sind auch Knoten (konzentrierten) Lasten ausgesetzt. Diese werden über die Klasse NodalLoad assoziiert. Wenn der Knoten die Nachricht computeNodalLoadVector(Loadcase) erhält, liest er die dem Lastfall entsprechenden Daten ein und erstellt den Knotenlastvektor nodalLoadVector. Analog zur Elementklasse sendet der Knoten auf die Aufforderung assembleNodalLoadVector(Loadcase) hin seinen Beitrag zusammen mit den Informationen über die Gleichungsnummer (aus locationArray) zum globalen Lastvektor der Klasse StructureFEM. 5.2.3 Die Klasse Dof Ein Freiheitsgrad ist Attribut eines Knotens. Durch die Betrachtungsweise als eigenständiges Objekt können einige Aufgaben vom Knoten zum Freiheitsgrad delegiert werden. Eine Instanz der Klasse Dof hat folgende Verantwortlichkeiten: • Management der Unbekannten 5 Globales Programmkonzept • Nummerierung der Gleichungen • Speicherung des Lagerzustandes 57 Die Klasse Dof besitzt ein Attribut unknowns, in dem die Unbekannten über einen Schlüssel verwaltet werden. Auf die Anweisung giveUnknown(key) gibt Dof die unter diesem Schlüssel gespeicherte Größe aus. Ein Key ist eine Variable vom Typ String, z.B. Verschiebung. Erhält der Freiheitsgrad die Nachricht setUnknown(key,value), dann wird der übergebende Wert an die entsprechende Stelle geschrieben. Ein gutes Beispiel für die Dezentralisierung des Entwurfs ist auch die Nummerierung der Freiheitsgrade. Jeder Dof enthält ein Attribut equationNumber. Diese Nummer entspricht der Gleichungsnummer, mit der Kräfte und Verformungen in Richtung dieses Freiheitsgrades in das Gesamtsystem eingehen. Wenn der Freiheitsgrad die Nachricht giveEquationNumber() erhält, wird das Attribut zurückgegeben. Falls equationNumber noch leer ist, führt der Freiheitsgrad die Methode getEquationNumber() durch. Falls der Freiheitsgrad gebunden ist (Attribut isbound = true), wird eine Null geschrieben, ansonsten gibt die Methode die aktuelle Dimension des Gleichungssystems + 1 zurück. 5.2.4 Die Klasse StructureFEM Die Klasse StructureFEM verwaltet alle Informationen und Methoden, die für die Berechnung eines Tragwerkes notwendig sind. Die Verantwortlichkeiten lassen sich wie folgt zusammenfassen: • Input/Output der Systemdaten • Management der Komponenten • Lösung des Gleichungssystems StructureFEM stellt das Interface des FEM-Programmsystems zum Benutzer dar. Eine Instanz der Klasse repräsentiert das gesamte Tragwerk, das berechnet werden soll. Über Container-Klassen werden alle Knoten, Elemente, Lastfälle und Materialien verwaltet. Die Klasse StructureFEM hält über diese Container-Klassen alle Methoden bereit, um Komponenten zu erstellen und zu verwalten (vgl. Abbildung 5-4). Die Lösung des Gleichungssystems wird ebenfalls über StructureFEM initiiert. Die Ablaufsteuerung der Berechnung wird allerdings an eine Instanz der Klasse ProblemDomain delegiert. StructureFEM besitzt als Attribute alle globalen Matrizen und Vektoren und stellt über verschiedene Methoden den Zugriff zu diesen Matrizen her (vgl. Sequenzdiagramme, Abbildung 5-7, Abbildung 5-9 und Abbildung 5-11). Für das Aufstellen des linearen 58 Globales Programmkonzept Gleichungssystems werden z.B. die Methoden assembleGlobalStiffnessMatrix(), assembleGlobalLoadVector(Loadcase) und solveSystem() bereitgestellt. Die Nachricht assembleGlobalStiffnessMatrix() veranlasst StructureFEM an alle Elemente den Aufruf assembleStiffnessMatrix() zu senden. Analog erfolgt für den Aufruf assembleGlobalLoadVector(Loadcase) das Zusammensetzen der Element-Lastvektoren und der Knoten-Lastvektoren. 5.2.5 Die Klasse ProblemDomain Die Instanzen der Kindklassen von ProblemDomain haben nur eine einzige Verantworlichkeit: die Ablaufsteuerung der Berechnung. Die Klasse hat keine Attribute die das Tragwerk betreffen und keine Methode außer solve(). Die Assoziation mit Structure ist die einzige Verbindung, die ProblemDomain mit den Komponenten des FEM-Models hat. Jede Kindklasse (bzw. „Enkelklasse“) von ProblemDomain hat eine eigene Methode solve() implementiert. Für die Kindklasse StaticalAnalysisFEM besteht die Methode aus nur drei Nachrichten, die an StructureFEM gesendet werden: assembleGlobalStiffnessMatrix(), assembleGlobalLoadVector() und solveSystem() (vgl. Kapitel 5.2.4). 5.2.6 Die Klasse Matrix Die Klasse Matrix ist die wichtigste mathematische Klasse im Objektmodell. Ihre Aufgaben beschränken sich auf • die Verwaltung und Strukturierung der Matrixelemente • Methoden zur Matrizenmanipulation Die Verwaltung und Strukturierung der Matrixelemente wird in der Implementation der von der Klasse bereitgestellten Methoden versteckt. Die (Mutter-)klasse Matrix speichert Elemente in einem zweidimensionalen Feld. Da diese Art der Datenverwaltung oft sehr langsam ist, können spezialisierte Unterklassen zu Matrix erstellt werden, wie z.B. BandMatrix oder SkylineMatrix. Diese übernehmen die Schnittstellen ihrer Mutterklasse und überschreiben die von Matrix implementierten Methoden zur Speicherverwaltung. Damit kann zu jedem Zeitpunkt eine Umstellung auf eine Kindklasse von Matrix geschehen. Da die Kindklasse ihre Mutterklasse „vertreten“ kann, muss lediglich bei der Instantiierung der neue Matrixtyp spezifiziert werden. Alle übrigen an Matrix gerichteten Methodenaufrufe werden über die gemeinsame Schnittstelle über die Mutterklasse an die Kindklasse weitergegeben (vgl. Kapitel 3.2 und 4.2.6). 5 Globales Programmkonzept 59 Die öffentlichen Methoden der Klasse Matrix sind zum Großteil über (überladene) Operatoren definiert, z.B. der Operator “ * “ für Matrixmultiplikationen oder der Operator “ + “ für Matrixadditionen. Auf die Nachricht giveSize() gibt die Klasse die aktuelle Dimension der (System-)Matrix zurück3. Die Methode transpose() transponiert die Matrix, die Methode solveSystem() löst das lineare Gleichungssystem. 5.3 Rechenabläufe In den nächsten Kapiteln werden die Berechnungsabläufe in einem objektorientierten FEM-Programm dargestellt. Die gegebenen Abläufe behandeln die Lösung des linearen Gleichungssystems sowie die iterativen und inkrementellen Methoden, die in Kapitel 2.1.3 (Nichtlineare Berechnungen) vorgestellt wurden. Für die Darstellung wurden Aktivitätsdiagramme und Sequenzdiagramme erstellt. Bei Aktivitätsdiagrammen liegt der Schwerpunkt auf dem Fluss der Aktivitäten im Ablauf der Berechnung. Sie sind also vergleichbar mit Flussdiagrammen in der sequentiellen Programmierung. Die Aktivitäten werden allerdings in sogenannten „Schwimmbahnen“ angeordnet. Diese Schwimmbahnen legen die Zuständigkeiten für die jeweiligen Aktivitäten fest, die Verantwortlichkeitsbereiche werden durch eine oder mehrere Klassen implementiert. In den folgenden Diagrammen werden die Diagramme in die Verantwortlichkeitsbereiche • Berechnungssteuerung (Klassen StructureFEM und ProblemDomain), • Elemente (Klasse ElementFEM bzw. Kindklassen) und • Knoten (Klasse Node) unterteilt. Transitionen werden als Ereignispfeile ohne explizite Ereignisbeschreibung notiert. Eingehende Transitionen lösen eine Aktivität aus, bei Abschluss der Aktivität werden neue Transitionen ausgelöst. Über die sogenannten „splitting“-Linien können theoretisch Abläufe geteilt und synchronisiert werden, parallel laufende Aktivitätspfade können nacheinander, gleichzeitig oder abwechselnd ausgeführt werden. In den folgenden Diagrammen werden „splitting“-Linien nur benutzt, um Schleifen zu beschreiben (*for each ...all). Bei Sequenzdiagrammen steht der Nachrichtenfluss zwischen den Objekten im Vordergrund. Die Objekte werden durch gestrichelte senkrechte Linien dargestellt. Der 3 Die Steifigkeits- und Massen-Matrizen in der FEM sind quadratisch, daher entspricht die Anzahl der Spalten der Anzahl der Reihen. Bei Vektoren (nur eine Spalte) spiegelt die Anzahl der Reihen die Dimension des Gleichungssystems wieder. 60 Globales Programmkonzept Objektname steht über der Linie. Die Überlagerung der gestrichelten Lebenslinien durch breite senkrechte Balken symbolisiert den Steuerungsfokus. Der Steuerungsfokus gibt an, welches Objekt gerade aktiv ist. Mit einem Sternchen vor der Nachricht soll das mehrfache Senden einer Nachricht symbolisiert werden. Die Instanzen der Klassen ElementFEM und Node werden ebenfalls nur durch ein Sternchen benannt, das bedeutet, dass die Nachricht an mehrere (oder alle) Objekte dieser Klasse gesendet wird [26]. Bei den Methodenaufrufen werden in den Diagrammen kaum Parameter angegeben. Die meisten Aufrufe bleiben in der Tat parameterlos. Teilweise werden Parameter allerdings auch ausgelassen (z.B. Loadcase), wenn sie für den Nachrichtenaustausch innerhalb des dargestellten Bereiches nicht entscheidend sind. Allgemein wird die Beschreibung der Abläufe auf einem hohen Abstraktionslevel gehalten, damit die Diagramme übersichtlich bleiben. Für eine vollständige (Implementations-) Darstellung wären noch weitere Diagramme erforderlich, die einzelne Teilbereiche näher beleuchten. 5.3.1 Statische Berechnung Der Ablauf einer statische Berechnung wird in Abbildung 5-6 und Abbildung 5-7 dargestellt. Der Aktivitätsfluss ist bis auf die Schleifen über Element und Knoten linear. Die Berechnungskontrolle verbleibt überwiegend bei den Instanzen der Klassen ProblemDomain und StructureFEM. Aus dem Sequenzdiagramm wird deutlich, dass die mathematischen Operationen (Lösung des Geleichungssystems) in StructureFEM stattfinden. Das bedeutet, dass ProblemDomain zwar die Berechnung steuert, aber keine Kenntnisse über die Inhalte der Systemgleichungen hat. Zudem verbleibt der unterste Kontrollfokus bei StructureFEM als Schnittstelle zum Benutzer. Die Berechnung wird durch die Nachricht solve() an ProblemDomain ausgelöst. 5.3.2 Nichtlineare Berechnung Die Berechnung nach der Theorie 2. Ordnung erfolgt nach dem Newton-RaphsonVerfahren (Kapitel 2.1.3.1). Das Diagramm in Abbildung 5-8 zeigt den allgemeinen Ablauf einer solchen Berechnung. Im Sequenzdiagramm (Abbildung 5-9) wird der Austausch der Nachrichten zwischen den Objekten für einen Iterationsschritt dargestellt. Für ein physikalisch nichtlineares System wurde bereits die inkrementelle Steifigkeitsmethode vorgestellt (Kapitel 2.1.3.2). Abbildung 5-10 zeigt den allgemeinen 5 Globales Programmkonzept 61 Ablauf der Berechnung. Das Sequenzdiagramm (Abbildung 5-11) stellt den Austausch der Nachrichten für ein Lastinkrement dar. Die Berechnung der nichtlinearen (tangentialen) Steifigkeitsmatrizen geschieht auf Elementebene. Das Zusammensetzen dieser Matrizen zur globalen Steifigkeitsmatrix erfolgt auf dem bereits geschilderten Weg (Kapitel 5.2.1). Er unterscheidet sich nicht von der Erstellung der linearen globalen Steifigkeitsmatrix. Es wird auffallen, dass für die nichtlinearen Berechnungen kaum zusätzliche Methodenaufrufe implementiert werden müssen. Dieses liegt vor allem an der bereits vorgestellten „Non-Anticipation-Method“. Die Errechnung der Element-Steifigkeitsmatrix findet theoretisch immer unter Berücksichtigung der Vorverformungen und des Materialzustandes statt. Da diese zu Beginn der statischen Berechnung gleich NULL sind, gehen diese Einflüsse in die lineare Steifigkeitsmatrix nicht ein (Ausnahme: Vorverformungen). Die Steifigkeitsmatrix wird nur einmal erstellt und bleibt dann konstant. Für eine nichtlineare Berechnung wird allerdings zu Beginn eines neuen Lastschrittes die Nachricht „update“ an das Element gesandt. Daraufhin löscht das Element seine bereits errechnete Matrix. Auf die Nachricht „assemble“ reagiert es also mit einer Neuberechnung der Matrix unter Einbeziehung der zu diesem Zeitpunkt aktuellen Verformungen bzw. des aktuellen Materialzustandes. 62 Globales Programmkonzept Abbildung 5-6: Aktivitätsdiagramm: Statische lineare Berechnung 5 Globales Programmkonzept Abbildung 5-7: Sequenzdiagramm: Statische lineare Berechnung 63 64 Globales Programmkonzept Abbildung 5-8: Aktivitätsdiagramm: Berechnung nach Theorie 2. Ordnung 5 Globales Programmkonzept Abbildung 5-9: Sequenzdiagramm: Berechnung eines Iterationsschritts nach Theorie 2. Ordnung 65 66 Globales Programmkonzept Abbildung 5-10: Aktivitätsdiagramm: Physikalisch nichtlineare Berechnung 5 Globales Programmkonzept Abbildung 5-11: Sequenzdiagramm: Berechnung eines Lastschrittes, physikalisch nichtlineare Berechnung 67 68 5.4 Globales Programmkonzept Erweiterbarkeit und Wiederverwendung Die Programmstruktur ist so angelegt, das eine Erweiterung des Programmsystems erleichtert wird. Diese Erweiterbarkeit betrifft sowohl die Ausweitung der Berechnung nach der Methode der Finiten Elemente als auch die Ausdehnung auf weitere Analyseverfahren. Die Ausweitung der FEM kann durch verschiedene Erweiterungen in der Klassenhierarchie geschehen. Die meisten Vererbungshierarchien in Abbildung 5-1 bis Abbildung 5-4 sind mit dem Zusatz {incomplete} bezeichnet. Das heißt, dass im Laufe des Lebenszyklus des Programms die Erweiterung der Vererbungsstruktur um zusätzliche Kindklassen erwartet wird. Dieses wird in einem FEM-Programmsystem vor allem die Klasse ElementFEM betreffen. Aber auch für ProblemDomain können weitere Kindklassen (oder Enkelklassen) eingefügt werden, die weitere nichtlineare Berechnungsverfahren implementieren. In den Namen der Klassen Element, Structure und ProblemDomain ist jeweils der Zusatz FEM vermerkt. Dieser ist notwendig, um bei einer Ausdehnung des Softwaresystems den Namensraum für gleichwertige Komponenten eines anderen Analyseverfahrens offenzuhalten. So werden z.B. für eine Berechnung nach der Methode der BoundaryElemente (BEM) die Klassen ElementBEM, StructureBEM und ProblemDomain in das Objektmodell miteingefügt werden. Klassen wie Matrix, Node, Dof, IntegrationPoint, Load und Loadcase sind zunächst unabhängig vom Berechnungsverfahren und können in einer Berechnung für die Methode der Boundary-Elemente wieder verwendet werden. An dieser Stelle wird der Vorteil des objektorientierten Entwurfes für ein Programmsystem zur Tragwerksanalyse deutlich. Erweiterungen für andere Elementtypen oder Berechnungsmethoden erfordern lediglich die Erweiterung der Klassenhierarchien. Die Schnittstellen bleiben in den meisten Fällen konstant oder werden höchstens um zusätzliche Funktionen erweitert. Wenn eine Klasse eine Methode anders als die Mutterklasse implementiert (z.B. wenn die Steifigkeitsmatrix im Element in direkter Form vorliegt und nicht durch Integration ermittelt wird) , kann die entsprechende Methode in der Kindklasse einfach überschrieben werden. Bei der Erweiterung auf weitere Analyseverfahren kann auf bereits bestehende Klassen zurückgegriffen werden, der Programmieraufwand verringert sich also. 6 Programmiersprachen 6 69 Programmiersprachen Im Folgenden soll die Implementierung des FEM-Softwaresystems mit verschiedenen Hochsprachen diskutiert werden. Als Kriterien bei der Auswahl einer Programmiersprache werden dabei • die Unterstützung des objektorientierten Programmierens, • die erreichbare Laufzeiteffizienz, • die Portabilität und • die Verbreitung der einzelnen Sprachen verglichen und bewertet. Dazu werden die folgenden Hochsprachen kurz vorgestellt und auf ihre Eignung zur Realisierung des zu erarbeiteten FE-Programms untersucht: 1. Prozedurale Programmiersprachen: FORTRAN und C 2. Genuine objektorientierte Programmiersprachen: Smalltalk und Eiffel 3. Hybride objektorientierte Programmiersprachen: Ada, C++ und Java Genuine objektorientierte Programmiersprachen sind Neuentwicklungen, die einen generellen Bruch mit den anderen bekannten Programmierstilen vollzogen haben und damit ausschließlich objektorientierte Programmierung erzwingen. Neben den genannten genuinen Programmiersprachen würden sich noch eine Reihe anderer rein objektorientierter Sprachen wie Sather, Beta, und Dylan anbieten. Sie zeichnen sich durch sehr moderne und konsistente Sprachmodelle aus, sind aber zum gegenwärtigen Zeitpunkt kaum verbreitet und werden darum nicht mit aufgenommen [28] Neben den genuinen existieren aber auch hybride – um objektorientierte Konzepte erweiterte – Programmiersprachen, die den oben formulierten Kriterien zur Realisierung objektorientierter Software genügen, aber zusätzlich konventionelle Konzepte der Sprache beibehalten, aus denen sie hervorgegangen sind. Zu dieser Klasse gehört z.B. C++ als Erweiterung der Sprache C [13]. Die Entwicklungslinien von Programmiersprachen werden in Abbildung 6-1 dargestellt. Die erste objektorientierte Programmiersprache war Simula. Diese hat die Entwicklung aller objektbasierten und –orientierten Programmiersprachen sehr stark beeinflusst. 70 Programmiersprachen Lambda Kalkül Assembler Logikkalküle Fortran 1960 Lisp Algol 60 Basic PL/1 Fortran IV Simula 67 Algol 68 1970 Pascal Smalltalk-72 g Prolog Smalltalk-74 g Smalltalk-76 1980 Flavors Smalltalk-78 Fortran 77 C Loops Smalltalk-80 C mit Klassen Common Lisp Ada g Objective C Common Loops C++ 1.xx New Flavors Eiffel Object Pascal Turbo Pascal CLOS C++ 2.xx Prolog++ 1990 Fortran 90 C++ 3.xx Java C++ 4.xx Ada 95 Objektbasierte g Sprache Fortran 95 funktional prozedural Objektorientierte Sprache logisch Abbildung 6-1: Entwicklungslinien der Programmiersprachen Unterstützung eines objektorientierten Programmierstils Objektorientierte Programmiersprachen werden genauer in objektbasierte, klassenbasierte und objektorientierte Sprachen unterteilt. Die Begriffsbestimmungen sind in der Literatur allerdings nicht eindeutig. Folgende Unterscheidungen werden nach Bannert/Weizel [1] angegeben: Objektbasiert: Sprachen heißen objektbasiert, wenn Objekte Daten und Methoden kapseln können und eine Objektidentität haben [1]. Das Abstraktionsprinzip wird nur dadurch unterstützt, dass Objekte erzeugt werden, die durch Nachrichten miteinander kommunizieren und Methoden ausführen. Dadurch werden Manipulationen des Zustands der Objekte vorgenommen [13]. 6 Programmiersprachen 71 Klassenbasiert: Sprachen heißen klassenbasiert, wenn sie objektbasiert sind und jedes Objekt zu einer Klasse gehört, wobei diese Klassen aber keine Oberklassen haben. Objektorientiert: Sprachen, die klassenbasiert sind, zusätzlich Vererbung zwischen Klassen ermöglichen und Polymorphie zulassen, heißen objektorientiert [1]. Objektorientierte Sprachen zeichnen sich durch ihre weitreichenden Fähigkeiten aus, neue Typen einzuführen und deren Eigenschaften realitätsnah abzubilden. Diese Eigenschaften umfassen im wesentlichen das Verhalten von Abstraktionen sowie die Repräsentation von Beziehungen zwischen Abstraktionen [28]. + Vererbung + Polymorphie + Klassen objektbasiert klassenbasiert z.B. Ada objektorientiert z.B. Eiffel, Smalltalk Abbildung 6-2: Objektbasierte, klassenbasierte und objektorientierte Programmiersprachen Typbindung Das wesentliche Charakteristikum der objektorientierten Programmierung ist die Fähigkeit, Objekte zu verwenden, die zur Laufzeit möglicherweise Objektwerte aus verschiedenen Objektklassen annehmen können. Dadurch kann die konkrete Zuordnung der Methodenimplementierung zu einer Nachricht an ein solches polymorphes Objekt erst zur Laufzeit durch die Klassenzugehörigkeit des zugeordneten Objektwertes bestimmt werden. Eine notwendige Voraussetzung für diese Eigenschaft ist die Möglichkeit, gleich benannte Methoden in verschiedenen Klassen unterschiedlich zu implementieren. Da in getypten Programmiersprachen Polymorphie auf abgeleitete Klassen eingeschränkt ist, muss die Möglichkeit der Klassenkonstruktion durch Ableiten ebenfalls gegeben sein (mit Vererbung und ggf. Redefinition von Methoden) [13]. Programmiersprachen werden entsprechend der Rolle, die die Typisierung dort spielt, in zwei Klassen unterschieden: statisch und dynamisch getypte Sprachen. In statisch getypten Programmiersprachen (FORTRAN, C++) wird den Variablen ein Typ in einer expliziten Deklaration zugewiesen und festgelegt, wie der Wert einer Variablen interpretiert und manipuliert werden kann. Bei der sogenannten dynamischen Typisierung wird die Typinformation nicht mit der Variablendeklaration abgelegt, sondern der Wert einer Variablen enthält seine Typinformationen. Funktionen können nun so programmiert werden, dass sie abhängig von der Typisierung ihrer Argumente unterschiedliche Aktionen durchführen können. 72 Programmiersprachen Bei dem Vergleich der beiden Typisierungsarten stehen Effizienz und Fehlererkennung der statischen Typisierung auf der einen Seite der Flexibilität der Programmentwicklung durch dynamische Typisierung auf der anderen Seite gegenüber. Der Vorteil bei der Verwendung von Polymorphie liegt auf der Hand: der Programmierer muss nicht mehr die gesamte verwendete Typmenge übersehen und hat somit größere Freiheiten bei der Codierung. Wenn neue Typen eingeführt werden, müssen nicht mehr alle Typisierungen von Identifikatoren überprüft werden, soweit sich der Programmierer sicher ist, dass in Folge einer Zuweisung dieser Variable mit Objekten der neuen Typen auch die darauf operierenden Funktionen ausführbar sind. Funktionen können, abhängig von der Typzugehörigkeit der Werte ihrer Argumente, verschieden reagieren, bzw. verschiedene Objekte können auf die gleiche Nachricht (d.h. gleichen Methodenaufrufwunsch) verschieden reagieren [13]. Im Folgenden werden die oben genannten Programmiersprachen vorgestellt. 6.1 Prozedurale Programmiersprachen 6.1.1 Fortran Fortran (FORmula TRANslation) ist die erste höhere Programmiersprache. Sie wurde zwischen 1954 und 1957 von einem IBM-Team für wissenschaftliche und algebraische Programmierung entwickelt. Das Hauptanliegen war, die umständliche und fehleranfällige Programmierung in Assembler zu vereinfachen. Da Computer damals vor allem zur Unterstützung mathematischer Berechnungen herangezogen wurden, sind die Sprachelemente stark an der Formelschreibweise der Mathematik orientiert. Die Nachfolger sind noch heute bei wissenschaftlichen Anwendungen, bei denen Berechnungen im Vordergrund stehen, dominierend. FEM-Programmsysteme oder damit verbundene Algorithmen in Fortran werden von den verschiedensten Autoren vorgestellt (Bathe [2], Krätzig [20]). Das Überleben von Fortran liegt zumindest teilweise daran, dass seine Compiler immer noch zu den effizientesten gehören, die verfügbar sind, da sie sehr schnellen Code erzeugen. Dies war auch eines der wichtigsten Ziele der ursprünglichen Entwicklungsbemühungen, da man zu der Zeit annahm, dass das Schreiben von Programmen in „höheren“ Sprachen im Vergleich zu Assemblersprachen oder direkt erzeugtem Maschinencode zu ineffizient sei. 6 Programmiersprachen 73 Fortran wurde in der Version Fortran IV 1966 international genormt (ISO), und überarbeitete Standards wurden 1977 (Fortran 77) bzw. 1991/92 (Fortran90) verabschiedet. Betrachtet man Fortran nach Kriterien, die heute eine „gute“ Programmiersprache ausmachen, so sind die frühen Versionen eher als unzureichend einzustufen. Die Möglichkeiten der Datenvereinbarung waren beschränkt, Ablaufsteuerung war nur teilweise möglich. Mit dem Fortran90-Standard wurde die Sprache erheblich verändert und um moderne Konzepte erweitert, die zu einer deutlichen Verbesserung führten. So wurde ein Modulkonzept realisiert, Steuerkonstrukte erhöhen die Lesbarkeit der Fortran-Programme und für Matrizenrechnung sind Sprachelemente vorgesehen. Datentypen, Operationen und rekursive Prozeduren können vom Benutzer definiert werden. Viele frühere Restriktionen (z.B. die Länge der Variablennamen) wurden aufgehoben oder verändert. Wie bereits erwähnt, steht Fortran in direkter Relation zu den Top-Down Entwurfsverfahren. Fundamentale Abstraktionseinheit ist das Unterprogramm. Ein objektorientiertes Programmsystem wie es in Kapitel 5 vorgestellt wurde, ist mit Fortran nur schwer und mit großem Aufwand zu realisieren. Um die Laufzeiteffizienz von Fortran auch für moderne Architekturen nutzen zu können, wurde 1992 eine Arbeitsgruppe gegründet, die einen neuen Sprachstandard erarbeiten soll, die unter anderem objektorientierte Erweiterungen und Sprachelemente für Parallelverarbeitung enthalten wird [22]. Der aktuelle Stand ist Fortran95 (ISO-Norm 1997), das allerdings nur eine minimale Änderung zu Fortran90 darstellt. Die nächste Revision (Fortran 2000) wird voraussichtlich 2004 veröffentlicht. Diese wird unter anderem ein ausgedehntes Exception handling beinhalten, eine verbesserte Interaktion mit C, das Erstellen von Datentypen z.B. für parametrisierte Typen, High performance numerische Berechnungen und Konzepte für die Objektorientierung [25]. Daher kann man vielleicht bald auch für Programmsysteme wie dem oben beschriebenen die hohe Effizienz dieser Sprache nutzen, ohne auf die Vorteile der objektorientierten Programmierung verzichten zu müssen. 6.1.2 C C wurde Anfang der 70er Jahre von Dennis Ritchie an den Bell Laboratories in New Jersey (USA) entwickelt. Ziel der Entwicklung war es, eine möglichst einfache und effiziente Programmiersprache zu schaffen. Als Ergebnis entstand eine relativ maschinennahe Sprache, die die Effizienz von Assemblersprachen und wichtige Konzepte höherer Programmiersprachen wie Algol und Pascal in sich vereint. Der Sprachumfang von C ist eher klein. So gibt es keine Operationen, die direkt zusammengesetzte Objekte wie 74 Programmiersprachen Arrays, Records oder Zeichenketten als Ganzes verarbeiten. Des weiteren besitzt C keine Anweisungen für die Ein-/Ausgabe oder eingebaute Zugriffstechniken für Dateien. All diese Operationen werden durch explizit aufzurufende Funktionen realisiert, die in umfangreichen Bibliotheken zur Verfügung stehen. Auffallend sind die im Sprachumfang enthaltenen Operationen für die Bitmanipulation, wie sie von maschinenorientierten Sprachen her bekannt sind. Obwohl C ursprünglich für die Systemprogrammierung verwendet wurde (z.B. Unix), stellt C eine allgemeine höhere Programmiersprache dar. Die Gründe für die weite Verbreitung liegen einerseits in der Effizienz, vor allem aber in der Portabilität der CProgramme. Compiler für C sind auf fast allen modernen Rechnern und Betriebssystemen verfügbar. 1990 wurde C international standardisiert, allerdings gibt es im Vergleich zu anderen Programmiersprachen sowieso kaum C-Dialekte, soweit der engere Sprachkern betrachtet wird. Die in C verwendeten Kontrollstrukturen sind einfach. Sie reichen dennoch aus, um wohlstrukturierte Programme zu erstellen. Darüber hinaus erlaubt C die getrennte Übersetzung von Programmteilen, so dass die modulare Entwicklung größerer Programmsysteme unterstützt wird. Im Gegensatz zu anderen Programmiersprachen legt C dem Programmierer nur wenig Restriktionen auf. Zum Beispiel existiert kein strenges Typkonzept. Allerdings besteht gerade aufgrund dieser hohen Flexibilität und der zahlreichen Freiheitsgrade die Gefahr, dass Programme schnell unleserlich und in hohem Maße unverständlich werden [22]. 6.2 Genuine objektorientierte Programmiersprachen 6.2.1 Smalltalk Smalltalk wurde seit den 70er Jahren am Xerox PARC (Palo Alto Research Center) entwickelt. Zusätzlich zu den Eigenschaften anderer Sprachen beinhaltet Smalltalk auch eine Entwicklungsumgebung. Innerhalb dieser Umgebung, die Vorläuferin für alle heute bekannten grafischen Benutzungsoberflächen ist, stehen Grundklassen, ein symbolischer Debugger und der volle Zugriff auf alle vorhandenen Klassen zur Verfügung [9]. Smalltalk kennt im Prinzip nur einen Typ, nämlich den Typ Objekt, das heißt alle Konstrukte werden als Objekte und ihre Typen als Klasse interpretiert [1]. Das bedeutet, dass auch Klassen ihrerseits Objekte sind. Alle Daten innerhalb von Klassen sind geschützt, 6 Programmiersprachen 75 es können nur Methoden exportiert werden. Attribute werden nur in neueren Versionen mehrfach vererbt. Smalltalk zeichnet sich durch eine durchgehend dynamische Typ- und Methodenbindung aus. Generische Klassen sind nicht notwendig, da die Sprache typenlos ist. Sie erlaubt polymorphe Zugriffe und eine automatische Speicherbereinigung. Nebenläufigkeit wird nicht unterstützt. Smalltalk ist eine Sprache, bei deren Entwicklung auf Portabilität hohen Wert gelegt wurde, sie wird sowohl interpretiert als auch compiliert. Der Smalltalk-Code wird zunächst in einen Byte-Code übersetzt und dann durch eine Smalltalk Virtual Machine interpretiert. Die Stärke von Smalltalk ist eine Entwicklungsumgebung, die extrem gut für schnelle Prototypenentwicklung geeignet ist. Als Nachteil wird gesehen, dass diese Umgebung relativ geschlossen ist. Eine Anbindung bestehender Programme aus anderen Programmiersprachen ist nur schwer zu erreichen [9]. 6.2.2 Eiffel Die Programmiersprache Eiffel wurde mit dem Ziel der Robustheit, Korrektheit, Portierbarkeit und Effizienz entworfen. Aus Effizienzgründen dient als Zwischensprache bei der Übersetzung die Sprache C. Im Gegensatz zu Smalltalk werden Klassen und Objekte unterschieden. Klassen entsprechen, wie oben definiert, der Implementierung abstrakter Datentypen. Durch die Unterscheidung zwischen der Klasse als Typ und einem Objekt als Laufzeitelement wird eine statische Typ- und Methodenbindung eingeführt. Sie erlaubt weniger Laufzeitfehler und erwirkt eine größere Effizienz der Programme. Methoden und Daten der Klassen werden explizit zugänglich gemacht. Herausragende Eigenschaften von Eiffel sind generische Klassen und die Zusicherungen über Objekte in Form von Vor- und Nachbedingungen sowie Invarianten. Diese Zusicherungen dienen dem Nachweis der Korrektheit von Programmen und werden auch an Kindklassen vererbt. Mehrfache Vererbungen sind gestattet. Konflikte in mehrfach geerbten Attributen werden durch Umbenennung gelöst. Weiterhin erlaubt die Sprache polymorphe Zugriffe und stellt eine automatische Speicherverwaltung zur Verfügung. Nebenläufigkeit ist nicht möglich. Die Persistenz von Objekten wird nur über eine Bibliotheksfunktion realisiert und ist daher noch nicht zufriedenstellend gelöst. Trotz der vermeintlich großen Vorteile durch die Zusicherung von Bedingungen und der effizienten Umsetzung durch die Zwischensprache C wird Eiffel für den Einsatz in kommerziellen 76 Programmiersprachen Anwendungen eher schlecht beurteilt. Für Ausbildungszwecke wird sie inzwischen erfolgreich eingesetzt [9]. 6.3 Hybride objektorientierte Programmiersprachen 6.3.1 Ada Ada geht auf eine internationale Ausschreibung des amerikanischen Verteidigungsministeriums zurück, das die Entwicklung einer einzigen, gemeinsamen, höheren Programmiersprache für die Softwareentwicklung propagierte; sie ist seit 1983 verfügbar. Unmittelbare Vorfahren von Ada sind u.a. Pascal und Simula [5]. Von Ada existieren keine Dialekte, da Ada bereits genormt wurde, bevor Ada-Übersetzer entwickelt werden konnten. Zusätzlich ist der Name Ada® als eingetragenes Warenzeichen des amerikanischen Verteidigungsministeriums geschützt. Ada entstand in der „Blütezeit“ des Software Engineering und kommt daher den Anforderungen an eine gute Programmiersprache sehr nahe. Der Einsatzbereich deckt nicht nur die traditionelle Datenverarbeitung ab, sondern auch andere Anforderungen, wie z.B. aus der Prozesssteuerung und aus dem militärischen Bereich. Entsprechend ihren Designern wurde Ada unter Berücksichtigung der Gesichtspunkte Zuverlässigkeit, Wartbarkeit und Effizienz von Programmen entworfen. Vor allem die Herstellung umfangreicher Programmsysteme, die im Allgemeinen arbeitsteilig in Teams erfolgt, sollte vereinfacht werden. Aus diesem Grund ist ein ausgefeiltes Modulkonzept (Packages) realisiert, das die Zerlegung komplexer Systeme, die Spezifikation der Module und die getrennte Entwicklung und Übersetzung derselben unterstützt. In Verbindung mit dem Modulkonzept ist es möglich eigene strukturierte Datentypen einzuführen (abstrakte Datentypen). Ada gehört zu den objektbasierten Programmiersprachen, das heißt Daten und Methoden werden in den Objekten gekapselt. Ada ist eine extrem typenstrenge Sprache, Polymorphie ist nicht möglich. Auch Vererbung ist durch die Objektbasiertheit kein Element des ursprünglichen Konzepts von Ada. Persistenz von Objekten wird nicht unterstützt. Dafür sind in Ada generische Konstrukte zugelassen [5]. 1995 wurde Ada erneut genormt. In dem neueren Standard sind aktuelle Entwicklungen berücksichtigt. Sprachelemente für die objektorientierte Programmierung wurden erweitert oder neu aufgenommen (z.B.Vererbung) sowie die bestehenden Konzepte für Datentypen 6 Programmiersprachen 77 und Parallelverarbeitung weiter ausgebaut und stabilisiert [22]. Ada95 hat sich damit von einer objektbasierten zu einer objektorientierten Sprache entwickelt. 6.3.2 C++ C++ ist eine hybride Programmiersprache. Im Prinzip ist C++ die Erweiterung der Sprache C um objektorientierte Konzepte mit dem Entwurfsziel der Portabilität und der Effizienz. Das Ergebnis ist ein Kompromiss zwischen dem objektorientierten Ideal und Pragmatismus. Wesentliche Merkmale sind das Überladen von Operatoren, so dass z.B. mit Objekten wie mit ganzen Zahlen „gerechnet“ werden kann. Der Zugriff auf Attribute von Objekten kann gesteuert werden. Eine spezielle Deklaration kann Klassen gegenseitig oder anderen Funktionen zugänglich machen. Eine automatische Speicherplatzverwaltung ist allerdings nicht vorgesehen [9]. Der bedeutendste Vorzug von C++ ist die Flexibilität zwischen hardwarenahen Funktionen und den abstrakten, objektorientierten Konzepten sowie die weite Verbreitung der Sprache (ca. 80% des Marktes für objektorientierte Sprachen). Letzteres liegt nicht zuletzt an der Aufwärtskompatibilität zu C. Bestehende, in C implementierte Systeme können um C++-Software erweitert werden. Diese Aufwärtskompatibilität ist andererseits auch das wesentlichste Problem von C++. Objektorientiertes Programmieren kann durch die nach wie vor möglichen konventionellen Konzepte umgangen werden. Untersuchungen von AT&T, die C++ ursprünglich erstellten, zeigen, dass nur etwa jedes zehnte Programm, das in C++ geschrieben wird, überhaupt auf Klassen und damit auf ein Grundkonstrukt der Objektorientierung in C++ zurückgreift [9]. Ein Problem ergibt sich auch aus dem Zwang, die grundlegenden Mechanismen der Sprache C zu erlernen, um die objektorientierten Konzepte von C++ anwenden zu können [13]. Die Vorzüge der objektorientierten Programmierung können durch die Verwendung bestimmter Optimierungsmöglichkeiten im Programm eingeschränkt werden. Hinzu kommt, dass einige objektorientierte Konzepte nicht unterstützt oder nur simuliert werden (dynamischer Polymorphismus) [1]. Hier bietet eine genuine Sprache wie Eiffel oder Smalltalk sicher reichere Konzepte. Um z.B. polymorphe Variablen zu realisieren, muss also auf jeden Fall der Speicherbereich von der Variablen abgekoppelt werden. Hierzu werden sogenannte Zeigertypen benutzt: eine Variable nimmt jetzt nur einen Verweis auf ein Objekt (also auf dessen Speicherbereich) aus. Wird an das durch die Variable so referenzierte Objekt eine Nachricht gesendet, werden zur Laufzeit – wie in dynamisch getypten Sprachen 78 Programmiersprachen – Typinformationen vom Wert der Variablen eingeholt und die passende Methode aufgerufen. Deswegen nennt man dieses auch das dynamische Binden einer Methode an eine Nachricht. Die Effizienznachteile bestehen hier aber auch [13]. C++-Compiler sind ebenfalls weit verbreitet. Eine Einbindung von Programmcode in Fortran oder C ist möglich. Speziell für das Arbeiten mit dem in C implementierten Betriebssystem Unix ergibt sich der Vorteil des leichten Zugangs zu den umfangreichen Betriebssystembibliotheken über die C-Schnittstelle. Ebenso wie C-Code gilt C++-Code als sehr effizient und portabel [13]. Die Grundsprache C++ ist wie C grundsätzlich plattformunabhängig. Zu dieser Grundsprache gehören allerdings nur Konsolenbefehle. Sobald eine Oberfläche einbezogen wird, ist ein Umstieg von einem Betriebssystem zu einem anderen schwierig. Dieses Problem wird durch Eigenkreationen wie z.B. die MicrosoftFoundationClasses (MFC) weiter verschärft. In den letzten Jahren wurde neben der Sprache auch eine Klassenbibliothek normiert, welche die wichtigsten Anforderungen der objektorientierten Programmierung unterstützen soll. Diese Klassenblibliothek (STL – „standard template library“) ist inzwischen Bestandteil aller wichtigen Entwicklungsumgebungen [9]. 6.3.3 Java Java wurde unter dem Gesichtspunkt der Sicherheit, Robustheit und der portablen Anwendbarkeit in heterogenen Rechnernetzen entwickelt. Dadurch ist sie heute zu einem Synonym für eine Programmiersprache „für das Internet“ geworden. Die Entwicklung erfolgte ab 1990 und führte 1993 zu einer ersten Veröffentlichung als Programmiersprache, die im Rahmen von HTML-Seiten interpretiert werden kann. Java ist einerseits Programmiersprache und stellt andererseits eine Klassenbibliothek zur Verfügung. Die Klassenbibliothek von Java enthält Klassen für die Erstellung von Applikationen, also beispielsweise einfache Oberflächenelemente, Klassen für die Kommunikation, zur Ausnahmebehandlung sowie für die Grafik- und Netzwerkprogrammierung. Als Programmiersprache lehnt sie sich stark an C++ an. Viele der Konstrukte dieser Sprache wurden jedoch aus Sicherheitsgründen modifiziert bzw. eliminiert. Hierzu gehört die Abschaffung von Verweisen („pointer“), die immer eine Quelle der Unsicherheit bei der Programmierung darstellen. Funktionen außerhalb von Klassen sind nicht erlaubt, so dass keine Verwirrung darüber entstehen kann, ob ein Aufruf sich auf eine Methode oder auf eine Funktion bezieht. 6 Programmiersprachen 79 „Offene“ Klassen, also die in C++ vorhandenen Strukturen, sind, ebenso wie automatische Typkonvertierungen, nicht Bestandteil der Sprache. Mehrfachvererbung ist ebenfalls nicht möglich, allerdings bietet Java eine automatische Speicherplatzverwaltung [9]. Da die Sprache ein besonderes Ausführungsmodell verwendet, werden alle Datentypen zunächst plattformunabhängig definiert, d.h. in Größe und Interpretation vereinheitlicht. Über einen Compiler wird der Java-Code in einen portablen Byte-Code übersetzt (ähnlich zu Pascal), der bei der Ausführung auf einem beliebigen Rechner durch eine dort vorhandene generische Java Virtual Machine interpretiert wird. Dieses beinhaltet einen Verlust an Laufzeiteffizienz gegenüber fertig kompilierten Programmsystemen und ist daher für FEMProgramme ungeeignet. Allerdings gibt es bereits verschiedene Ansätze die Laufzeiteffizienz von Java zu steigern: Zum einen wird an der Entwicklung besonderer Mikroprozessoren gearbeitet, deren Befehlssatz dem Java Byte-Code entspricht. Zum anderen existieren bereits Systeme, die den Programmcode während der Ausführung des Programms übersetzen (Just-in-time-compilation). Daher kann man vielleicht bald auch für FEM-Programmsysteme die Portabilität dieser Sprache nutzen, ohne hohe Verluste in der Laufzeiteffizienz in Kauf nehmen zu müssen [28] 6.4 Vergleich und Auswertung Ein wichtiges Kriterium für die Wahl einer Programmiersprache für den Programmentwurf aus Kapitel 5 ist die Menge der Sprachelemente, die sie für eine objektorientierte Programmierung zur Verfügung stellt. Die Objektorientierung ist letztendlich ein Programmierstil und nicht abhängig von der Sprache in der sie umgesetzt wird, allerdings beruht die Topologie der meisten Programmiersprachen mehr oder weniger auf den Konzepten eines bestimmten Programmierstiles (vgl. Kapitel 3). Programmiersprachen die ebenfalls objektorientiert arbeiten, unterstützen einen objektorientierten Entwurf wesentlich besser als konventionelle Programmiersprachen wie z.B. Fortran, die als fundamentale Abstraktionseinheit Unterprogramme verwendet und in direkter Relation zu einem prozedurorientierten Programmierstil und den angesprochenen Top-Down Entwurfsverfahren steht [28]. Eine Realisierung des Entwurfes in Fortran würde letztendlich nur Abstraktionen auf einem wesentlich niedrigeren Level als für eine objektorientierte Programmierung notwendig zulassen. Damit könnten die oben genannten Vorteile einer objektorientierten 80 Programmiersprachen Programmierung (Modularität, Wiederverwendbarkeit, Übersichtlichkeit usw.) nicht genutzt werden. Um alle Vorteile der objektorientieren Programmierung zu nutzen, bietet sich eine (genuine) objektorientierte Programmiersprache an. Eine Kurzübersicht über die Sprachelemente, die die verschiedenen objektorientierten Sprachen zur Verfügung stellen, gibt die Tabelle 6-1. In diesem Fall wäre Smalltalk die Sprache der Wahl, da sie insgesamt eine saubere objektorientierte Programmierung erzwingt und ausreichend Konzepte zur Verfügung stellt. Ein einfaches objektorientiertes FEM-Programm in Smalltalk wurde bereits 1992 von Dubois-Pélerin und Zimmermann [12] vorgestellt. Smalltalk Eiffel Ada(83) C++ Java + + + + + + - + + - + + + + + + + + + -, + -, + -, + -, #, + -, #, + -, + -, + Modularität - Unit Package Datei Package Vererbung + + - + + Mehrfachvererbung - + - + - Ja (einfach) + - + + d s s s/d s/d indirekt - + indirekt + Persistenz - - - - - Generizität - + + + - Abstraktion Instanzvariable Instanzmethode Klassenvariable Klassenmethode Kapselung Variablen Methoden - private, # protected, + public Polymorphismus Typbindung s: statisch , d: dynamisch Nebenläufigkeit Tabelle 6-1: Objektorientierte Konzepte der verschiedenen Hochsprachen Legt man bei der Wahl der Programmiersprache das Hauptaugenmerk auf die zu erreichende numerische Effizienz, dann werden objektorientierte Sprachen gegenüber den prozeduralen eher schlecht beurteilt. Die prozedurale Programmierung lehnt sich an die Organisation der Operationen und Daten im Computer selber an, ist also bei der Ausführung effizienter als eine objektorientierte Programmstruktur. Die hohen Abstraktionsebenen (Kapselung, Hierarchie) gehen auf Kosten der Rechengeschwindigkeit. Bei einer Implementierung in Smalltalk beeinträchtigen zusätzlich die dynamische Typisierung und 6 Programmiersprachen 81 die Interpretation des Programmcodes (anstatt Kompilierung) die Laufzeiteffizienz. Die Entwicklungsumgebung ermöglicht zwar das schnelle Erstellen eines Prototyps, verhindert aber das Einbinden vorhandener Algorithmen z.B. aus Fortran oder C. Insgesamt wird eine Implementierung eines FEM-Programmes für praktische Anwendungen in Smalltalk ungünstig beurteilt [11]. Tabelle 6-2 (aus [19] und [25]) vergleicht Geschwindigkeit und Strukturen der Programmiersprachen C, C++ und Fortran77 bzw. 95 für numerische Berechnungen. Fortran77 und Fortran95 dominieren dabei mit ihren hochoptimierten Compilern in Bezug auf die erreichbare Effizienz. C hat weiterhin den gravierenden Nachteil, dass dynamische Matrizen langsam und unhandlich sind und keine weitergehenden Strukturen für numerische Berechnungen vorhanden sind. Außerdem ist das Erreichen einer guten Laufzeiteffizienz unter anderem vom Programmierstil (und damit von der Erfahrung des Programmierers) abhängig. Für ein Optimum an numerischer Effizienz wird man also auf einen prozeduralen Programmierstil und eine Programmiersprache wie Fortran zurückgreifen. FEM-Programme in Fortran sind weit verbreitet und werden von den verschiedensten Autoren vorgestellt. Ein Entwurf wie er in Kapitel 5 vorgestellt wird, kann in Fortran allerdings bis jetzt nicht verwirklicht werden. Es bleibt abzuwarten, ob der neue Standard 2004 genügend Konstrukte für objektorientierte Programmierung enthält, um eine solche Programmstruktur zu verwirklichen. Eine Programmierung mit einer hybriden objektorientierten Programmiersprache, z. B. C++, kann einen guten Kompromiss zwischen den Vorzügen einer objektorientierten Programmierung und einer guten Laufzeiteffizienz bieten (vgl. Tabelle 6-2: Eignung für numerische Berechnung: Fortran77, Fortran 90, C, C++). Wichtig für die Wahl von C++ ist, dass C++ alle wesentlichen Vorzüge der objektorientierten Programmierung sicherstellt, durch seine Verwandtschaft mit C aber eine relativ hohe Geschwindigkeit erreichen kann. Ein effizienter Programmcode in C++ wird durch den umfassenden Gebrauch der Konzepte einer objektorientierten Programmierung und der Optimierung für einige wenige zeitkritische Operationen erreicht. Für diese Optimierung wird auf die niedrigen Abstraktionsgrade (“low-level“-Konstrukte) der prozeduralen Programmierung zurückgegriffen, die C++ von C geerbt hat (vgl. Abbildung 6-3). Es findet also eine Vermischung eines objektorientierten Entwurfs mit prozeduralen Programmiertechniken statt. 82 Programmiersprachen Besonderheiten • C dynamische Matrizen langsam (indirekte Adressierung) oder unhandlich weit verbreitet bei SystemProgrammierern keine besonderen Abstraktionen für Numerik Parametrisierung von Klassen mittels Templates Überladen von Operatoren komplexe Zahlen, schnelle Vektoren kleine Bibliothek für Numerik die Sprache für objektorientierte Numerik Potenzierungsoperator: A**B komplexe Zahlen überladene Standardfunktionen lange die Sprache für numerische Anwendungen große vorhandene Basis an Programmen und Bibliotheken programmiertechnisch veraltet Matrixfunktionen abstrakte Datentypen incl. Operatoren portable Standardtypen incl. komplexer Zahlen (fast) kompatibel zu Fortran77 und 90 (alte Programme, Bibliotheken) • • • C++ • • • • Fortran77 • • • • • Fortran95 Geschwindigkeit • • • • • • Compiler-Optimierung auf höherer Ebene oft nicht effektiv schneller Code möglich durch Handoptimierung (``hardwarenah'') • • fast wie C (mit guten Compilern und optimierter Programmierung) • • Matrixoperationen sehr schnell hochoptimierende Compiler verfügbar • so schnell wie FORTRAN77 Tabelle 6-2: Eignung für numerische Berechnung: Fortran77, Fortran 90, C, C++ Ein Nachteil dieses Vorgehens ist, dass einige Vorteile der Objektorientierung (klare Strukturierung sowie Datenkapselung und Abstraktion) abgeschwächt werden. Zusätzlich hängt der Erfolg der Optimierung für rechenintensive Prozesse wie bei C weitgehend vom Programmierstil ab. Eine effiziente Implementation in C++ erfordert also erfahrene Programmierer. Abstraktion Sprachelemente hoch Datenkapselung Klassenvererbung mittel Einfache Datenstrukturen Sprachen C/ Fortran 95 C++ Fortran77 Standardprozeduren niedrig Zeiger Abbildung 6-3: Abstraktionslevel in Smalltalk, C++, Fortran, C [32] Smalltalk 6 Programmiersprachen 83 Dubois-Pélerin et al. stellen in ihrem Artikel [12] Vergleichsrechnungen zwischen zwei FEM-Programmen an. Das eine ist in Fortran (prozedural) geschrieben, das andere in C++ (objektorientiert); beide Programme haben einen vergleichbaren Umfang. Die Aufstellung der Systemmatrizen für ein Referenzproblem findet im FortranProgramm wie erwartet wesentlich schneller statt (ca. 30%). Im objektorientierten Programm wird die Aufstellung der Systemmatrizen an die Elemente delegiert, was eine Vielzahl von gesendeten Methodenaufrufen bedingt. Dieser Overhead an Nachrichten verlangsamt die Aufstellung der Matrizen. Im Gegenzug bewältigt das C++-Programm die Lösung des Gleichungssystems zügiger (ca. 20%). Insgesamt gibt es Einbußen in der Gesamtlaufzeit des Berechnungskernes bei einer Implementierung eines FEM-Programms in C++. Dem gegenüber stehen nach wie vor die bereits genannten Vorteile der objektorientierten Programmierung in C++ (Wartung des Programms, Erweiterbarkeit, vereinfachte Fehlersuche und –korrektur etc.) [32]. Für das folgende Beispiel wird C++ als Programmiersprache gewählt. C++ stellt alle notwendigen objektorientierten Konzepte zur Verfügung, um den in Kapitel 5 vorgestellten Entwurf zu verwirklichen. Es können alle Vorteile, die sich aus einer objektorientierten Programmstruktur ergeben, genutzt werden. Zusätzlich bietet die Sprache die Möglichkeit, für rechenintensive Prozesse auf prozedurale Strukturen zurückzugreifen. Bereits vorhandene Algorithmen in C oder Fortran können in das Programm eingebunden werden. Zudem ist C++ (z.B. im Vergleich zu Ada) eine weit verbreitete Sprache und Compiler stehen für nahezu jedes Betriebssystem zur Verfügung. 84 Protokolle und Dokumentation 7 Protokolle und Dokumentation Das Endergebnis eines Entwurfsprozesses ist ein Dokument, das aus verschiedenen Diagrammen der UML besteht und das gesamte System vollständig beschreibt. Diese Beschreibung ist die Basis für die Implementierung. Dazu müssen die bisher erhaltenen Ergebnisse verfeinert und auf Konsistenz geprüft werden. Für alle Klassen wird das genaue Verhalten festgelegt. Anschließend werden alle Klassen und Teilsysteme auf Formularen festgehalten. Die Dokumentation des Entwurfs besteht aus • den statischen Entwurfssichten (Klassendiagramme u.a.), • den dynamischen Entwurfssichten (Aktivitätsdiagramme, Sequenzdiagramme u.a.) und • der Spezifikation der Klassen. Für jede Klasse wird ein eigenes Protokoll erstellt. In diesem Protokoll werden die Attribute und Methoden der Klasse vollständig beschrieben. Es sind alle Spezifikationen enthalten, die in den UML-Diagrammen beschrieben werden. Die Informationen, die dieses Protokoll enthalten soll, sind wie folgt gegliedert: 1. Klasse: (abstrakt/konkret) 2. Elternklasse(n): 3. Kindklasse(n): 4. Spezifiziert in Diagrammen: 5. Verantwortlichkeit: 6. Wird assoziiert von Klasse: 7. Assoziiert Klasse: 8. Attribute 9. 8.1. Privat 8.2. Geschützt 8.3. Öffentlich Methoden 9.1. Privat 9.2. Geschützt 9.3. Öffentlich Bei der Verwirklichung eines Entwurfes in C++ kann dieses Protokoll direkt in die Implementierung übernommen werden. Die einzelnen Methoden der Klassen werden in 7 Protokolle und Dokumentation 85 einer Datei (*.cpp) unabhängig von der Klassendefinition implementiert. Sie sind nur über die entsprechende Header-Datei (*.hpp) zugänglich, die diese Methode für die Klasse definiert. Die Header-Dateien bilden also auch die Schnittstelle einer Klasse zu den anderen Klassen. Die Header werden analog zum erarbeiteten Protokoll strukturiert. Dies ermöglicht einen schnellen Übergang vom Entwurf zur Implementation. Die Informationen werden dabei als Kommentar an den Anfang der Datei gestellt oder als Notiz an die entsprechende Stelle in den Code gesetzt. Für eine Programmierung in arbeitsteiligen Teams ist es zudem notwendig, in der Header-Datei die Information über die vorliegende Version, das letzte Bearbeitungsdatum und den Bearbeiter zu vermerken. Dieses ist besonders wichtig, wenn bei Klassen während der Implementation noch Schnittstellen verändert werden. Für jede Versionsänderung sollte zusätzlich ein neues schriftliches Klassenprotokoll erstellt werden, das explizit die vorgenommenen Änderungen beschreibt. Zur Dokumentation des Programmcodes gehört auch eine konsistente Namensgebung für Attribute und Methoden, sowie der Klassen. Es gilt: • Für konzeptionell gleiche Methoden werden gleiche Methodennamen benutzt • Für konzeptionell gleiche Attribute werden gleiche Attributnamen benutzt • Attributnamen bestehen (soweit möglich) aus o der Bedeutung des Attributes im „realen“ Problemfeld oder aus dem Namen des Objektes, das es referenziert o den Datentyp bzw. der Klasse des Attributs (falls nicht trivial) o dem Präfix is oder has falls es ein Boolean ist • Methodennamen bestehen (soweit möglich) aus o der Aktion, die die Methode ausführt (Berechnung, Einlesen, Auslesen u.ä.). Hier wurde verwendet: get : Abfragen von Attributen assoziierter Klassen starten (oder Auslesen aus Datenfile) give: Das Ausgeben eigener Attribute compute: Berechnung von Attributen assemble: Einlesen lokaler Attribute zu einem Gesamtsystem (FEM-spezifisch) solve: Lösen eines Gleichungssystems o das Attribut auf das es vornehmlich zugreift 86 Protokolle und Dokumentation • Attribute, Variablen und Methodennamen beginnen mit einem Kleinbuchstaben • Klassennamen beschreiben o das Objekt des „realen“ Problemfeldes, das sie darstellen oder o die Aufgabe, die sie im Entwurf wahrnehmen • Klassennamen beginnen mit einem Großbuchstaben • Es werden möglichst keine oder nur allgemein übliche Abkürzungen benutzt Die Einhaltung dieser Benennungsregeln erleichtert das Nachvollziehen von fremden Entwürfen. Besonders die Einführung von Abkürzungen sollte vermieden werden. Diese erleichtern zwar zunächst die Arbeit (z.B. weniger Schreibarbeit, weniger Schreibfehler), sind aber für andere Programmierer oder Anwender nur schwer nachzuvollziehen. Die Dokumentation der Methoden in der Implementierungsdatei (*.cpp) erfolgt Methode für Methode. Hierbei wird die Information • Version-Nr.: • Letzte Bearbeitung am: • Bearbeiter: festgelegt und wenn vom Gesamtdokument abweichend auch für einzelne Methoden notiert. Beispiele für die Umsetzung dieser Regeln finden sich in der Dokumentation des Beispielprogramms in Kapitel 8. Zusätzlich findet sich im Anhang ein exemplarisches Klassenprotokoll. Dort wird die Aufgabe der Klasse, ihre Einbindung in die Klassenhierarchie und ihre Schnittstelle beschrieben. Zusätzlich wird anhand der Dokumentation einer fiktiven Schnittstellenerweiterung bzw. Implementationsänderung die Versionskontrolle dargestellt. 8 Beispielprogramm 8 87 Beispielprogramm Das erarbeitete Beispielprogramm AllTA (Allgemeine Tragwerks-Analyse) setzt - in vereinfachter Form - den in den Kapitel 5 vorgestellten Programmentwurf in der Programmiersprache C++ um. Die Klassenhierarchie des Programms ist soweit ausgebaut, dass ein dreidimensionales Stabwerk mit der Methode der finiten Elemente berechnet werden kann. Als Elementtyp ist mit der Klasse Beam3D ein räumliches schubstarres Balkenelement implementiert Der Aufbau der Hierarchie ist entsprechend dem Entwurf sehr offen gehalten. Eine Erweiterung des Programmsystems um weitere Elementtypen oder Methoden der Berechnung ist mit begrenztem Programmieraufwand möglich. Zur Überprüfung des Programms wurden vier ebene Rahmen mit unterschiedlichen Belastungen und Systemangaben mit AllTA berechnet. Die Ergebnisse wurden dann mit dem zum Vergleich herangezogenen Stabwerksprogramm 4H-NISI der pcae-GmbH kontrolliert. Die errechneten Knotenverschiebungen und –verdrehungen, sowie die Schnittgrößenverläufe über die Stabelemente stimmen für die Anzahl der ausgegebenen Nachkommastellen zu 100% überein. Die Ausgaben sowohl von AllTA als auch dem Vergleichsprogramm sind im Anhang zu finden. Im Folgenden wird Eingabe und Ausgabe des Programms AllTA kurz erläutert. Der Quellcode aller Klassen (Header-Dateien und Implementations-Dateien) ist ebenfalls im Anhang zu finden. Die Header-Dateien sind durchgehend dokumentiert und enthalten im Prinzip die in Kapitel 7 angesprochenen Klassenprotokolle. Da es sich allerdings bei den Klassen jeweils um Version 1.0 handelt, wird im Anhang noch ein fiktives Klassenprotokol beigefügt, das exemplarisch die Dokumentation der Erweiterung der Klasse ElementFEM beinhaltet. Die angenommene Versionsänderung enthält zwei Ausweitungen: - die Einfügung eines neuen Elementtypes (eine neue Kindklasse) und - die Berechnung der Element-Steifigkeitsmatrix durch numerische Integration. Die numerische Integration ist im vorliegenden Programm noch nicht verwirklicht, da die einzig bisher vorhandene Kindklasse (Beam3D) ihre Steifigkeitsmatrix direkt berechnet. 8.1 Dateneingabe Die Dateneingabe erfolgt über eine Datei, in dem alle Informationen über die Struktur und das zu lösende Problem spezifiziert werden. Der Input-File hat einen beliebigen Namen 88 Beispielprogramm und ist vom Typ '*.dat' . Der Name der Datei muss dem Programm beim Starten als Parameter übergeben werden, dabei entfällt die Endung. Der Input-File enthält verschiedene Abschnitte, die jeweils mit einem 'Keyword' anfangen. Die Reihenfolge dieser Abschnitte im Input-File ist unerheblich. Abschnitte enden mit einer Zeile, die zwei Sternchen enthält (**). Die bereits implementierten Keywords sind: - Structure - Node - Material - Profile - ElementFEM - Load Jede Zeile in einem Abschnitt enthält jeweils die Daten für ein Objekt der zu erstellenden Struktur. Mit Ausnahme vom Abschnitt Structure fängt jede Zeile mit der Nummer des Objektes an. Ebenfalls mit Ausnahme von Abschnitt Structure folgt auf jedes Keyword die Anzahl der Objekte, die in diesem Abschnitt definiert werden. Im Abschnitt Structure wird ausgelesen, welche Kindklasse von Structure erstellt wird und welcher Art die Berechnung sein soll, d.h. welche Unterklasse von ProblemDomain von Structure referenziert wird. Die übrigen Abschnitte repräsentieren die verschiedenen Komponenten einer (FEM-) Struktur. Das letzte Zeichen einer Zeile in einem Abschnitt ist ein Sternchen (*). Die Zahlenwerte in einer Zeile werden über ihre direkt vorangestellten Namen identifiziert (z.B. 'E 200000' bei Material). Kommentare können überall zwischen oder nach Zeilen eingefügt werden, sie sollten allerdings kenntlich gemacht werden. Sie dürfen allerdings nie zwischen dem Namen eines Zahlenwertes und dem Zahlenwert selber stehen. An Einheiten gebundene Werte müssen konform eingegeben werden. Abschnitt Structure Keyword-Zeile: Structure Daten-Zeile: Analysis Type [Structure] [ProblemDomain] * Structure : =FEM (weitere noch nicht implementiert) ProblemDomain : =static (weitere noch nicht implementiert) 8 Beispielprogramm 89 Abschnitt Node Keyword-Zeile: Node [n] n: Anzahl der Knoten Daten-Zeile: [i] nDofs [nDof] coord [nc c1 c2 … cnc ] fix [nf f1 f2 … fnf ] load [nl l1 l2 … lnl ] * i: nDof: nc: c1 c2 ... cnc: nf: f1 f2 … fnf : nl : l1 l2 … lnl : Nummer des Knotens Anzahl der Freiheitsgrade an diesem Knoten Anzahl der Koordinaten Knotenkoordinaten Anzahl der gebundenen Freiheitsgrade Nummern der gebundenen Freiheitsgrade Anzahl der Knotenlasten Nummern der Knotenlasten Abschnitt Material Keyword-Zeile: Material [n] n: Anzahl der Materialien Daten-Zeile: [i] E [E-Modul] G [G-Modul] * i: E-Modul: G-Modul: Nummer des Materials Elastizitätsmodul Schubmodul Abschnitt Profile Keyword-Zeile: Profile [n] n: Anzahl der Querschnitte Daten-Zeile: [i] Type [ProfilTyp] [h] A [A] Iy [Iy] Iz [Iz] IT [IT] * i: ProfilTyp: h: A: Iy: Iz: IT: Nummer des Querschnitts =free Æ Explizite Eingabe der Attribute =IPE, HEA, HEB Æ Auslesen aus Bibliothek Höhe des Querschnitts (zum Auslesen aus Bibliothek) Querschnittsfläche Tragheitsmoment um die y-Achse Tragheitsmoment um die z-Achse Tragheitsmoment um die x-Achse (Stabachse) 90 Beispielprogramm Abschnitt ElementFEM Keyword-Zeile: ElementFEM [n] n: Anzahl der Elemente Daten-Zeile: [i] Type [ElementTyp] nodes [n1 … nN] pro [pro] mat [mat] load [nl l1 l2 … lnl ] * i: ElementTyp: n1 ... nN: mat: pro: nl : l1 l2 … lnl : Nummer des Querschnitts =Beam3D (weitere noch nicht implementiert) Knotennummern (Anzahl abhängig von ElementTyp) Nummer des Materials Nummer des Profils Anzahl der Elementlasten Nummern der Elementlasten Abschnitt Load Keyword-Zeile: Load [n] n: Anzahl der Lasten Daten-Zeile: [i] Type [LastTyp] [Verlauf] comp [nc c1 c2 … cnc ] Lc [nl l1 l2 … lnl ] * i: LastTyp: Verlauf: nc : c1 c2 … cnc : nl: l1 l2 … lnl : Nummer der Last =ElementLoad, NodalLoad der Verlauf von Lasten über die Stabachse (bei ElementLoad) =const (weitere noch nicht implementiert) Anzahl der Lastkomponenten (=Anzahl Dof bei Node !) Lastkomponenten Anzahl der Lastfälle zu denen die Last gehört Nummer der Lastfälle Beispiel für eine Input-Datei (siehe Kontrollrechnungen): #Datei unsym_rahmen.dat # Einheiten: kN, m Structure Analysis Type FEM static * ** Node 4 1 nDofs 6 2 nDofs 6 3 nDofs 6 4 nDofs 6 ** Material 1 coord 3 0. 0. 0. coord 3 0. 0. 9. coord 3 12. 0. 0. coord 3 15. 0. 9. fix 3 2 4 6 load 1 2 * fix 6 1 2 3 4 5 6 * fix 3 2 4 6 * fix 6 1 2 3 4 5 6 * 8 Beispielprogramm 91 1 E 10000e+03 G 0.8e+08 * ** Profile 1 1 Type free A 0.05 Iy 0.01 Iz 1 IT 1 ** ElementFEM 3 1 Type Beam3D mat 1 nodes 2 1 pro 1 load 1 1 * 2 Type Beam3D mat 1 nodes 1 3 pro 1 * 3 Type Beam3D mat 1 nodes 3 4 pro 1 * ** Load 2 1 Type ElementLoad const comp 6 0. 0. 8. 0. 0. 0. Lc 1 1 * 2 Type NodalLoad comp 6 10. 0. 0. 0. 0. 0. Lc 1 2 * ** 8.2 Datenausgabe Die Datenausgabe erfolgt in einer Datei, die denselben Namen trägt wie die InputDatei, allerdings vom Typ '*.log ' ist. Zur Kontrolle werden noch einmal alle Komponenten der Struktur mit ihren Attributen ausgegeben. Danach erfolgt die Ausgabe der Verschiebungen und Verdrehungen der Knoten und die Stabkräfte für jeden Lastfall. Für die Stabkräfte wird der Wert an Stabanfang, -mitte und –ende ausgegeben. Output-Dateien sind im Anhang eingefügt. 92 Literaturverzeichnis Literaturverzeichnis [1] Gabriele Bannert, Martin Weitzel Objektorientierter Softwareentwurf mit UML Addison Wesley Longman Verlag GmbH, München 1999 [2] Klaus-Jürgen Bathe Finite-Element-Methoden Springer-Verlag Berlin Heidelberg 1990 [3] H. Beem, K. Brink, B. Lechtleitner FEMAS: Finite Element Moduln Allgemeiner Strukturen Ruhr-Univerität Bochum 1981 [4] Christoph Butenweg, Carsten Ebenau Entwicklung eines objektorientierten FE-Programms Forum Bauinformatik 2000-Junge Wissenschaftler Forschen Fortschritt-Berichte VDI: Reihe 4, Bauingenieurwesen VDI-Verlag, Düsseldorf 2000 [5] Grady Booch Objektorientierte Analyse und Design Addison-Wesley, Bonn, Paris [u.a.], 1994 [6] Grady Booch, Jim Rumbaugh, Ivar Jacobson Das UML-Benutzerhandbuch 2.Auflage, Addison-Wesley-Longman, Bonn [u.a.] 1999 [7] Rostislav Chudoba Finite Element Kernel with Metaobject Protocol aus: Modern Software Tools for Scientific Computing Birkhäuser, Boston, Basel, Berlin 1997 [8] Rotislav Chudoba, Z. Bittnar, P. Krysl Explicit finite element computation: An object-oriented approach Computing in Civil and Building Engineering, Pahl & Werner (eds), S. 139-145 Balkema, Rotterdam 1995 [9] Ute Claussen Objektorientiertes Programmieren 2. aktual. Ausgabe, Springer-Verlag, Berlin [u.a.] 1998 [10] Guido Drexel Hierarchische Strukturierung: Objektorientierte Programmierung am Beispiel CheOPS http://www.sme.de/papers/oop-cheops.html#opattern Stand 1997, (02.08.2001) Literaturverzeichnis 93 [11] Yves Dubois-Pèlerin, Thomas Zimmermann, Patricia Bomme Object-oriented finite element programming: II. A prototype programm in Smalltalk Computer Methods in Applied Mechanics and Engineering, Vol. 98, S. 361-397 Elsevier Science Publishers B.V. 1992 [12] Yves Dubois-Pèlerin, Thomas Zimmermann Object-oriented finite element programming: III. An efficient implementation in C++ Computer Methods in Applied Mechanics and Engineering, Vol. 108, S. 165-183 Elsevier Science Publishers B.V. 1993 [13] Helmut Eirund Objektorientierte Programmierung B.G. Teubner Stuttgart 1993 [14] Gisela Engeln-Müllges, Fritz Reutter Numerik-Algorithmen mit ANSI C-Programmen BI-Wissenschaftsverlag, Mannheim, Leipzig, Wien, Zürich 1993 [15] Otto von Estorff Unterlagen zur Vorlesung: Nonlinear Structures Stand: Wintersemester 1999/2000 Arbeitsbereich Meerestechnik II, Technische Universität Hamburg-Harburg [16] Gregory L. Fenves Object-Oriented Programming for Engineering Software Development Engineering with Computers, Vol. 6, S. 1- 15 Springer-Verlag New York Inc. 1990 [17] Bruce W. R. Forde, Ricardo O. Foschi, Siegfried F. Stiemer Object-oriented Finite Element Analysis Computers & Structures, Vol. 34, S. 355-374 Civil-Comp Ltd and Pergamon Press plc 1990 [18] Till Jeske Nitty-Gritty: C++ Addison-Wesley, München, Boston [u.a.] 2000 [19] Peter Junglas Programmiersprachen für numerische Software – ein Überblick http://www.tu-harburg.de/rzt/tuinfo/programmentwicklung/sprachen/numsoft/master.html Stand vom 08.10.1999, (03.09.2001) [20] Wilfried B. Krätzig Tragwerke 2: Theorie und Berechnungsmethoden statisch unbestimmter Stabtragwerke 3. Auflage, Springer-Verlag Berlin Heidelberg 1997 [21] Wilfried B. Krätzig, Yavuz Başar Tragwerke 3: Theorie und Anwendung der Methode der Finiten Elemente Springer-Verlag Berlin Heidelberg 1997 94 Literaturverzeichnis [22] Karl Kurbel Programmierung und Softwaretechnik Addison-Wesley, Bonn [u.a.] 1997 [23] Kenneth C. Louden Programmiersprachen: Grundlagen, Konzepte, Entwurf 1. Auflage, International Thomson Publishing GmbH, Bonn 1994 [24] G. R. Miller An Object-oriented Approach to Structural Analysis and Design Computers & Structures, Vol. 40, Nr. 1, S. 75-82 Civil-Comp Ltd and Pergamon Press plc 1991 [25] NAG – Numerical Algorithms Group Revision of ISO/IEC 1539-1 : 1997 (Information technology - Programming languages - Fortran) http://www.nag.co.uk/sc22wg5/IS1539-1_200x.html, (03.09.2001) [26] Bernd Oesterreich Objektorientierte Softwareentwicklung: Analyse und Design mit der Unified Modeling Language 4., aktual. Ausgabe, R. Oldenburg Verlag 1998 [27] Rational Software Corporation UML Resource Center http://www.rational.com/uml/index.jsp (03.09.2001) [28] Georg Schmid Zur Entwicklung objektorientierter Finite-Elemente-Programme Institut für Statik und Dynamik der Luft- und Raumfahrtkonstruktionen Universität Stuttgart, Stuttgart 1998 [29] U. Starossek Vorlesungsunterlagen zur Vorlesung Baustatik II Stand: Sommersemester 2001 Arbeitsbereich Statik und Dynamik der Baukonstruktionen, Technische Universität Hamburg – Harburg [30] Bjarne Stroustrup Die C++ Programmiersprache 4., aktual. Ausgabe, Addison-Wesley, München, Boston [u.a.] 2000 [31] Rebecca Wirfs-Brock, Brian Wilkerson, Lauren Wiener Objektorientiertes Software-Design Carl Hanser Verlag München Wien, Prentice-Hall International Inc., London 1993 [32] Thomas Zimmermann , Yves Dubois-Pèlerin, Patricia Bomme Object-oriented finite element programming: I.Governing principles Computer Methods in Applied Mechanics and Engineering, Vol. 98, S. 291-303 Elsevier Science Publishers B.V. 1992 Anhang Anhang A. Unified Modeling Language (UML 1.4) Notationsübersicht B. Quellcode des Programms AllTA C. Vergleichsrechnungen D. Fiktives Klassenprotokoll der Klasse ElementFEM 95 A. Unified Modeling Language (UML 1.4) Notationsübersicht B. Quellcode des Programms AllTA Reihenfolge der beigefügten Klassendeklarationen und –definitionen: Hauptprogramm: Struktur: allta.cpp struc.hpp struc.cpp struc_fem.hpp struc_fem.cpp comp.hpp comp.cpp Knoten: node.hpp node.cpp Material: material.hpp material.cpp Querschnitt: profile.hpp profile.cpp Finite Elemente: elem_fem.hpp elem_fem.cpp beam3D.hpp beam3D.cpp Lastfälle: loadcase.hpp loadcase.cpp Lasten: load.hpp load.cpp nodal_load.hpp nodal_load.cpp elem_load.hpp elem_load.cpp Freiheitsgrade: dof.hpp dof.cpp Berechnungssteuerung: problem_domain.hpp problem_domain.cpp Basisklasse für Struktur-Komponenten Komponenten: static_fem.hpp static_fem.cpp Mathematische Klassen: matrix.hpp Hilfsklassen: string.hpp string.cpp point.hpp point.cpp file_reader.hpp file_reader.cpp C. Vergleichsrechnungen Es folgen die Ausgaben von AllTA und 4H-NISI für zwei einfache Systeme: 1. symmetrischer ebener Rahmen mit • Einzelkraft am Knoten • konstanter Elementlast 2. unsymmetrischer ebener Rahmen • Einzelkraft am Knoten • konstanter Elementlast D. Fiktives Klassenprotokoll der Klasse ElementFEM Selbständigkeitserklärung Diese Diplomarbeit mit dem Titel „Konzeption und Realisierung eines zeitgemäßen Programmsystems zur allgemeinen Tragwerksanalyse“ wurde von mir im Studiengang Bauingenieurwesen und Umwelttechnik an der Technischen Universität Hamburg-Harburg im Sommersemester 2001 angefertigt. Sie besteht aus 94 Seiten plus Anhang und einer CD, die das in C++ geschriebene Beispielprogramm und Beispieldateien enthält. Die Diplomarbeit wurde von mir ausschließlich unter Zuhilfenahme der im Literaturverzeichnis aufgeführten Literatur verfasst und ist bisher weder an dieser noch an anderen Universitäten bewertet worden. Kathrin Telkamp Matr.-Nr.: 9952
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
Related manuals
Download PDF
advertisement