Einführung in die Programmierung mit Fortran
Transcrição
Einführung in die Programmierung mit Fortran
Einführung in die Programmierung mit Fortran Markus Meuwly Michael Devereux Stefan Willitsch Department of Chemistry University of Basel Fortran Ziel / Motivation Sie sollten in der Lage sein: • Einfache Programme zur Lösung naturwissenschaftlicher Probleme zu schreiben, zu kompilieren und zu benutzen. Weshalb Programmieren? • Geschwindigkeit • Genauigkeit • Flexibilität Fortran übersicht • Einführung • Auswertung von Funktionen (function, subroutine) • Numerische Differentiation • Numerische Integration • Matrixoperationen Fortran übersicht Die Programmiersprache Fortran ist eine sog. “höhere Programmiersprache” im Gegensatz zu Assembler. Es gibt von Fortran verschiedene “Dialekte” Fortran I, II, IV Fortran 66 Fortran 77 Fortran 90, 95, 2000, 2003, 2008, 2010 Wir werden uns mit Fortran 77 beschäftigen. Neben Fortran gibt es noch C, C++, welche im high performance computing verwendet werden. Allen höheren Programmiersprachen gemein ist die Tatsache, dass ein Computerprogramm in der entsprechenden Sprache geschrieben wird und dann durch einen Compiler in ein ausführbares Programm übersetzt wird. Fortran Allgemeine Programmstruktur program test !Name des Programms Implicit none !Ausschalten der autom. Type conversion Integer i !Deklaration einer integer-Zahl Real*8 r !Deklaration einer reellen Zahl Complex cn !Deklaration einer komplexen Zahl Character c1 !Deklaration eines alphanumerischen String Etc… Input !Eingabe/Einlesen von Daten Instructions !Anweisungen Output !Ausgabe der Resultate end !Ende des Programms Fortran Allgemeine Programmstruktur Einige Merkmale von Fortran: Gute Programmierpraxis ist es, die automatische Typenkonversion auszuschalten. So vermeidet man eine Vielzahl von Fehlern. Also: implicit none In Fortran 77 beginnen die Instruktionen in der 7. Spalte des Editors – manche Editoren erkennen dies selbständig. In späteren Fortran Versionen fällt dieser Umstand weg. Die erste Spalte kann für Kommentare verwendet werden: C This is a comment and will not be interpreted by the compiler Die maximale Zeilenlänge sind 80 Zeichen; ist ein Kommando länger, muss es umgebrochen und fortgesetzt werden; das Fortsetzungszeichen “&” steht in der 6. Spalte: x = tanh(sin(x))-dble(i)*erf(x)*dexp(-sin(x))* & x**2-4*x Fortran unterscheidet nicht zwischen Gross- und Kleinschreibung Fortran Eingabe/Ausgabe Anweisungen Format: Read(nunit,format) Write(nunit,format) Open(nunit,name) Close(nunit) nunit ist eine Zahl, welche es erlaubt, ein bestimmtes File anzusprechen (s. Open) Format ist eine Formatierungsanweisung, welche es z. B. erlaubt, eine gewisse Anzahl Stellen bei der Ausgabe von Resultaten anzuzeigen. Beispiele: Open(unit=3,file=‘name.dat’) Read(3,*) zahl Read(3,100) zahl 100 format(f12.5) C F12.5 steht fuer floating point (reelle Zahl) C mit insgesamt 12 Stellen und 5 Stellen nach dem Komma write(22,101) zahl 101 format(f10.4) Fortran Kompilieren und Ausführen von Programmen Zweck ist es, aus dem Quellcode (“lesbar”) ein ausführbares Programm (“nicht-lesbar”) zu machen. Das “executable” run wird aus dem Quellcode run.f folgendermassen erzeugt: >gfortran –o run run.f Dabei steht “>” für den Cursor unter UNIX. Von der Kommandozeile aus wird das Programm folgendermassen ausgeführt (”laufen gelassen”): >./run Benötigt das Programm einen “input” – also sollen Daten extern eingelesen werden – so geschieht dies mittels einer “Pipe”. Dabei wird der input input.dat mit “<“ hinein-gepiped und der output mit “>” in eine output-datei umgeleitet (statt auf Bildschirm geschrieben). >./run < input.dat > output.dat Aufgabe: Programm zur Berechnung der Flaeche eines Kreises mit Eingabe des Radius. Fortran Einfache Funktionen und Prozeduren Sobald Programme etwas umfangreicher werden, empfiehlt es sich, gewisse Teile in Funktionen und Unterprogramme auszulagern. Die erlaubt es auch, wiederkehrende Aufgaben effizient zu erledigen. Bei einer function wird am Ende dem Funktionsnamen ein entsprechender Wert zugewiesen Beispiele: Suchen von Nullstellen mittels Newton-Raphson Diagonalisieren von Matrizen Die allgemeine Struktur einer function function f(…) ! Name der function muss mit Wert am Ende übereinstimmen Deklarationen ! Wieder mit implicit none etc. Anweisungen !argumente werden verarbeitet f=… … return end Fortran Einfache Funktionen und Prozeduren Im Gegensatz zu einer function wird dem Namen einer subroutine kein Wert zugewiesen. Vielmehr werden zur Ein- und Ausgabe die Argumente der subroutine verwendet. Die allgemeine Struktur einer subroutine subroutine name(…) !name sollte die Aufgabe/Methode widerspiegeln Deklarationen Anweisungen … return end Beispiele sind Diagonalisieren von Matrizen, Ordnen einer Liste Aufgaben Programm zur Auswertung einer algebraischen Funktion Programm zur Nullstellenberechnung Fortran Einfache Funktionen und Prozeduren Beim Auswerten von Funktionen ist auf numerische Instabilitäten zu achten. Zum Beispiel ist die Auswertung des Ausdrucks x +1 − x für grosse x unstabil, da für grosse x die Differenz zwischen x +1 − x ≈ x und x-1 sehr klein wird; dementsprechend ginge das 1 2 1 1 1 2 Resultat gegen 0, was jedoch nicht sein kann, was eine 1 + x − x + .. − 1 + (x − 1) − (x − 1) + .. 8 8 2 2 Taylorentwicklung zeigt: 1 5 1 1 1 = − x + + .. = − x + .. 8 8 4 2 4 Die numerisch stabile Variante ist: x +1 − x = ( x +1 − x ) (( ) ) x +1 + x = x +1 + x 1 x +1 + x Diese Probleme werden unter dem Begriff “numerische Auslöschung” oder “cancellation” zusammengefasst. Weitere Beispiele, die durch verschiedene mathematische Umformungen in stabile Varianten übergeführt werden können sind: Für kleine x; entwickle sin(x) in Taylorreihe Für kleines e; forme mit Trigonometrie um Für grosses x; erweitern – siehe oben Fortran sin x x sin(x + ε ) − sin x 1 1 − x x +1 Einfache Funktionen und Prozeduren: Finden von Nullstellen Finden von Nullstellen mittels • Bisection • Regula Falsi • Newton Raphson Bei den ersten beiden Methoden nutzt man aus, dass das Produkt der Funktionswerte das Vorzeichen ändern muss, wenn dazwischen eine Nullstelle ist. Bisection: Dann wird ein dritter Punkt zwischen x1 und x2 definiert und die Vorzeichenänderung verfolgt. Auf diese Art kann das Intervall immer enger eingeschränkt. (x1, x 2 ) f (x1 ) > 0; f (x 2 ) < 0 f (x1 )f (x 2 ) < 0 Regula Falsi: Hier wird eine lineare Interpolation gemacht, für welche ein neuer, verbesserter unterer Wert analytisch bestimmt werden kann: (x1, x 2 ) f (x1 ) < 0; f (x 2 ) > 0 x f (x ) − x 2f (x1 ) x~1 = 1 2 f (x 2 ) −f (x1 ) Die beiden ersten Methoden unterscheiden sich dadurch, wie rasch sie konvergieren. Newton Raphson x k +1 = x k − Fortran f (x k ) f ′(x k ) Einfache Funktionen und Prozeduren FUNCTION rtnewt(x0,xacc) implicit none ! Newton-Raphson Funktion real*8 x0,xacc integer JMAX,j real*8 rtnewt,df,dx,f external funcd parameter (JMAX=50) ! Deklaration der externen Variablen ! Deklaration der internen Variablen rtnewt=x0 ! Start-Wert do j=1,JMAX print*,'cycle ',j,'r_trial=',rtnewt call funcd(rtnewt,f,df) dx=f/df rtnewt=rtnewt-dx if(abs(dx).lt.xacc) return enddo ! DO-LOOP (root-finding) ! Deklaration der Funktions-Subroutine ! Def. Parameters; Anzahl Iterationen ! Call Morse-Subroutine 'funcd' ! Convergence ! Ende des Loops print*,'rtnewt exceeded maximium iterations (',JMAX,')' END ! Ende der Funktion Fortran Einfache Funktionen und Prozeduren program main implicit none Deklarationen Eingabe Anweisungen ! Incl. calls to subroutines etc. Ausgabe End C-------------------Subroutine sb1(arguments) implicit none Deklarationen Eingabe !Oft unnötig, da in “arguments” übergeben Anweisungen Ausgabe !Oft nur als test End C--------------------Function fct1(arguments) implicit none Deklarationen Eingabe !Oft unnötig, da in “arguments” übergeben Anweisungen Ausgabe !Oft nur als test C-------------------------Weitere subroutines und functions Fortran Numerische Ableitung und Integration Sind Funktionen nur auf einem diskreten Gitter bekannt (beispielsweise durch Messen einer Grösse als Funktion der Temperatur welche nicht kontinuierlich reguliert werden kann), so stellt sich das Problem, Ableitungen numerisch zu berechnen. Die dazu üblichen Formeln heissen “finite differences”. Wenn man die einfache Definition einer ersten Ableitung unkritisch anwendet, können die Ableitungen sehr ungenau werden. 2 Fehlerquellen führen dazu Abschneidefehler Rundungsfehler Ein stabiler Algorithmus wird in den Uebungen vorgestellt. Aufgabe: Programm zur numerischen Ableitung einer algebraischen Funktion Newton-Raphson mit numerischer statt analytischer Ableitung Fortran Numerische Ableitung und Integration f ′(x ) ≈ f (x + h ) − f (x ) h Probleme: Wenn man blind einen Wert für h einsetzt, ergeben sich numerische Instabilitäten, da sich x und x+h nicht beliebig genau im Rechner darstellen lassen. Es ist sicherer, bei gegebenem x, die Schrittweite h durch folgende Konstruktion zu bestimmen: tmp = x+h h=tmp-x Durch Verwenden einer symmetrisierten Formel für die Ableitung erhält man ebenfalls eine Stabilisierung: f ′(x ) ≈ Fortran f (x + h ) − f (x − h ) 2h Numerische Ableitung und Integration Numerische Integration ist eine wichtige Disziplin in der numerischen Behandlung von naturwisenschaftlichen Problemen. Man unterscheidet dabei zwei Kategorien: Die Integrationspunkte sind regelmässig verteilt Numerische Quadraturen – die Punkte sind nicht gleichmässig verteilt. In allen Fällen wird ein Integral durch eine Summe approximiert. Auf einem äquidistanten Gitter xi=x0+ih ergeben sich die Trapezregel und die Simpson Regel, welche Polynome ersten, zweiten und dritten Grades exakt integrieren. Für andere Funktionen ergeben diese Formeln einen Näherungswert für das Integral. x2 1 1 1 4 ∫ f (x )dx ≈ h 2 f 1 + 2 f 2 x1 x3 ∫ f (x )dx ≈ h 3 f 1 + 3 f 2 + 3 f 3 x1 Fortran 1 Numerische Ableitung und Integration Für die Romberg Integration wird der Fehlerterm in der Simpson-Regel explizit behandelt, und zwar durch eine Polynominterpolation. Aufgabe: Programm, welches nacheinander das Integral einer Funktion ueber ein endliches Intervall mit der Trapezregel, der Simpson Regel und der Romberg Integration berechnet. Hinweise zur Lösung der Aufgaben: Sie erhalten mehrere subroutines trapzd, qtrap, qsimp, qromb, polint Diese können Sie unverändert verwenden. Beim Kompilieren müssen diese Programme mit an das Hauptprogramm gelinkt werden: gfortran –o prog main.f trapzd.f etc…. Dabei ist main.f Ihr Hauptprogramm. Fortran Numerische Ableitung und Integration program main implicit none Real*8 func,a,b,s a=xx b=xx call qsimp(func,a,b,s) write(6,*) ‘Wert des Integrals ‘,s end C-------------------function func(x) implicit none real*8 func,x func=xxxx return end Fortran Matrixoperationen Matrizenrechnung ist eine weitere wichtige Anwendung. Dabei stehen folgende Operationen im Vordergrund: Matrixmultiplikation Lösen linearer Gleichungssysteme Diagonalisierung (Eigenwerte, Eigenvektoren) Aufgaben Programm zur Matrixmultiplikation Lösen eines linearen Gleichungssystems (Gauss Elimination) Fortran Matrixoperationen Eine Matrix ist ein rechteckiges Schema welches reelle oder imaginäre Zahlen enthält. In Fortran wird eine Matrix folgendermassen deklariert: Real*8 a(2,2) Dieses Statement deklariert eine 2x2 Matrix. Dieses Schema entspricht der folgenden Anordnung: a11 a12 a21 a22 Computertechnisch heissen Matrizen allgemeiner “arrays”. Sie können auch mehr als 2 Indizes aufweisen: Real*8 a(2,2,4,2) Ausdrücke, welche in Matrixform geschrieben werden, sind Ihnen beim Lösen von Gleichungssystemen begegnet: 5 x + 3y = 1 5 3 x 1 = − 2 x + y = 4 − 2 1 y 4 (x = −1, y = 2) Beachten Sie, dass die Indizierung von arrays von “1” losgeht. Das erste Element in einem array ist also a11 und nicht a00. Sollte es notwendig sein, kann man die Indizes auch von “0” weg laufen lassen: Real*8 a(0:2,0:2) Fortran Matrixoperationen Nachdem die Matrix deklariert wurde, muss sie mit Werten gefüllt werden. Dies geschieht auf die übliche Weise einer Zuordnung. Ein kleines Beispielprogramm: Program matrix Implicit none Real*8 a(2,2) A(1,1) = 1.d0 A(1,2) = 0.d0 A(2,1) = 0.d0 A(2,2) = 1.d0 end Dieses Fragment definiert eine 2x2 Einheitsmatrix. I.a. sind für diesen speziellen Fall “do-loops” vorgesehen: Fortran Matrixoperationen Program matrix Implicit none Real*8 a(2,2) Integer I,j Do I = 1,2 Do j = 1,2 A(I,j) = 0.d0 If (I .eq. j) a(I,j) = 1.d0 Enddo Enddo end In der Uebungsaufgabe sollen Sie ein Gleichungssystem lösen. Dazu werden Ihnen wieder einige subroutines zur Verfügung gestellt. Die Aufgabe besteht demzufolge darin, die Matrix A sowie den Lösungsvektor b mit entsprechenden Werten zu füllen und diese an die subroutine zu übergeben, welche das Gleichungssystem löst. Fortran