Created
October 15, 2020 01:16
-
-
Save komasaru/66a2ce405a0d2e6a60bf9fcbc778dc19 to your computer and use it in GitHub Desktop.
C++ source code to calculate a Lorenz attractor by Runge-Kutta's method.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "calc.hpp" | |
#include <cmath> | |
#include <iomanip> | |
#include <iostream> | |
#include <sstream> | |
#include <vector> | |
namespace my_lib { | |
// 定数 | |
constexpr double kDt = 1.0e-3; // Differential interval | |
constexpr int kStep = 100000; // Time step count | |
constexpr double kX0 = 1.0; // Initial value of x | |
constexpr double kY0 = 1.0; // Initial value of y | |
constexpr double kZ0 = 1.0; // Initial value of z | |
/** | |
* @brief 計算(ローレンツ・アトラクタ(Runge-Kutta 法) | |
* | |
* @param[ref] データ配列(計算結果) rec: (vector<vector<double>>) | |
* @return 真偽(true|false)(bool) | |
*/ | |
bool Calc::lorenz_runge_kutta(std::vector<std::vector<double>>& res) { | |
double xyz[] = {kX0, kY0, kZ0}; | |
double xyz_l_0[3]; // 計算用(LorenzAttractor) | |
double xyz_l_1[3]; // 計算用(LorenzAttractor) | |
double xyz_l_2[3]; // 計算用(LorenzAttractor) | |
double xyz_l_3[3]; // 計算用(LorenzAttractor) | |
double xyz_w[3]; // 計算用(作業用) | |
unsigned int i; // ループインデックス | |
unsigned int j; // ループインデックス | |
try { | |
for (i = 0; i < kStep; i++) { | |
if (!lorenz(xyz, xyz_l_0)) return false; | |
xyz_w[0] = xyz[0] + xyz_l_0[0] * kDt / 2.0; | |
xyz_w[1] = xyz[1] + xyz_l_0[1] * kDt / 2.0; | |
xyz_w[2] = xyz[2] + xyz_l_0[2] * kDt / 2.0; | |
if (!lorenz(xyz_w, xyz_l_1)) return false; | |
xyz_w[0] = xyz[0] + xyz_l_1[0] * kDt / 2.0; | |
xyz_w[1] = xyz[1] + xyz_l_1[1] * kDt / 2.0; | |
xyz_w[2] = xyz[2] + xyz_l_1[2] * kDt / 2.0; | |
if (!lorenz(xyz_w, xyz_l_2)) return false; | |
xyz_w[0] = xyz[0] + xyz_l_2[0] * kDt; | |
xyz_w[1] = xyz[1] + xyz_l_2[1] * kDt; | |
xyz_w[2] = xyz[2] + xyz_l_2[2] * kDt; | |
if (!lorenz(xyz_w, xyz_l_3)) return false; | |
for (j = 0; j < 3; ++j) { | |
xyz[j] += (xyz_l_0[j] + 2 * xyz_l_1[j] + 2 * xyz_l_2[j] + xyz_l_3[j]) | |
* kDt / 6.0; | |
} | |
res.push_back({xyz[0], xyz[1], xyz[2]}); | |
} | |
} catch (...) { | |
return false; // 計算失敗 | |
} | |
return true; // 計算成功 | |
} | |
bool Calc::lorenz(const double xyz[], double(&xyz_l)[3]) { | |
try { | |
xyz_l[0] = -p * xyz[0] + p * xyz[1]; | |
xyz_l[1] = -xyz[0] * xyz[2] + r * xyz[0] - xyz[1]; | |
xyz_l[2] = xyz[0] * xyz[1] - b * xyz[2]; | |
} catch (...) { | |
return false; | |
} | |
return true; | |
} | |
} // namespace my_lib |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef LORENZ_ATTRACTOR_EULER_CALC_HPP_ | |
#define LORENZ_ATTRACTOR_EULER_CALC_HPP_ | |
#include <vector> | |
namespace my_lib { | |
class Calc { | |
double p; | |
double r; | |
double b; | |
bool lorenz(const double[], double(&)[3]); // 計算(各ステップ) | |
public: | |
Calc(double p, double r, double b) : p(p), r(r), b(b) {} // コンストラクタ | |
bool lorenz_runge_kutta(std::vector<std::vector<double>>&); // 計算 | |
}; | |
} // namespace my_lib | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*********************************************************** | |
Lorenz attractor (Runge-Kutta method) | |
DATE AUTHOR VERSION | |
2020.10.14 mk-mode.com 1.00 新規作成 | |
Copyright(C) 2020 mk-mode.com All Rights Reserved. | |
***********************************************************/ | |
#include "calc.hpp" | |
#include <cstdlib> // for EXIT_XXXX | |
#include <iomanip> // for setprecision | |
#include <iostream> | |
#include <string> | |
#include <vector> | |
int main(int argc, char* argv[]) { | |
double p; | |
double r; | |
double b; | |
std::vector<std::vector<double>> res; // データ配列(計算結果) | |
std::size_t i; // loop インデックス | |
try { | |
// コマンドライン引数のチェック | |
if (argc < 4) { | |
std::cerr << "[ERROR] Number of arguments is wrong!\n" | |
<< "[USAGE] ./lorenz_attractor_runge_kutta p r b" | |
<< std::endl; | |
return EXIT_FAILURE; | |
} | |
// p, r, b の取得 | |
p = std::stod(argv[1]); | |
r = std::stod(argv[2]); | |
b = std::stod(argv[3]); | |
// 計算用オプジェクトのインスタンス化 | |
my_lib::Calc calc(p, r, b); | |
// 計算 | |
if (!calc.lorenz_runge_kutta(res)) { | |
std::cout << "[ERROR] Failed to calculare!" << std::endl; | |
return EXIT_FAILURE; | |
} | |
// 結果出力 | |
std::cout << std::fixed << std::setprecision(8); | |
for (i = 0; i < res.size(); ++i) { | |
std::cout << std::setw(14) << std::right << res[i][0] | |
<< std::setw(14) << std::right << res[i][1] | |
<< std::setw(14) << std::right << res[i][2] | |
<< std::endl; | |
} | |
} catch (...) { | |
std::cerr << "EXCEPTION!" << std::endl; | |
return EXIT_FAILURE; | |
} | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment