補足:RUNGE KUTTA法 只木進一 佐賀大学総合情報基盤センター 知能情報システム学特別講義
RUNGE KUTTA法 一階常微分方程式の数値解法
4次のRunge Kutta法
( ),dy f x ydx
=
( ) ( ) ( )
( )( )
( )
( )
( )( )
1 2 3 4
1
2 1
3 2
4 3
2 2
,
,2 2
6
,2 2,
k k k
f x y x
h hk f x y x k
h hk f x y x k
k f x
hy
h y x h
x h y x
k
k
k + + +
=
= + +
= + +
= +
+ = +
+
連立微分方程式への拡張
( ),d y f x ydx
=
( ) ( ) ( )( )( )
( )
( )
( )( )
1 2 3 4
1
2 1
3 2
4 3
2 2
,
,2 2
2
6
,2
,
k k k
f x y x
h hk f x y x k
h hk f x y
hy x h y x k
k
x k
k f x h y x hk
+ = +
+ + +
=
= + +
= + +
= + +
JAVAでの実装 注意点
関数ポインタを引数で渡すことができない 一階微分(微分方程式の右辺)を計算するメソッドを持ったクラスを渡す インターフェイスを定義する
微分方程式を定義するインターフェイス
package rungeKutta; /** * Runge Kutta法で用いる微分方程式のインターフェイス * @author tadaki */ public interface EvolutionEquation { public double[] derivatives(double x,double y[]); }
( ),d y f x ydx
=
RUNGE KUTTA法の本体 public static double[] rk4( double x, double y[], double h, EvolutionEquation eq) { int n = y.length; double hh = h / 2.; double h6 = h / 6.; double k1[] = eq.derivatives(x, y); double xh = x + hh; double yt[] = new double[n]; for (int i = 0; i < n; i++) {yt[i] = y[i] + hh * k1[i];} double k2[] = eq.derivatives(xh, yt); for (int i = 0; i < n; i++) {yt[i] = y[i] + hh * k2[i]; } double k3[] = eq.derivatives(xh, yt); for (int i = 0; i < n; i++) {yt[i] = y[i] + h * k3[i]; } double k4[] = eq.derivatives(x + h, yt); double yy[] = new double[n]; for (int i = 0; i < n; i++) { yy[i] = y[i] + h6 * (k1[i] + 2. * k2[i] + 2. * k3[i] + k4[i]); } return yy; }
サンプル1:単振動 元の微分方程式
連立微分方程式化
解
22
2
d xdt
xω= −
2
dx ydtdy xdt
ω
=
= −
( ) ( )sint ax tω θ= +
public class SimpleCircle implements EvolutionEquation { private double x; private double v; private double omega; public SimpleCircle(double x, double v, double omega) { this.x = x; this.v = v; this.omega = omega; } @Override public double[] derivatives(double x, double[] y) { double dy[] = new double[2]; dy[0] = y[1]; dy[1] = -omega * omega * y[0]; return dy; } }
サンプル2:等加速度運動 元の微分方程式
連立微分方程式化
解
2
2
d xdt
a=
dx ydtdy adt
=
=
( ) 20 02
at tx v t x+ +=
public class Parabola implements EvolutionEquation { private double x; private double v; private double accel; public Parabola(double x, double v, double accel) { this.x = x; this.v = v; this.accel = accel; } @Override public double[] derivatives(double x, double[] y) { double dy[] = new double[2]; dy[0] = y[1]; dy[1] = accel; return dy; } }
おまけ:ファイルへの出力
FileOutputStream OutputStreamの派生クラス
System.out PrintStreamのインスタンス
OutputStreamの派生クラス
BufferedWriter
OutputStreamWriter
OutputStream
FileOutputStream f = new FileOutputStream( new File(“output.txt”));
public static void printPointsList(List<Point2D.Double> points) throws IOException { printPointsList(points, System.out); } public static void printPointsList(List<Point2D.Double> points, OutputStream oStream) throws IOException { BufferedWriter out = new BufferedWriter( new OutputStreamWriter(oStream)); printPointsList(points, out); } public static void printPointsList(List<Point2D.Double> points, BufferedWriter out) throws IOException { for (int i = 0; i < points.size(); i++) { Point2D.Double p = points.get(i); StringBuilder b = new StringBuilder(); b.append(p.x).append(" ").append(p.y); out.write(b.toString()); out.newLine(); } out.flush(); }
RungeKutta.java
package rungeKutta;
/** * 4th order Runge-Kutta method * @author tadaki */public class RungeKutta {
/** * One step from x to x + h * @param x initial value of independent valiable * @param y initial values of dependent valiables * @param h step * @param eq class contains differential equations * @return next values of dependent valiables */ public static double[] rk4( double x, double y[], double h, EvolutionEquation eq) { int n = y.length; double hh = h / 2.; double h6 = h / 6.; double k1[] = eq.derivatives(x, y); double xh = x + hh; double yt[] = new double[n]; for (int i = 0; i < n; i++) { yt[i] = y[i] + hh * k1[i]; } double k2[] = eq.derivatives(xh, yt); for (int i = 0; i < n; i++) { yt[i] = y[i] + hh * k2[i]; } double k3[] = eq.derivatives(xh, yt); for (int i = 0; i < n; i++) { yt[i] = y[i] + h * k3[i]; } double k4[] = eq.derivatives(x + h, yt); double yy[] = new double[n]; for (int i = 0; i < n; i++) { yy[i] = y[i] + h6 * (k1[i] + 2. * k2[i] + 2. * k3[i] + k4[i]); } return yy; }
/** * solve by rk4 from x1 to x2 with nstep * @param vstart start values of dependent valiables * @param x1 initial value of independent valiable * @param x2 final value of independent valiable * @param nstep the number of steps between x1 and x3 * @param eq class contains differential equations * @return sequence of values of dependent valiables */ public static double[][] rkdumb( double vstart[], double x1, double x2, int nstep, EvolutionEquation eq) {
1/2 ページ
RungeKutta.java
int n = vstart.length; double y[][] = new double[n][nstep]; double v[] = new double[n]; for (int i = 0; i < n; i++) { v[i] = vstart[i]; y[i][0] = v[i]; } double xx[] = new double[nstep]; xx[0] = x1; double x = x1; double h = (x2 - x1) / nstep; for (int t = 1; t < nstep; t++) { double vout[] = rk4(x, v, h, eq); if ((double) (x + h) == x) { System.err.println("too small step"); } x += h; xx[t] = x; for (int i = 0; i < n; i++) { v[i] = vout[i]; y[i][t] = v[i]; } } return y; }}
2/2 ページ
EvolutionEquation.java
package rungeKutta;
/** * * @author tadaki */public interface EvolutionEquation { public double[] derivatives(double x,double y[]);}
1/1 ページ
Parabola.java
package samples;
import java.awt.geom.Point2D;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.util.ArrayList;import java.util.Collections;import java.util.List;import rungeKutta.EvolutionEquation;import rungeKutta.RungeKutta;import utils.FileIO;
/** * * @author tadaki */public class Parabola implements EvolutionEquation {
private double x; private double v; private double accel;
public Parabola(double x, double v, double accel) { this.x = x; this.v = v; this.accel = accel; }
public List<Point2D.Double> evlution(double t, int nstep) { double y[] = new double[2]; y[0] = x; y[1] = v; double yy[][] = RungeKutta.rkdumb(y, 0., t, nstep, this); List<Point2D.Double> points = Collections.synchronizedList( new ArrayList<Point2D.Double>()); double dt = t / nstep; for (int i = 0; i < nstep; i++) { double tt = i * dt; points.add(new Point2D.Double(tt, yy[0][i])); } return points; }
@Override public double[] derivatives(double x, double[] y) { double dy[] = new double[2]; dy[0] = y[1]; dy[1] = accel; return dy; }
/** * @param args the command line arguments */
1/2 ページ
Parabola.java
public static void main(String[] args) throws IOException { Parabola sys = new Parabola(0., 0., 1.); double t = 10.; int nstep = 10000; try (FileOutputStream fStream1 = new FileOutputStream( new File("output.txt"))) { List<Point2D.Double> points = sys.evlution(t, nstep); FileIO.printPointsList(points, fStream1); }
}}
2/2 ページ
SimpleCircle.java
package samples;
import java.awt.geom.Point2D;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.util.ArrayList;import java.util.Collections;import java.util.List;import rungeKutta.EvolutionEquation;import rungeKutta.RungeKutta;import utils.FileIO;
/** * * @author tadaki */public class SimpleCircle implements EvolutionEquation {
private double x; private double v; private double omega;
public SimpleCircle(double x, double v, double omega) { this.x = x; this.v = v; this.omega = omega; }
public List<Point2D.Double> evlution(double t, int nstep) { double y[] = new double[2]; y[0] = x; y[1] = v; double yy[][] = RungeKutta.rkdumb(y, 0., t, nstep, this); List<Point2D.Double> points = Collections.synchronizedList( new ArrayList<Point2D.Double>()); double dt = t / nstep; for (int i = 0; i < nstep; i++) { double tt = i * dt; points.add(new Point2D.Double(tt, yy[0][i])); } return points; }
@Override public double[] derivatives(double x, double[] y) { double dy[] = new double[2]; dy[0] = y[1]; dy[1] = -omega * omega * y[0]; return dy; }
/** * @param args the command line arguments */
1/2 ページ
SimpleCircle.java
public static void main(String[] args) throws IOException { SimpleCircle sys = new SimpleCircle(0., 1., 1.); double t = 10.; int nstep = 10000; try (FileOutputStream fStream1 = new FileOutputStream( new File("output.txt"))) { List<Point2D.Double> points = sys.evlution(t, nstep); FileIO.printPointsList(points, fStream1); }
}}
2/2 ページ
FileIO.java
package utils;
import java.awt.geom.Point2D;import java.io.BufferedWriter;import java.io.IOException;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.util.List;
/** * * @author tadaki */public class FileIO {
public static void printPointsList(List<Point2D.Double> points) throws IOException { printPointsList(points, System.out); }
public static void printPointsList(List<Point2D.Double> points, OutputStream oStream) throws IOException { BufferedWriter out = new BufferedWriter( new OutputStreamWriter(oStream)); printPointsList(points, out); }
public static void printPointsList(List<Point2D.Double> points, BufferedWriter out) throws IOException { for (int i = 0; i < points.size(); i++) { Point2D.Double p = points.get(i); StringBuilder b = new StringBuilder(); b.append(p.x).append(" ").append(p.y); out.write(b.toString()); out.newLine(); } out.flush(); }
public static void printComments(String comments[]) throws IOException { printComments(comments, System.out); }
public static void printComments(String comments[], OutputStream oStream) throws IOException { BufferedWriter out = new BufferedWriter( new OutputStreamWriter(oStream)); printComments(comments, out); }
public static void printComments(String comments[], BufferedWriter out) throws IOException { for (int i = 0; i < comments.length; i++) { StringBuilder b = new StringBuilder(); b.append("#").append(comments[i]);
1/2 ページ
FileIO.java
out.write(b.toString()); out.newLine(); } out.flush(); }}
2/2 ページ