From 53f7c5b3fe72249d3fca2f58d1d2637a7f6f3464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B8=D1=81=D0=B0=D1=80=D0=B5=D0=B2=20=D0=92=D0=B0?= =?UTF-8?q?=D1=81=D0=B8=D0=BB=D0=B8=D0=B9=20=D0=92=D1=8F=D1=87=D0=B5=D1=81?= =?UTF-8?q?=D0=BB=D0=B0=D0=B2=D0=BE=D0=B2=D0=B8=D1=87?= <vpisarev@miem.hse.ru> Date: Wed, 6 Oct 2021 12:55:03 +0000 Subject: [PATCH] Added 1D heat equation solvers --- heat_equation.hpp | 60 ++++++++++ heat_equation_cg.cpp | 208 +++++++++++++++++++++++++++++++++ heat_equation_explicit.cpp | 156 +++++++++++++++++++++++++ heat_equation_explicit_omp.cpp | 157 +++++++++++++++++++++++++ heat_equation_implicit.cpp | 188 +++++++++++++++++++++++++++++ 5 files changed, 769 insertions(+) create mode 100644 heat_equation.hpp create mode 100644 heat_equation_cg.cpp create mode 100644 heat_equation_explicit.cpp create mode 100644 heat_equation_explicit_omp.cpp create mode 100644 heat_equation_implicit.cpp diff --git a/heat_equation.hpp b/heat_equation.hpp new file mode 100644 index 0000000..350efc9 --- /dev/null +++ b/heat_equation.hpp @@ -0,0 +1,60 @@ +#ifndef HEAT_EQN_H +#define HEAT_EQN_H + +#include "../vectors_and_matrices/array_types.hpp" +#include <iostream> +#include <fstream> +#include <cstdint> + +using intptr_t = std::intptr_t; + +// Общее граничное условие вида +// (a u + b du/dx)_bound = z +struct boundary_cond +{ + double coeff_u; + double coeff_du; + double rhp_val; +}; + +struct heat_eq_problem +{ + vec<double> us; + vec<double> us_next; + double step_x; + double conductivity; + boundary_cond left_bc; + boundary_cond right_bc; +}; + +boundary_cond dirichlet_bc(double val) +{ + return boundary_cond {1.0, 0.0, val}; +} + +boundary_cond neumann_bc(double val) +{ + return boundary_cond {0.0, 1.0, val}; +} + +void print_temp_profile(std::ostream& log_file, heat_eq_problem prob) +{ + double h = prob.step_x; + intptr_t nx = prob.us.length() - 2; + log_file << "0.0 " << 0.5 * (prob.us(0) + prob.us(1)) << "\n"; + for (intptr_t i = 1; i <= nx; i++) + { + log_file << (i - 0.5) * h << " " << prob.us(i) << "\n"; + } + log_file << nx * h << " " << 0.5 * (prob.us(nx) + prob.us(nx+1)) << "\n"; + log_file << "\n\n" << std::endl; +} + +void print_log(std::ostream& log_file, intptr_t step, double step_time, + heat_eq_problem prob) +{ + log_file << "Timestep " << step << ". t = " << step_time << "\n"; + print_temp_profile(log_file, prob); +} + +#endif diff --git a/heat_equation_cg.cpp b/heat_equation_cg.cpp new file mode 100644 index 0000000..b4356f0 --- /dev/null +++ b/heat_equation_cg.cpp @@ -0,0 +1,208 @@ +#include "../vectors_and_matrices/array_types.hpp" +#include "../vectors_and_matrices/linalg.hpp" +#include "heat_equation.hpp" +#include <iostream> +#include <fstream> +#include <cstddef> +#include <string> +#include <cmath> +#include <omp.h> + +using size_t = std::size_t; +using intptr_t = std::intptr_t; + +void set_constant_u(vec<double> us, double u0) +{ + intptr_t n = us.length()-2; + for (intptr_t i=1; i<=n; i++) + { + us(i) = u0; + } +} + +void compute_residual(vec<double> residual, vec<double> x, + vec<double> lower, vec<double> diag, vec<double> upper, + vec<double> rhp + ) +{ + intptr_t n = rhp.length() - 2; + for (intptr_t i=1; i<=n; i++) + { + residual(i) = lower(i) * x(i-1) + diag(i) * x(i) + upper(i) * x(i+1) - rhp(i); + } +} + +double pAp(vec<double> dir, + vec<double> lower, vec<double> diag, vec<double> upper + ) +{ + // Вычисляет dir' * A * dir, + // где A - трёхдиагональная матрица, задаваемая l, d и u + double prod = 0; + intptr_t n = dir.length() - 2; + for (intptr_t i=1; i<=n; i++) + { + prod += dir(i) * (lower(i) * dir(i-1) + diag(i) * dir(i) + upper(i) * dir(i+1)); + } + return prod; +} + +void solve_tridiag(vec<double> x, + vec<double> lower, vec<double> diag, vec<double> upper, + vec<double> rhp + ) +{ + // входные параметры: + // lower, diag, upper — массивы коэффициентов l, d, u + // rhp — массив с правой частью (right-hand part) + // x — массив, в который будет записываться решение + // courant - a * tau / h^2 + + // прямой ход + double factor; + intptr_t n = rhp.length()-2; + vec<double> residual(n+2); + vec<double> dir(n+2); + + diag(1) -= upper(0) * lower(1) / diag(0); + rhp(1) -= rhp(0) * lower(1) / diag(0); + diag(n) -= lower(n+1) * upper(n) / diag(n+1); + rhp(n) -= rhp(n+1) * upper(n) / diag(n+1); + + lower(1) = 0; + upper(n) = 0; + + compute_residual(residual, x, lower, diag, upper, rhp); + + residual(0) = 0; + residual(n+1) = 0; + for (intptr_t i = 0; i <= n+1; i++) + { + dir(i) = -residual(i); + } + + double rkrk = dot(residual, residual); + while (sqrt(rkrk / n) > 1e-6) + { + double alpha = rkrk / pAp(dir, lower, diag, upper); + + // x <- x + alpha * dir + // r <- r + alpha * A * dir + for (intptr_t i = 1; i <= n; i++) + { + x(i) += alpha * dir(i); + residual(i) += alpha * (lower(i) * dir(i-1) + diag(i) * dir(i) + upper(i) * dir(i+1)); + } + + double d = dot(residual, residual); + double beta = d / rkrk; + rkrk = d; + + // dir <- -r + beta * dir + for (intptr_t i = 1; i <= n; i++) + { + dir(i) = -residual(i) + beta * dir(i); + } + } +} + +void dirichlet_implicit_step(heat_eq_problem& prob, double tau, + double u0, double uL, + vec<double> lower, vec<double> diag, vec<double> upper) +{ + vec<double> us = prob.us; + intptr_t n = us.length() - 2; + double h = prob.step_x; + double courant = tau * prob.coeff_a / (h * h); + for (intptr_t i = 0; i <= n; i++) + { + diag(i) = 1.0 + 2 * courant; + lower(i) = -courant; + upper(i) = -courant; + } + upper(0) = 1.0; + lower(n+1) = 1.0; + diag(0) = 1.0; + diag(n+1) = 1.0; + us(0) = 2 * u0; + us(n+1) = 2 * uL; + solve_tridiag(prob.us_next, lower, diag, upper, us); + + vec<double> tmp = us; + prob.us = prob.us_next; + prob.us_next = tmp; + apply_dirichlet_bc(prob, u0, uL); +} + +void dirichlet_implicit_solver(heat_eq_problem& prob, double u0, double uL, + double L, double tau, size_t ntimesteps, + size_t log_freq, std::ofstream& log_file) +{ + // входные параметры: + // prob - начальная конфигурация + // u0 - температура при x=0 + // uL - температура при x=L + // L - длина отрезка, на котором решается уравнение + // tau - шаг по времени + // ntimesteps - сколько шагов по времени сделать + // log_freq - раз в столько шагов выводить информацию + // log_file - файловый дескриптор для вывода информации + size_t nx = prob.us.length() - 2; + double h = L / nx; + prob.step_x = h; + double courant = prob.coeff_a * tau / (h * h); + if (courant > 0.5) { + std::cerr << "Warning: Courant number > 1\n"; + } + print_log(log_file, 0, 0.0, prob); + vec<double> lower(nx+2); + vec<double> diag(nx+2); + vec<double> upper(nx+2); + set_constant_u(lower, -courant); + set_constant_u(upper, -courant); + upper(0) = 1.0; + lower(nx+1) = 1.0; + // эволюция по времени + for (intptr_t step = 1; step <= ntimesteps; step++) { + dirichlet_implicit_step(prob, tau, u0, uL, lower, diag, upper); + if (step % log_freq == 0) { + print_log(log_file, step, step * tau, prob); + } + } +} + +int main(int argc, char* argv[]) { + if (argc < 4) { + std::cout << "Usage: " << argv[0] << "<heat conductivity> <nx> <nsteps_t> <dt>" << std::endl; + return 1; + } + double heat_cond = std::stod(argv[1]); + size_t nx = std::stoi(argv[2]); + size_t nsteps_t = std::stoi(argv[3]); + double dt = std::stod(argv[4]); + + std::string log_name = "heat_eq_cg_log.a" + + std::to_string(heat_cond) + + ".grid" + std::to_string(nx) + + "x1.dt" + std::to_string(dt) + + ".txt"; + + std::ofstream log_file(log_name); + size_t log_freq = nsteps_t / 50; + if (log_freq == 0) { + log_freq = 1; + } + + vec<double> us(nx+2), us_next(nx+2); + heat_eq_problem prob = {us, us_next, 1.0 / nx, heat_cond}; + + set_constant_u(prob.us, 1.0); + apply_dirichlet_bc(prob, 1.0, 0.5); + + double t0 = omp_get_wtime(); + dirichlet_implicit_solver(prob, 1.0, 0.5, 1.0, dt, nsteps_t, log_freq, log_file); + double t1 = omp_get_wtime(); + std::cout << "Execution time: " << t1 - t0 << "\n"; + + return 0; +} diff --git a/heat_equation_explicit.cpp b/heat_equation_explicit.cpp new file mode 100644 index 0000000..1043a07 --- /dev/null +++ b/heat_equation_explicit.cpp @@ -0,0 +1,156 @@ +#include "../vectors_and_matrices/array_types.hpp" +#include "heat_equation.hpp" +#include <iostream> +#include <fstream> +#include <cstdint> +#include <cmath> +#include <string> +#include <omp.h> + +using intptr_t = std::intptr_t; +using std::cin; +using std::cout; +using std::endl; +using std::floor; + +void set_constant_u(vec<double> us, double u0) +{ + intptr_t n = us.length()-2; + for (intptr_t i=1; i<=n; i++) + { + us(i) = u0; + } +} + +void apply_bc_explicit(heat_eq_problem& prob) +{ + boundary_cond left_bc = prob.left_bc, right_bc = prob.right_bc; + + // Граничное условие имеет вид + // a u + b du/dx = z + // Аппроксимируем как + // a (u_0 + u_1) / 2 + b (u_1 - u_0) / h = z + vec<double> us = prob.us; + intptr_t n = us.length() - 2; + double h = prob.step_x; + + double al = left_bc.coeff_u, bl = left_bc.coeff_du, zl = left_bc.rhp_val; + us(0) = (zl - (al / 2 + bl / h) * us(1)) / (al / 2 - bl / h); + + double ar = right_bc.coeff_u, br = right_bc.coeff_du, zr = right_bc.rhp_val; + us(n+1) = (zr - (ar / 2 - br / h) * us(n)) / (ar / 2 + br / h); +} + +void explicit_step(heat_eq_problem& prob, double tau) +{ + vec<double> us = prob.us; + vec<double> us_next = prob.us_next; + intptr_t n = us.length() - 2; + double h = prob.step_x; + double courant = tau * prob.conductivity / (h * h); + + apply_bc_explicit(prob); + for (intptr_t i=1; i<=n; i++) + { + us_next(i) = us(i) + courant * (-2 * us(i) + us(i-1) + us(i+1)); + } + // prob.us, prob.us_next = prob.us_next, prob.us + vec<double> tmp = us; + prob.us = us_next; + prob.us_next = tmp; +} + +void explicit_solver(heat_eq_problem& prob, + double L, double tau, intptr_t ntimesteps, + intptr_t log_freq, std::ostream& log_file) +{ + // входные параметры: + // prob - начальная конфигурация + // L - длина отрезка, на котором решается уравнение + // tau - шаг по времени + // ntimesteps - сколько шагов по времени сделать + // log_freq - раз в столько шагов выводить информацию + // log_file - файловый дескриптор для вывода информации + intptr_t nx = prob.us.length() - 2; + double h = L / nx; + prob.step_x = h; + double courant = 2.0 * prob.conductivity * tau / (h * h); + if (courant > 1.0) { + std::cerr << "Warning: Courant number > 1\n"; + log_file << "Warning: Courant number > 1\n"; + } + apply_bc_explicit(prob); + print_log(log_file, 0, 0.0, prob); + // эволюция по времени + for (intptr_t step = 1; step <= ntimesteps; step++) { + explicit_step(prob, tau); + if (step % log_freq == 0) { + print_log(log_file, step, step * tau, prob); + } + } +} + +int main(int argc, char* argv[]) { + + std::string npoints_str, dx_str, dt_str, tmax_str; + + double heat_cond = 1.0; + intptr_t nx; + double dx, dt, tmax; + + cout << "Enter:\nNPOINTS: n\nSTEP_X: h\nSTEP_T: dt\nT_MAX: T" << endl; + cin >> npoints_str; + if (npoints_str != "NPOINTS:") { + cout << "ERROR: Cannot find NPOINTS record\n"; + return 1; + } + cin >> nx; + + cin >> dx_str; + if (dx_str != "STEP_X:") { + cout << "ERROR: Cannot find STEP_X record\n"; + return 1; + } + cin >> dx; + + cin >> dt_str; + if (dt_str != "STEP_T:") { + cout << "ERROR: Cannot find STEP_T record\n"; + return 1; + } + cin >> dt; + + cin >> tmax_str; + if (tmax_str != "T_MAX:") { + cout << "ERROR: Cannot find T_MAX record\n"; + return 1; + } + cin >> tmax; + + intptr_t nsteps_t = floor(tmax / dt); + std::string log_name = "heat_eq_expl_log.grid" + std::to_string(nx) + "pts.dx" + std::to_string(dx) + ".dt" + std::to_string(dt) + ".txt"; + + std::ofstream log_file(log_name); + intptr_t log_freq = nsteps_t / 5; + if (log_freq == 0) { + log_freq = 1; + } + + vec<double> us(nx+2), us_next(nx+2); + heat_eq_problem prob = {us, us_next, dx, heat_cond, dirichlet_bc(1.0), dirichlet_bc(0.5)}; + + set_constant_u(prob.us, 1.0); + + double t0 = omp_get_wtime(); + explicit_solver(prob, nx * dx, dt, nsteps_t, log_freq, log_file); + double t1 = omp_get_wtime(); + + intptr_t nflops = (5 * nx + 18) * nsteps_t; // 5nx - основные итерации, 18 - применение ГУ + + cout << "Execution time: " << t1 - t0 << "\n"; + cout << "Steps per second: " << nsteps_t / (t1 - t0) << "\n"; + cout << "GFLOPS: " << 1e-9 * nflops / (t1 - t0) << "\n"; + cout << "Output written to " + log_name << std::endl; + + return 0; +} diff --git a/heat_equation_explicit_omp.cpp b/heat_equation_explicit_omp.cpp new file mode 100644 index 0000000..ed7d5ac --- /dev/null +++ b/heat_equation_explicit_omp.cpp @@ -0,0 +1,157 @@ +#include "../vectors_and_matrices/array_types.hpp" +#include "heat_equation.hpp" +#include <iostream> +#include <fstream> +#include <cstdint> +#include <cmath> +#include <string> +#include <omp.h> + +using intptr_t = std::intptr_t; +using std::cin; +using std::cout; +using std::endl; +using std::floor; + +void set_constant_u(vec<double> us, double u0) +{ + intptr_t n = us.length()-2; + for (intptr_t i=1; i<=n; i++) + { + us(i) = u0; + } +} + +void apply_bc_explicit(heat_eq_problem& prob) +{ + boundary_cond left_bc = prob.left_bc, right_bc = prob.right_bc; + + // Граничное условие имеет вид + // a u + b du/dx = z + // Аппроксимируем как + // a (u_0 + u_1) / 2 + b (u_1 - u_0) / h = z + vec<double> us = prob.us; + intptr_t n = us.length() - 2; + double h = prob.step_x; + + double al = left_bc.coeff_u, bl = left_bc.coeff_du, zl = left_bc.rhp_val; + us(0) = (zl - (al / 2 + bl / h) * us(1)) / (al / 2 - bl / h); + + double ar = right_bc.coeff_u, br = right_bc.coeff_du, zr = right_bc.rhp_val; + us(n+1) = (zr - (ar / 2 - br / h) * us(n)) / (ar / 2 + br / h); +} + +void explicit_step(heat_eq_problem& prob, double tau) +{ + vec<double> us = prob.us; + vec<double> us_next = prob.us_next; + intptr_t n = us.length() - 2; + double h = prob.step_x; + double courant = tau * prob.conductivity / (h * h); + + apply_bc_explicit(prob); + #pragma omp parallel for + for (intptr_t i=1; i<=n; i++) + { + us_next(i) = us(i) + courant * (-2 * us(i) + us(i-1) + us(i+1)); + } + // prob.us, prob.us_next = prob.us_next, prob.us + vec<double> tmp = us; + prob.us = us_next; + prob.us_next = tmp; +} + +void explicit_solver(heat_eq_problem& prob, + double L, double tau, intptr_t ntimesteps, + intptr_t log_freq, std::ostream& log_file) +{ + // входные параметры: + // prob - начальная конфигурация + // L - длина отрезка, на котором решается уравнение + // tau - шаг по времени + // ntimesteps - сколько шагов по времени сделать + // log_freq - раз в столько шагов выводить информацию + // log_file - файловый дескриптор для вывода информации + intptr_t nx = prob.us.length() - 2; + double h = L / nx; + prob.step_x = h; + double courant = 2.0 * prob.conductivity * tau / (h * h); + if (courant > 1.0) { + std::cerr << "Warning: Courant number > 1\n"; + log_file << "Warning: Courant number > 1\n"; + } + apply_bc_explicit(prob); + print_log(log_file, 0, 0.0, prob); + // эволюция по времени + for (intptr_t step = 1; step <= ntimesteps; step++) { + explicit_step(prob, tau); + if (step % log_freq == 0) { + print_log(log_file, step, step * tau, prob); + } + } +} + +int main(int argc, char* argv[]) { + + std::string npoints_str, dx_str, dt_str, tmax_str; + + double heat_cond = 1.0; + intptr_t nx; + double dx, dt, tmax; + + cout << "Enter:\nNPOINTS: n\nSTEP_X: h\nSTEP_T: dt\nT_MAX: T" << endl; + cin >> npoints_str; + if (npoints_str != "NPOINTS:") { + cout << "ERROR: Cannot find NPOINTS record\n"; + return 1; + } + cin >> nx; + + cin >> dx_str; + if (dx_str != "STEP_X:") { + cout << "ERROR: Cannot find STEP_X record\n"; + return 1; + } + cin >> dx; + + cin >> dt_str; + if (dt_str != "STEP_T:") { + cout << "ERROR: Cannot find STEP_T record\n"; + return 1; + } + cin >> dt; + + cin >> tmax_str; + if (tmax_str != "T_MAX:") { + cout << "ERROR: Cannot find T_MAX record\n"; + return 1; + } + cin >> tmax; + + intptr_t nsteps_t = floor(tmax / dt); + std::string log_name = "heat_eq_expl_log.grid" + std::to_string(nx) + "pts.dx" + std::to_string(dx) + ".dt" + std::to_string(dt) + ".txt"; + + std::ofstream log_file(log_name); + intptr_t log_freq = nsteps_t / 5; + if (log_freq == 0) { + log_freq = 1; + } + + vec<double> us(nx+2), us_next(nx+2); + heat_eq_problem prob = {us, us_next, dx, heat_cond, dirichlet_bc(1.0), dirichlet_bc(0.5)}; + + set_constant_u(prob.us, 1.0); + + double t0 = omp_get_wtime(); + explicit_solver(prob, nx * dx, dt, nsteps_t, log_freq, log_file); + double t1 = omp_get_wtime(); + + intptr_t nflops = (5 * nx + 18) * nsteps_t; // 5nx - основные итерации, 18 - применение ГУ + + cout << "Execution time: " << t1 - t0 << "\n"; + cout << "Steps per second: " << nsteps_t / (t1 - t0) << "\n"; + cout << "GFLOPS: " << 1e-9 * nflops / (t1 - t0) << "\n"; + cout << "Output written to " + log_name << std::endl; + + return 0; +} diff --git a/heat_equation_implicit.cpp b/heat_equation_implicit.cpp new file mode 100644 index 0000000..bc931e3 --- /dev/null +++ b/heat_equation_implicit.cpp @@ -0,0 +1,188 @@ +#include "../vectors_and_matrices/array_types.hpp" +#include "heat_equation.hpp" +#include <iostream> +#include <fstream> +#include <cstdint> +#include <cmath> +#include <string> +#include <omp.h> + +using intptr_t = std::intptr_t; +using std::cin; +using std::cout; +using std::endl; +using std::floor; + +void set_constant_u(vec<double> us, double u0) +{ + intptr_t n = us.length()-2; + for (intptr_t i=1; i<=n; i++) + { + us(i) = u0; + } +} + +void solve_tridiag(vec<double> x, + vec<double> lower, vec<double> diag, vec<double> upper, + vec<double> rhp + ) +{ + // входные параметры: + // lower, diag, upper — массивы коэффициентов l, d, u + // rhp — массив с правой частью (right-hand part) + // x — массив, в который будет записываться решение + // courant - a * tau / h^2 + + // Замечание: если rhp и x — это один и тот же массив, то программа корректно отработает, только правая часть будет перезаписана решением + // прямой ход + double factor; + intptr_t n = rhp.length()-2; + x(0) = rhp(0); + for (intptr_t i = 1; i <= n+1; i++) + { + factor = lower(i) / diag(i-1); + diag(i) -= factor * upper(i-1); + x(i) = rhp(i) - factor * x(i-1); + } + x(n+1) /= diag(n+1); + // обратный ход + for (intptr_t i = n+1; i > 0; i--) + { + x(i-1) = (x(i-1) - upper(i-1) * x(i)) / diag(i-1); + } +} + +void apply_bc_implicit(heat_eq_problem& prob, + vec<double> lower, vec<double> diag, vec<double> upper) +{ + boundary_cond left_bc = prob.left_bc, right_bc = prob.right_bc; + + // Граничное условие имеет вид + // a u + b du/dx = z + // Аппроксимируем как + // a (u_0 + u_1) / 2 + b (u_1 - u_0) / h = z + vec<double> us = prob.us; + intptr_t n = us.length() - 2; + double h = prob.step_x; + + double al = left_bc.coeff_u, bl = left_bc.coeff_du, zl = left_bc.rhp_val; + diag(0) = (al / 2 - bl / h); + upper(0) = (al / 2 + bl / h); + us(0) = zl; + + double ar = right_bc.coeff_u, br = right_bc.coeff_du, zr = right_bc.rhp_val; + diag(n+1) = (ar / 2 + br / h); + lower(n+1) = (ar / 2 - br / h); + us(n+1) = zr; +} + +void implicit_step(heat_eq_problem& prob, double tau, + vec<double> lower, vec<double> diag, vec<double> upper) +{ + vec<double> us = prob.us; + intptr_t n = us.length() - 2; + double h = prob.step_x; + double courant = tau * prob.conductivity / (h * h); + + set_constant_u(diag, 1.0 + 2 * courant); + + apply_bc_implicit(prob, lower, diag, upper); + solve_tridiag(us, lower, diag, upper, us); +} + +void implicit_solver(heat_eq_problem& prob, + double L, double tau, intptr_t ntimesteps, + intptr_t log_freq, std::ostream& log_file) +{ + // входные параметры: + // prob - начальная конфигурация + // L - длина отрезка, на котором решается уравнение + // tau - шаг по времени + // ntimesteps - сколько шагов по времени сделать + // log_freq - раз в столько шагов выводить информацию + // log_file - файловый дескриптор для вывода информации + intptr_t nx = prob.us.length() - 2; + double h = L / nx; + prob.step_x = h; + double courant = prob.conductivity * tau / (h * h); + if (courant > 0.5) { + std::cerr << "Warning: Courant number > 1\n"; + } + print_log(log_file, 0, 0.0, prob); + vec<double> lower(nx+2); + vec<double> diag(nx+2); + vec<double> upper(nx+2); + set_constant_u(lower, -courant); + set_constant_u(upper, -courant); + // эволюция по времени + for (intptr_t step = 1; step <= ntimesteps; step++) { + implicit_step(prob, tau, lower, diag, upper); + if (step % log_freq == 0) { + print_log(log_file, step, step * tau, prob); + } + } +} + +int main(int argc, char* argv[]) { + std::string npoints_str, dx_str, dt_str, tmax_str; + + double heat_cond = 1.0; + intptr_t nx; + double dx, dt, tmax; + + cout << "Enter:\nNPOINTS: n\nSTEP_X: h\nSTEP_T: dt\nT_MAX: T" << endl; + cin >> npoints_str; + if (npoints_str != "NPOINTS:") { + cout << "ERROR: Cannot find NPOINTS record\n"; + return 1; + } + cin >> nx; + + cin >> dx_str; + if (dx_str != "STEP_X:") { + cout << "ERROR: Cannot find STEP_X record\n"; + return 1; + } + cin >> dx; + + cin >> dt_str; + if (dt_str != "STEP_T:") { + cout << "ERROR: Cannot find STEP_T record\n"; + return 1; + } + cin >> dt; + + cin >> tmax_str; + if (tmax_str != "T_MAX:") { + cout << "ERROR: Cannot find T_MAX record\n"; + return 1; + } + cin >> tmax; + + intptr_t nsteps_t = floor(tmax / dt); + std::string log_name = "heat_eq_impl_log.grid" + std::to_string(nx) + "pts.dx" + std::to_string(dx) + ".dt" + std::to_string(dt) + ".txt"; + + std::ofstream log_file(log_name); + std::intptr_t log_freq = nsteps_t / 5; + if (log_freq == 0) { + log_freq = 1; + } + + vec<double> us(nx+2), us_next(nx+2); + heat_eq_problem prob = {us, us_next, dx, heat_cond, dirichlet_bc(1.0), dirichlet_bc(0.5)}; + + set_constant_u(prob.us, 1.0); + + double t0 = omp_get_wtime(); + implicit_solver(prob, nx * dx, dt, nsteps_t, log_freq, log_file); + double t1 = omp_get_wtime(); + + intptr_t nflops = (8 * nx + 12) * nsteps_t; // 8nx - прогонка, 12 - применение ГУ + + cout << "Execution time: " << t1 - t0 << "\n"; + cout << "Steps per second: " << nsteps_t / (t1 - t0) << "\n"; + cout << "GFLOPS: " << 1e-9 * nflops / (t1 - t0) << "\n"; + cout << "Output written to " + log_name << std::endl; + + return 0; +} -- GitLab