OpenMP параллельное вычисление обыкновенных дифференциальных уравнений GSL - PullRequest
0 голосов
/ 09 июня 2019

Я пытаюсь распараллелить мой код, но я получил ошибки. Мне нужно вычислить задачу Коши (это уже сделано), но затем мне нужно распараллелить ее с помощью OpenMP lib.

Я пытался написать код с OpenMP, но он не работает.

Я создал структуру для сбора результатов.

struct Dots {
    double par;
    double x;
    double y;
};

Это моя целевая функция с параметром.

int ode_func (double x, const double y[], double f[], void *params)
{

    double mu = *(int *)params;
    f[0] = x + 2 * y[0] / (1 + mu * mu);
    return GSL_SUCCESS;
}

Это основная функция. В настоящее время я не нашел способ создания массива массивов struct, но это не главная проблема.

void calc_cauchy_problem(struct Dots ArrayOfDots[], double x_start, double x_end, double y_start,
        int count) {

    int dim = 1;
    double x = x_start;
    double y[1] = {y_start};
    int mu = 5;
    int param = 0;
    gsl_odeiv2_system sys = {ode_func, NULL, dim, &param};
    gsl_odeiv2_driver * d = gsl_odeiv2_driver_alloc_y_new (&sys,
                                                               gsl_odeiv2_step_rkf45, 1e-6, 1e-6, 0.0);
    int status = 0;
#pragma omp parallel for shared(ArrayOfDots) private(sys, param, d, status)
    for (int param = 1; param < mu; param++) {

        gsl_odeiv2_system sys = {ode_func, NULL, dim, &param};
        gsl_odeiv2_driver * d = gsl_odeiv2_driver_alloc_y_new (&sys,
                                                               gsl_odeiv2_step_rkf45, 1e-6, 1e-6, 0.0);
        for (int i = 1; i <= count; i++)
        {
            double xi = x_start + i * (x_end - x_start) / count;

            int status = gsl_odeiv2_driver_apply(d, &x, xi, y);

            if (status != GSL_SUCCESS)
            {
                printf ("error, return value=%d\n", status);
                break;
            }
           // ArrayOfDots[i].par = mu;
           // ArrayOfDots[i].x = xi;
           // ArrayOfDots[i].y = y[0];
        }
        gsl_odeiv2_driver_free (d);
    }

}

Основной

int main() {
    double x_start = 0;
    double x_end = 10;
    double y_start = 0;
    int count = 10;
    struct Dots ArrayOfDots[count];
    calc_cauchy_problem(ArrayOfDots, x_start, x_end, y_start, count);
    return 0;
}

Он успешно скомпилирован с этим gcc main.c -o main -fopenmp -lgsl -std=gnu11, но когда я запускаю его, я получаю сообщение об ошибке

gsl: driver.c:354: ERROR: integration limits and/or step direction not consistent
Default GSL error handler invoked.

Я думаю, что главная проблема с этим #pragma omp parallel for shared(ArrayOfDots) private(sys, param, d, status), но я понятия не имею, как переписать это другим способом. Спасибо за ваши ответы.

UPD:

С помощью Kaveh Vahedipour мой код частично начал работать. Это значит, что половина моего за цикл начинает работать. UPD UPD: После еще одного расследования у меня был следующий код: Он компилируется и запускается, но у меня есть Process finished with exit code 4 и printf("Elapsed time = %f\n", omp_get_wtime() - start_time);, ничего не печатать.

struct Dots {
    double par;
    double x;
    double y;
};

int ode_func (double x, const double y[], double f[], void *params)
{

    double mu = *(int *)params;
    f[0] = (x + 2 * y[0]) / (1 + mu * mu);
    return GSL_SUCCESS;
}
void calc_cauchy_problem(double x_start, double x_end, double y_start,
                         int count, int param1, int param2) {
    int dim = 1;
    double x = x_start;
    double y[1] = {y_start};
    int param = param1;
    int j = 0;
    int status = 0;
    char filename[10];

#pragma omp parallel for private(param, status, x, y)
    for (param = param1; param <= param2; param++) {
        struct Dots ArrayOfDots[count];
        gsl_odeiv2_system sys = {ode_func, NULL, dim, &param};
        gsl_odeiv2_driver * d =
                gsl_odeiv2_driver_alloc_y_new (&sys, gsl_odeiv2_step_rkf45, 1e-6, 1e-6, 0.0);
        for (int i = 1; i <= count; i++) {
            double xi = x_start + i * (x_end - x_start) / count;

            int status = gsl_odeiv2_driver_apply(d, &x, xi, y);
            if (status != GSL_SUCCESS)
            {
                printf ("error, return value=%d\n", status);
                break;
            }

            ArrayOfDots[i].par = param;
            ArrayOfDots[i].x = xi;
            ArrayOfDots[i].y = y[0];
        }
        gsl_odeiv2_driver_free (d);

    }
}
int main() {
    double start_time = omp_get_wtime();
    double x_start = 0;
    double x_end = 10;
    double y_start = 0;
    const int count = 500;
    int param1 = 1;
    int param2 = 10;
    calc_cauchy_problem(x_start, x_end, y_start, count, param1, param2);
    printf("Elapsed time = %f\n", omp_get_wtime() - start_time);
    return 0;
}

1 Ответ

0 голосов
/ 09 июня 2019

Добавить x к частным циклам: private(sys, param, d, status, x).Пожалуйста, ответьте мне, если у вас все еще есть проблемы.

void calc_cauchy_problem(double x_start, double x_end, double y_start,
                         int count, int param1, int param2) {

  int dim = 1;
  double x = x_start;
  double y[1] = {y_start};
  int param = param1;
  int j = 0;
  int status = 0;
  char filename[10];

#pragma omp parallel for private(param, status, x, y)
  for (param = param1; param <= param2; param++) {
    struct Dots ArrayOfDots[count];
    gsl_odeiv2_system sys = {ode_func, NULL, dim, &param};
    gsl_odeiv2_driver * d =
      gsl_odeiv2_driver_alloc_y_new (&sys, gsl_odeiv2_step_rkf45, 1e-6, 1e-6, 0.0);
    for (int i = 1; i <= count; i++) {
      double xi = x_start + i * (x_end - x_start) / count;

      int status = gsl_odeiv2_driver_apply(d, &x, xi, y);
      if (status != GSL_SUCCESS)
        {
          printf ("error, return value=%d\n", status);
          break;
        }
      ArrayOfDots[i].par = param;
      ArrayOfDots[i].x = xi;
      ArrayOfDots[i].y = y[0];
    }
    //write_data_to_file(param, count, ArrayOfDots);                                                                                        
    for (int i = 0; i < count; ++i) {
      printf ("%d: %f, %f, %f\n", omp_get_thread_num(),
              ArrayOfDots[i].par, ArrayOfDots[i].x, ArrayOfDots[i].y);
    }
    gsl_odeiv2_driver_free (d);
  }
}
...