【问题标题】:GSL adaptive integration giving Invalid Pointer errorGSL 自适应积分给出无效指针错误
【发布时间】:2020-07-14 15:24:45
【问题描述】:

我正在尝试使用内置的 RK2imp 方法来解决 GSL sample examples 中给出的范德波尔问题的略微修改版本,以使用自适应求解器进行集成。但是,我不断收到此“错误:无效指针”。 我在这里附上我的代码

#include <stdio.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_odeiv2.h>

#define ABTOL 1e-18

#define A 2.00861986087484313650940188
#define mu 1.0
#define TEND 6.6632868593231301896996820305

double eps_abs=ABTOL, eps_rel=0.0, tend=TEND;

int func (double t, const double y[], double f[], void *params)
{
    (void)(t); /* avoid unused parameter warning */
    f[0] = y[1];
    f[1] = -y[0] - mu*y[1]*(y[0]*y[0] - 1);
    return GSL_SUCCESS;
}

int jac (double t, const double y[], double *dfdy, double dfdt[], void *params)
{
    (void)(t); /* avoid unused parameter warning */
    gsl_matrix_view dfdy_mat = gsl_matrix_view_array (dfdy, 2, 2);
    gsl_matrix * m = &dfdy_mat.matrix;
    gsl_matrix_set (m, 0, 0, 0.0);
    gsl_matrix_set (m, 0, 1, 1.0);
    gsl_matrix_set (m, 1, 0, -2.0*mu*y[0]*y[1] - 1.0);
    gsl_matrix_set (m, 1, 1, -mu*(y[0]*y[0] - 1.0));
    dfdt[0] = 0.0;
    dfdt[1] = 0.0;
    return GSL_SUCCESS;
}

int main (void)
{
    const gsl_odeiv2_step_type * T = gsl_odeiv2_step_rk2imp;

    gsl_odeiv2_step * s = gsl_odeiv2_step_alloc (T, 2);
    gsl_odeiv2_control * c = gsl_odeiv2_control_y_new (eps_abs, eps_rel);
    gsl_odeiv2_evolve * e = gsl_odeiv2_evolve_alloc (2);

    gsl_odeiv2_system sys = {func, jac, 2, NULL};

    double t = 0.0, t1 = TEND;
    double h = 1e-6;
    double y[2] = { A, 0.0 };

    while (t < t1)
    {
        int status = gsl_odeiv2_evolve_apply (e, c, s, &sys, &t, t1, &h, y);

        if (status != GSL_SUCCESS)
        {
            printf ("error: %s\n", gsl_strerror (status));
            break;
        }

        printf ("%.5e %.5e %.5e\n", t, y[0], y[1]);
    }

    gsl_odeiv2_evolve_free (e);
    gsl_odeiv2_control_free (c);
    gsl_odeiv2_step_free (s);
    return 0;
}
 

这是我得到的输出:

 error: invalid pointer

我知道我可能犯了一个非常简单(而且很愚蠢)的错误,但由于某种原因我看不到它。我真的很感激任何帮助!谢谢。

【问题讨论】:

    标签: c ode gsl


    【解决方案1】:

    据我了解,不恰当的 stepping function 用于数值积分方法 (Runge-Kutta)。这里最好使用显式方法,甚至可以使用gsl_odeiv2_step_rk2步进函数,但解会收敛很长时间。 或者你可以使用隐式集成方法,但是你需要使用step driver

    #include <stdio.h>
    #include <gsl/gsl_errno.h>
    #include <gsl/gsl_matrix.h>
    #include <gsl/gsl_odeiv2.h>
    
    #define ABTOL 1e-18
    
    #define A 2.00861986087484313650940188
    #define mu 1.0
    #define TEND 6.6632868593231301896996820305
    
    double eps_abs=ABTOL, eps_rel=0.0, tend=TEND;
    
    int func (double t, const double y[], double f[], void *params)
    {
        (void)(t); /* avoid unused parameter warning */
        f[0] = y[1];
        f[1] = -y[0] - mu*y[1]*(y[0]*y[0] - 1);
        return GSL_SUCCESS;
    }
    
    int jac (double t, const double y[], double *dfdy, double dfdt[], void *params)
    {
        (void)(t); /* avoid unused parameter warning */
        gsl_matrix_view dfdy_mat = gsl_matrix_view_array (dfdy, 2, 2);
        gsl_matrix * m = &dfdy_mat.matrix;
        gsl_matrix_set (m, 0, 0, 0.0);
        gsl_matrix_set (m, 0, 1, 1.0);
        gsl_matrix_set (m, 1, 0, -2.0*mu*y[0]*y[1] - 1.0);
        gsl_matrix_set (m, 1, 1, -mu*(y[0]*y[0] - 1.0));
        dfdt[0] = 0.0;
        dfdt[1] = 0.0;
        return GSL_SUCCESS;
    }
    
    int main (void)
    {
        const gsl_odeiv2_step_type * T = gsl_odeiv2_step_msadams;
        // with "gsl_odeiv2_step_rk2imp" stepping function the solution
        // converges VERY SLOWLY and may be "failure" error at the end
    
        gsl_odeiv2_step * s = gsl_odeiv2_step_alloc (T, 2);
        gsl_odeiv2_control * c = gsl_odeiv2_control_y_new (eps_abs, eps_rel);
        gsl_odeiv2_evolve * e = gsl_odeiv2_evolve_alloc (2);
    
        gsl_odeiv2_system sys = {func, jac, 2, NULL};
    
        gsl_odeiv2_driver * d = gsl_odeiv2_driver_alloc_y_new(&sys, T, 1e-6, 1e-6, 1e-6 );
        gsl_odeiv2_step_set_driver(s, d);
    
        double t = 0.0, t1 = TEND;
        double h = 1e-6;
        double y[2] = { A, 0.0 };
    
        while (t < t1)
        {
            int status = gsl_odeiv2_evolve_apply (e, c, s, &sys, &t, t1, &h, y);
    
            if (status != GSL_SUCCESS)
            {
                printf ("error: %s\n", gsl_strerror (status));
                break;
            }
    
            printf ("%.5e %.5e %.5e\n", t, y[0], y[1]);
        }
    
        gsl_odeiv2_evolve_free (e);
        gsl_odeiv2_control_free (c);
        gsl_odeiv2_step_free (s);
        return 0;
    }
    

    【讨论】:

    • 当输出集很大时,可能希望每 100 行以及最后一行输出一次。将 10K 行输出写入stdout 有点……很多。请注意,您可以在每个函数的末尾强制转换 (void)params;(即使在 return 之后)以避免 -Wunused-parameter 警告 :)
    • 非常感谢@DJNZ 的帮助!使用 step_driver 解决了这个问题。 PS 谢谢@David 的提示!我实际上删除了打印语句,只需要最终解决方案! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 1970-01-01
    • 2017-09-16
    • 2016-08-08
    • 2014-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多