直观的 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 应该有一个合适的列表。
我需要求解具有刚性行为的 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
我需要修改他们给我的示例,我需要使用求解刚性方程的算法,最好 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 应该有一个合适的列表。