Skip to content

Instantly share code, notes, and snippets.

@komasaru
Created October 15, 2020 01:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save komasaru/66a2ce405a0d2e6a60bf9fcbc778dc19 to your computer and use it in GitHub Desktop.
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.
#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
#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
/***********************************************************
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