Advertisement
BorrowTheProgrammer

fem

Dec 17th, 2022
793
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.23 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <cmath>
  4. // #define CUBE
  5.  
  6. constexpr double EPS = 1e-16, CUB=2.966181e-8;
  7. constexpr double X_BEGIN = 3.0;
  8. constexpr double X_END = 18.0;
  9. constexpr size_t ELEMS_NUM = 20;
  10. constexpr double L = (X_END - X_BEGIN) / ELEMS_NUM;
  11. constexpr double a = 2.0, B = 0.0, C = -3.0, D = 11.0, usl_left = 5, usl_right = 4;
  12.  
  13. std::vector<double> solve_with_gauss(std::vector<std::vector<double>>& A, std::vector<double>& b)
  14. {
  15.     size_t row_size = A.size();
  16.     size_t col_size = A.back().size();
  17.  
  18.     // Прямой ход Гаусса
  19.     double pivot = 0.0;
  20.     for (size_t i = 0; i < row_size; i++)
  21.     {
  22.         for (size_t j = i + 1; j < col_size; j++)
  23.         {
  24.             if (std::abs(A.at(j).at(i)) < EPS)
  25.             {
  26.                 continue;
  27.             }
  28.             pivot = A.at(j).at(i) / A.at(i).at(i);
  29.             b.at(j) -= pivot * b.at(i);
  30.             for (size_t k = 0; k < row_size; k++)
  31.             {
  32.                 A.at(j).at(k) -= pivot * A.at(i).at(k) ;
  33.             }
  34.         }
  35.     }
  36.     // Обратный ход Гаусса
  37.     std::vector<double> x(row_size);
  38.     for (int i = row_size - 1.0; i >= 0; i--)
  39.     {
  40.         x.at(i) = b.at(i);
  41.         for (size_t j = i + 1; j < row_size; j++)
  42.         {
  43.             x.at(i) -= x.at(j) * A.at(i).at(j);
  44.         }
  45.         x.at(i) /= A.at(i).at(i);
  46.     }
  47.  
  48.     return x;
  49. }
  50.  
  51. double analytical_solution(double x)
  52. {
  53.     double rez = 1.0 / 9.0 * (-33.0 * x - 52.0 * exp((-3.0) / 2.0 * (x - 3.0)) + 52.0 / exp(45.0 / 2.0) + 630);
  54.    
  55.     return rez;
  56. }
  57.  
  58. std::vector<double> build_analytical_solution(std::vector<double>& x_vec) {
  59.     size_t x_vec_size = x_vec.size();
  60.     std::vector<double> y_vec = std::vector<double>(x_vec_size);
  61.  
  62.     for (size_t i = 0; i < x_vec_size; i++)
  63.     {
  64.         y_vec.at(i) = analytical_solution(x_vec.at(i));
  65.     }
  66.  
  67.     return y_vec;
  68. }
  69.  
  70. std::vector<double> build_linear_solution(size_t elems_num)
  71. {
  72.     double L = (X_END - X_BEGIN) / elems_num;
  73.     size_t size = elems_num + 1;
  74.     std::vector< std::vector<double> > A(size, std::vector<double>(size));
  75.     std::vector<double> b(size);
  76.    
  77.     // Локальная матрица жесткости для линейного КЭ
  78.     std::vector< std::vector<double> > local_matrix = {
  79.         { -3.0 / 2.0 - 2.0 / L, 3.0 / 2.0 + 2.0 / L },
  80.         { -3.0 / 2.0 + 2.0 / L, 3.0 / 2.0 - 2.0 / L },
  81.     };
  82.    
  83.     // Ансамблирование и получение глобальной матрицы жесткости для линейного КЭ
  84.     for (size_t i = 0; i < elems_num; i++)
  85.     {
  86.         for (size_t j = 0; j < 2; j++)
  87.         {
  88.             for (size_t k = 0; k < 2; k++)
  89.             {
  90.                 A.at(i + j).at(i + k) += local_matrix.at(j).at(k);
  91.             }
  92.         }
  93.     }
  94.    
  95.     for (size_t i = 0; i < size ; i++)
  96.     {
  97.         b.at(i) = D * L;
  98.     }  
  99.    
  100.     // Учет ГУ
  101.     b.at(0) = D * L / 2 - a * usl_left;
  102.  
  103.     b.at(size - 1) = usl_right;
  104.     A.at(size - 1).at(size - 1) = 1;
  105.     A.at(size - 1).at(size - 2) = 0;
  106.  
  107.    
  108.     // Решение полученной СЛАУ методом Гаусса
  109.     std::vector<double> res = solve_with_gauss(A, b);
  110.     return res;
  111. }
  112.  
  113. std::vector<double> build_cube_solution(size_t elems_num) {
  114.     double L = (X_END - X_BEGIN) / elems_num;
  115.     size_t size = elems_num + 1;
  116.     std::vector< std::vector<double> > A(size,std::vector<double>(size));
  117.     std::vector<double> b(size);
  118.    
  119.     // Локальная матрица жесткости для кубического КЭ
  120.     std::vector< std::vector<double> > local_matrix = {
  121.  
  122.         {  24.0 * L / 105.0 - 74.0 / (10 * L), 99.0 * L / 560.0 + 378.0 / (40 * L), -9.0 * L / 140.0 - 54.0 / (20 * L), 57.0 * L / 1680.0 + 26.0 / (40 * L)},
  123.         { 99.0 * L / 560.0 + 378.0 / (40 * L), 81.0 * L / 70.0 - 108.0 / (5 * L), -81.0 * L / 560.0 + 594.0 / (40 * L), -9.0 * L / 140.0 - 54.0 / (20 * L)},
  124.         {  -9.0 * L / 140.0 - 54.0 / (20 * L), -81.0 * L / 560.0 + 594.0 / (40 * L), 81.0 * L / 560.0 + 108.0 / (5 * L), 99.0 * L / 560.0 + 378.0 / (40 * L)},
  125.         { 57.0 * L / 1680.0 + 26.0 / (40 * L), -9.0 * L / 140.0 - 54.0 / (20 * L), 99.0 * L / 560.0 + 378.0 / (40 * L),  24.0 * L / 105.0 - 74.0 / (10 * L)}
  126.        
  127.    };
  128.    
  129.     // Локальный вектор нагрузок (дополнительные слагаемые для первого и последнего элементов учитываются далее)
  130.     std::vector<double> local_b = { D * L / 8.0,
  131.                                     D * 3.0 * L / 8.0,
  132.                                     D * 3.0 * L / 8.0,
  133.                                     D * L / 8.0 };
  134.  
  135.    
  136.     // Производим матричные преобразования для обнуления элементов локальной матрицы жесткости, относящихся к внутренним узлам
  137.     for (size_t i = 1; i < 3; i++)
  138.     {
  139.         for (size_t j = 0; j < 4; j++)
  140.         {
  141.             if (std::fabs(local_matrix.at(j).at(i)) > EPS && i != j)
  142.             {
  143.                 double  val = local_matrix.at(j).at(i) /local_matrix.at(i).at(i);
  144.                 local_b.at(j) -= val * local_b.at(i);
  145.                 for (size_t k = 0; k < 4; k++)
  146.                 {
  147.                     local_matrix.at(j).at(k) -= val *local_matrix.at(i).at(k);
  148.                 }
  149.             }
  150.             continue;
  151.         }
  152.     }
  153.    
  154.    
  155.     // Исключаем внутренние узлы из рассмотрения
  156.     std::vector< std::vector<double> >  local_matrix_mod  = {{ local_matrix.at(0).at(0), local_matrix.at(0).at(3) },
  157.                                                              { local_matrix.at(3).at(0), local_matrix.at(3).at(3) }};
  158.     std::vector<double> local_b_mod = { local_b.at(0),
  159.                                         local_b.at(3)};
  160.    
  161.     // Ансамблирование и получение глобальной матрицы жесткости для кубического КЭ
  162.     for (size_t i = 0; i < elems_num; i++)
  163.     {
  164.         for (size_t j = 0; j < 2; j++)
  165.         {
  166.             for (size_t k = 0; k < 2; k++)
  167.             {
  168.                 A.at(i + j).at(i + k) += local_matrix_mod.at(j).at(k);
  169.             }
  170.         }
  171.     }
  172.    
  173.     for (size_t i = 0; i < elems_num; i++)
  174.     {
  175.         b.at(i) += local_b_mod.at(0);
  176.         b.at(i + 1) += local_b_mod.at(1);
  177.     }
  178.        
  179.     // Учет ГУ
  180.     b.at(0) = local_b_mod.at(0) - a * usl_left;
  181.     b.at(elems_num) = usl_right;
  182.     A.at(elems_num).at(elems_num) = 1.0;
  183.     A.at(elems_num).at(elems_num - 1) = 0.0;
  184.    
  185.     // Решение полученной СЛАУ методом Гаусса
  186.     std::vector<double> res = solve_with_gauss(A, b);
  187.     return res;
  188. }
  189.  
  190. double calc_abs_error(const std::vector<double>& y_real, const std::vector<double>& y)
  191. {
  192.     double max_err = 0.0;
  193.     for (size_t i = 0; i < y_real.size(); i++)
  194.     {
  195.         double err = std::fabs(y_real.at(i) - y.at(i));
  196.         if (err > max_err)
  197.         {
  198.             max_err = err;
  199.         }
  200.     }
  201.     return max_err;
  202. }
  203.  
  204. int main() {
  205.  
  206.     std::vector<double> x(ELEMS_NUM + 1);
  207.  
  208.     for (size_t i = 0; i < x.size(); i++)
  209.     {
  210.         x.at(i) = X_BEGIN + i * L;
  211.     }
  212.    
  213.     size_t x_size = x.size();
  214.    
  215. #ifdef CUBE
  216.     std::vector<double> y = build_cube_solution(ELEMS_NUM);
  217.    
  218. #else
  219.     std::vector<double> y = build_linear_solution(ELEMS_NUM);
  220. #endif
  221.     std::vector<double> y_real = build_analytical_solution(x);
  222.    
  223.  
  224.     FILE* gp = popen("gnuplot -persist", "w");
  225.     fprintf(gp, "$predict << EOD\n");
  226.  
  227.     for (size_t i = 0; i < x_size; i++)
  228.     {
  229.         fprintf(gp, "%lf %lf\n", x.at(i), y.at(i));
  230.     }
  231.  
  232.     fprintf(gp, "EOD\n");
  233.     fprintf(gp, "$real << EOD\n");
  234.  
  235.     for (size_t i = 0; i < x_size; i++)
  236.     {
  237.         fprintf(gp, "%lf %lf\n", x.at(i), y_real.at(i));
  238.     }
  239.  
  240.     fprintf(gp, "EOD\n");
  241.     fprintf(gp, "set grid\n");
  242.     fprintf(gp, "plot '$predict' using 1:2 with lp lc '#20155e' lw 1.5 pt 7 ps 0.5 title 'МКЭ-решение (%zu КЭ)'," "'$real' using 1:2 with lines lc rgb '#c93c20' lt 1 lw 2 title 'аналитическое решение (%zu КЭ)',\n", ELEMS_NUM, ELEMS_NUM);
  243.     printf("Абсолютная погрешность: %e\n", calc_abs_error(y_real, y));
  244.    
  245.     //нахождение количества линейных КЭ
  246.     int N = ELEMS_NUM, n = 0;
  247.     double err = 10;
  248.    
  249.     while (err > CUB)
  250.     {
  251.         double L = (X_END - X_BEGIN) / N;
  252.         std::vector<double> x(N + 1);
  253.  
  254.         for (size_t i = 0; i < x.size(); i++)
  255.         {
  256.             x.at(i) = X_BEGIN + i * L;
  257.         }
  258.        
  259.         std::vector<double> y_r(N + 1);
  260.         std::vector<double> y(N + 1);
  261.        
  262.         y = build_linear_solution(N);
  263.         y_r = build_analytical_solution(x);
  264.        
  265.         err = calc_abs_error(y_r, y);
  266.         printf("Абсолютная погрешность: %e\n", calc_abs_error(y_r, y));
  267.         N += 1;
  268.         //n+=1;
  269.     }
  270.  
  271.     std::cout << "Количество линейных КЭ "<< N - 1 << std::endl;
  272.     printf("Абсолютная погрешность: %e\n", err);
  273.  
  274.     return 0;
  275. }
  276.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement