Advertisement
gladilov-gleb

Untitled

Jun 4th, 2017
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.68 KB | None | 0 0
  1. #include <cstdlib>
  2. #include <algorithm>
  3. #include <omp.h>
  4.  
  5. static inline void gauss(double **A, const int n, const int m)
  6. {
  7.     int rank = 0;
  8.     for (int j = 0; j < m; ++j)
  9.     {
  10.         double max_abs = 0;
  11.         int max_abs_i = -1;
  12.  
  13.         for (int i = rank; i < n; ++i)
  14.         {
  15.             if (max_abs < std::abs(A[i][j]))
  16.             {
  17.                 max_abs = std::abs(A[i][j]);
  18.                 max_abs_i = i;
  19.             }
  20.         }
  21.  
  22.         if (max_abs_i != -1)
  23.         {
  24.             if (rank != max_abs_i)
  25.             {
  26.                 double *tmp = A[rank];
  27.                 A[rank] = A[max_abs_i];
  28.                 A[max_abs_i] = tmp;
  29.             }
  30.  
  31.             for (int i = 0; i < n; ++i)
  32.             {
  33.                 if (i == rank)
  34.                     continue;
  35.  
  36.                 double A_i_j = A[i][j];
  37.                 for (int k = 0; k < m; ++k)
  38.                     A[i][k] = A[i][k] - A[rank][k] * A_i_j / A[rank][j];
  39.             }
  40.  
  41.             rank++;
  42.         }
  43.     }
  44. }
  45.  
  46. static inline void sweep(int size, double *const b, double *const c, double *const a, double *const f)
  47. {
  48.     double **M;
  49.     int m, n;
  50.  
  51.     #pragma omp parallel
  52.     {
  53.         int t = omp_get_thread_num();
  54.         if (t == 0)
  55.             n = omp_get_num_threads();
  56.  
  57.         #pragma omp barrier
  58.  
  59.         int block_start = size/n * t + std::min(t, size%n) + 1;
  60.         int block_end   = size/n * (t+1) + std::min(t+1, size%n);
  61.         int block_size  = block_end - block_start + 1;
  62.  
  63.         if (t == 0)
  64.         {
  65.             m = std::min(2*n, size);
  66.             M = new double*[m];
  67.             for (int i = 0; i < m; ++i)
  68.             {
  69.                 M[i] = new double[m + 1];
  70.                 memset(M[i], 0, (m + 1) * sizeof(double));
  71.             }
  72.         }
  73.  
  74.         for (int i = block_start; i < block_end; ++i)
  75.         {
  76.             c[i+1] -= a[i+1]/c[i] * b[i];
  77.             f[i+1] -= a[i+1]/c[i] * f[i];
  78.             a[i+1] = t ? -a[i+1]/c[i] * a[i] : 0.0;
  79.         }
  80.  
  81.         #pragma omp barrier
  82.  
  83.         for (int i = block_end; i > block_start; --i)
  84.         {
  85.             f[i-1] -= b[i-1]/c[i] * f[i];
  86.  
  87.             if (t != 0)
  88.                 a[i-1] -= b[i-1]/c[i] * a[i];
  89.  
  90.             b[i-1] = t != n-1 ? -b[i-1]/c[i] * b[i] : 0.0;
  91.         }
  92.  
  93.         #pragma omp barrier
  94.  
  95.         if (t == 0)
  96.         {
  97.             int ssize = std::min(n, size);
  98.  
  99.             int offset = 0;
  100.             for (int t = 0; t < ssize; ++t)
  101.             {
  102.                 int block_start  = size/n * t + std::min(t, size%n) + 1;
  103.                 int block_end    = size/n * (t+1) + std::min(t+1, size%n);
  104.                 int m_block_size = std::min(block_end - block_start + 1, 2);
  105.  
  106.                 if (m_block_size == 2)
  107.                 {
  108.                     M[offset+0][offset+0] = c[block_start];
  109.                     M[offset+1][offset+1] = c[block_end];
  110.  
  111.                     if (t != ssize-1)
  112.                     {
  113.                         M[offset+0][offset+2] = b[block_start];
  114.                         M[offset+1][offset+2] = b[block_end];
  115.                     }
  116.  
  117.                     if (t != 0)
  118.                     {
  119.                         M[offset+0][offset-1] = a[block_start];
  120.                         M[offset+1][offset-1] = a[block_end];
  121.                     }
  122.  
  123.                     M[offset+0][m] = f[block_start];
  124.                     M[offset+1][m] = f[block_end];
  125.                 }
  126.                 else if (m_block_size == 1)
  127.                 {
  128.                     M[offset+0][offset+0] = c[block_start];
  129.  
  130.                     if (t != ssize-1)
  131.                         M[offset+0][offset+1] = b[block_start];
  132.  
  133.                     if (t != 0)
  134.                         M[offset+0][offset-1] = a[block_start];
  135.  
  136.                     M[offset+0][m] = f[block_start];
  137.                 }
  138.  
  139.                 offset += m_block_size;
  140.             }
  141.  
  142.             gauss(M, m, m+1);
  143.  
  144.             offset = 0;
  145.             for (int t = 0; t < ssize; ++t)
  146.             {
  147.                 int block_start  = size/n * t  + std::min(t, size%n) + 1;
  148.                 int block_end    = size/n * (t+1) + std::min(t+1, size%n);
  149.                 int m_block_size = std::min(block_end - block_start + 1, 2);
  150.  
  151.                 if (m_block_size == 2)
  152.                 {
  153.                     c[block_start] = M[offset+0][offset+0];
  154.                     c[block_end] = M[offset+1][offset+1];
  155.  
  156.                     f[block_start] = M[offset+0][m];
  157.                     f[block_end] = M[offset+1][m];
  158.  
  159.                     f[block_start] /= c[block_start];
  160.                     f[block_end] /= c[block_end];
  161.  
  162.                 }
  163.                 else if (m_block_size == 1)
  164.                 {
  165.                     c[block_start] = M[offset+0][offset+0];
  166.                     f[block_start] = M[offset+0][m];
  167.                     f[block_start] /= c[block_start];
  168.                 }
  169.  
  170.                 offset += m_block_size;
  171.             }
  172.         }
  173.  
  174.         #pragma omp barrier
  175.  
  176.         for (int i = block_start+1; i < block_end; ++i)
  177.         {
  178.             if (t == 0)
  179.                 f[i] = (f[i] - b[i]*f[block_end+1]) / c[i];
  180.             else if (t == n-1)
  181.                 f[i] = (f[i] - a[i]*f[block_start-1]) / c[i];
  182.             else
  183.                 f[i] = (f[i] - b[i]*f[block_end+1] - a[i]*f[block_start-1]) / c[i];
  184.         }
  185.     }
  186.  
  187.     for (int i = 0; i < m; ++i)
  188.         delete[] M[i];
  189.     delete[] M;
  190. }
  191.  
  192. void heat_equation_crank_nicolson(heat_task task, double *v)
  193. {
  194.     double T = task.T;
  195.     double L = task.L;
  196.     int n = task.n;
  197.     int m = task.m;
  198.  
  199.     double dx = L / n;
  200.     double dt = T / m;
  201.  
  202.     double *curr = (double *) calloc(n + 1, sizeof(double));
  203.     double *next = (double *) calloc(n + 1, sizeof(double));
  204.     double *a = (double *) calloc(n + 1 - 3, sizeof(double));
  205.     double *c = (double *) calloc(n + 1 - 2, sizeof(double));
  206.     double *b = (double *) calloc(n + 1 - 3, sizeof(double));
  207.     double *f = (double *) calloc(n + 1 - 2, sizeof(double));
  208.  
  209.     #pragma omp parallel for
  210.     for (int x = 0; x <= n; x++)
  211.         curr[x] = task.initial_condition(x * dx);
  212.  
  213.     for (int t = 1; t <= m; t++)
  214.     {
  215.         next[0] = task.left_condition(t * dt);
  216.         next[n] = task.right_condition(t * dt);
  217.  
  218.         #pragma omp parallel for
  219.         for (int x = 0; x <= n - 3; x++)
  220.             a[x] = dt / (2.0 * dx * dx);
  221.  
  222.         #pragma omp parallel for
  223.         for (int x = 0; x <= n - 3; x++)
  224.             b[x] = dt / (2.0 * dx * dx);
  225.  
  226.         #pragma omp parallel for
  227.         for (int x = 0; x <= n - 2; x++)
  228.             c[x] = -1.0 * (1.0 + dt / (dx * dx));
  229.  
  230.         f[0] =
  231.             -(1.0 - dt / (dx * dx)) * curr[1] +
  232.             -dt / (2.0 * dx * dx) * (curr[0] + curr[2]) +
  233.             -dt * task.f(1.0 * dx, t * dt) +
  234.             -1.0 * dt / (2.0 * dx * dx) * next[0];
  235.         #pragma omp parallel for
  236.         for (int x = 1; x <= n - 3; x++)
  237.             f[x] =
  238.                 -(1.0 - dt / (dx * dx)) * curr[x + 1] +
  239.                 -dt / (2.0 * dx * dx) * (curr[x] + curr[x + 2]) +
  240.                 -dt * task.f((x + 1) * dx, t * dt);
  241.         f[n - 2] =
  242.             -(1.0 - dt / (dx * dx)) * curr[n - 1] +
  243.             -dt / (2.0 * dx * dx) * (curr[n - 2] + curr[n]) +
  244.             -dt * task.f((n - 1) * dx, t * dt) +
  245.             -1.0 * dt / (2.0 * dx * dx) * next[n];
  246.  
  247.         sweep(n + 1 - 2, b - 1, c - 1, a - 2, f - 1);
  248.  
  249.         #pragma omp parallel for
  250.         for (int x = 1; x <= n - 1; x++)
  251.             next[x] = f[x - 1];
  252.  
  253.         std::swap(curr, next);
  254.     }
  255.  
  256.     #pragma omp parallel for
  257.     for (int x = 0; x <= n; x++)
  258.         v[x] = curr[x];
  259.  
  260.     free(f);
  261.     free(a);
  262.     free(c);
  263.     free(b);
  264.     free(next);
  265.     free(curr);
  266. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement