OpenMP并行GSL常微分方程计算
OpenMP paralleling GSL Ordinary Differential Equations calculation
我正在尝试并行化我的代码,但我遇到了错误。我需要计算 Cauchy 问题(它已经完成),但我需要使用 OpenMP 库将其并行化。
我尝试使用 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;
}
这是主要功能。我目前没有找到如何创建结构数组数组的方法,但这不是主要问题。
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, ¶m};
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, ¶m};
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)
的主要问题是,但我不知道如何用其他方式重写它。
感谢您的回复。
更新:
Kaveh Vahedipour 帮助我的代码部分开始工作。这意味着我的 for 循环的一半开始工作了。
更新更新:
经过另一次调查,我有以下代码:
它是编译和 运行,但我得到 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, ¶m};
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;
}
将 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, ¶m};
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);
}
}
看来这个版本工作正常。我认为问题在于此结构 Dots ArrayOfDots[count];
以及当我尝试将值推送到此结构时。
ArrayOfDots[i].par = param;
ArrayOfDots[i].x = xi;
ArrayOfDots[i].y = y[0];
这是完整的代码。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
// GSL lib includes
#include <gsl/gsl_sf_bessel.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_odeiv2.h>
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) {
#pragma omp parallel for
for(int param = param1; param < param2; param++) {
gsl_odeiv2_system sys = {ode_func, NULL, 1, ¶m};
gsl_odeiv2_driver * d =
gsl_odeiv2_driver_alloc_y_new (&sys, gsl_odeiv2_step_rk8pd,
1e-6, 1e-6, 0.0);
int i;
double x = x_start, x1 = x_end;
double y[1] = { y_start };
for (i = 1; i <= count; i++)
{
double xi = i * x1 / count;
int status = gsl_odeiv2_driver_apply (d, &x, xi, y);
if (status != GSL_SUCCESS)
{
printf ("error, return value=%d\n", status);
break;
}
// printf ("%d %d %.5e %.5e\n", omp_get_thread_num(), param, x, 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 = 100000;
int param1 = 1;
int param2 = 20;
calc_cauchy_problem(x_start, x_end, y_start, count, param1, param2);
printf("Elapsed time = %f\n", omp_get_wtime() - start_time);
return 0;
}
非常感谢 Kaveh Vahedipour。
我正在尝试并行化我的代码,但我遇到了错误。我需要计算 Cauchy 问题(它已经完成),但我需要使用 OpenMP 库将其并行化。
我尝试使用 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;
}
这是主要功能。我目前没有找到如何创建结构数组数组的方法,但这不是主要问题。
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, ¶m};
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, ¶m};
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)
的主要问题是,但我不知道如何用其他方式重写它。
感谢您的回复。
更新:
Kaveh Vahedipour 帮助我的代码部分开始工作。这意味着我的 for 循环的一半开始工作了。
更新更新:
经过另一次调查,我有以下代码:
它是编译和 运行,但我得到 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, ¶m};
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;
}
将 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, ¶m};
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);
}
}
看来这个版本工作正常。我认为问题在于此结构 Dots ArrayOfDots[count];
以及当我尝试将值推送到此结构时。
ArrayOfDots[i].par = param;
ArrayOfDots[i].x = xi;
ArrayOfDots[i].y = y[0];
这是完整的代码。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
// GSL lib includes
#include <gsl/gsl_sf_bessel.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_odeiv2.h>
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) {
#pragma omp parallel for
for(int param = param1; param < param2; param++) {
gsl_odeiv2_system sys = {ode_func, NULL, 1, ¶m};
gsl_odeiv2_driver * d =
gsl_odeiv2_driver_alloc_y_new (&sys, gsl_odeiv2_step_rk8pd,
1e-6, 1e-6, 0.0);
int i;
double x = x_start, x1 = x_end;
double y[1] = { y_start };
for (i = 1; i <= count; i++)
{
double xi = i * x1 / count;
int status = gsl_odeiv2_driver_apply (d, &x, xi, y);
if (status != GSL_SUCCESS)
{
printf ("error, return value=%d\n", status);
break;
}
// printf ("%d %d %.5e %.5e\n", omp_get_thread_num(), param, x, 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 = 100000;
int param1 = 1;
int param2 = 20;
calc_cauchy_problem(x_start, x_end, y_start, count, param1, param2);
printf("Elapsed time = %f\n", omp_get_wtime() - start_time);
return 0;
}
非常感谢 Kaveh Vahedipour。