直观的 GSL 刚性 EDO

Intuitive GSL stiff EDO

我需要求解具有刚性行为的 ODE。所述 ODE 将由

给出
int odefunc (double x, const double y[], double f[], void *params)
{
    double k=1e12; //At k=1e7 it works (doesn't show stiffness)
    double y_eq=-1.931+1.5*log(x)-x;
    f[0] = k*(exp(2*y_eq-y[0])-exp(y[0]));   
    return GSL_SUCCESS;
}

我不太习惯 C(虽然我习惯 C++)和 the GSL page for Differential Equations doesn't have that many comments for me to understand it. I've used 中的文档来理解它(也因为我只有 1 首颂歌,而不是它们的系统),并且在某种程度上它是有用的,但它仍然让我有点困惑。对于我的测试,我使用了我的函数而不是给定的函数,尽管我不理解代码,但我还是使用了它。但现在对我来说理解是关键,因为...

我需要修改他们给我的示例,我需要使用求解刚性方程的算法,最好 gsl_odeiv2_step_msbdf 具有自适应步长或等效的东西(BDF 方法似乎在学术界广泛使用)。这需要 jacobian,如果你不习惯 GSL 或 C,那部分真的很复杂。

要手动实现算法微分,包含明确的中间步骤会有所帮助

int odefunc (double x, const double y[], double f[], void *params)
{
    double k=1e12; //At k=1e7 it works (doesn't show stiffness)
    double y_eq=-1.931+1.5*log(x)-x;
    double v1 = exp(2*y_eq-y[0]);
    double v2 = exp(y[0]);
    double z = k*(v1-v2);   
    f[0] = z;
    return GSL_SUCCESS;
}

然后你可以用它的衍生传播来增强每一步

int jac (double x, const double y[], double *dfdy,
     double dfdx[], void *params)
{
    double k=1e12; //At k=1e7 it works (doesn't show stiffness)
    // Dx_dx=Dy_dy=1, Dx_dy=Dy_dx=0 are used without naming them
    double y_eq = -1.931+1.5*log(x)-x, 
          Dy_eq_dx=1.5/x-1, 
          Dy_eq_dy=0;
    double v1 = exp(2*y_eq-y[0]),
          Dv1_dx=v1*(2*Dy_eq_dx-0),
          Dv1_dy=v1*(2*Dy_eq_dy-1);
    double v2 = exp(y[0]), 
          Dv2_dx=v2*(0), 
          Dv2_dy=v2*(1);
    double z = k*(v1-v2), 
          Dz_dx=k*(Dv1_dx-Dv2_dx), 
          Dz_dy=k*(Dv1_dy-Dv2_dy);   
    dfdx[0] = Dz_dx;
    dfdy[0] = Dz_dy;
    return GSL_SUCCESS;
}

对于较大的代码,请使用自动执行这些步骤的代码重写工具。 auto-diff.org 应该有一个合适的列表。