Hi, I hope this kind of problem has already been faced by users of this mail-list.
I have a code that solves a relatively simple equation, it is somewhat an Helmotz equation (with negative parameter) whose solution is combination of an exponential increasing+ exponential decreasing function (one can treat first this very simply analytically). This is the equation y''[r]+2/r y'[r]-k y[r]=0 analytical solutions are y[r]=C1 Exp[- sqrt(k) r] /r+ C2 Exp[ sqrt(k) r] /(Sqrt[k]* r) If one is interested in only the exponential decreasing solution can just simply set C2=0. For a numerical solution, one must instead put initial conditions on the function and its derivative obtained from the analytical treatment (which is equivalent to dropping the exponential-increasing solution), so that the numerical code should of course integrate and obtain only the exponential decreasing solution (C2=0). After doing that, depending on the method and accuracy, you get the desired exponential decay but after a while, (for higher initial K-values) at some point the exponential increasing solution starts to dominate. It is of course only matter of numerical integration and not of wrong initial conditions. What I'm wondering is whether there is some way to force the code anyway to avoid the fake exponential increasing, or it must be held by the user (e.g., stopping when derivative becomes positive). Presently I use gsl_odeiv_control *k = gsl_odeiv_control_y_new(eps,eps); gsl_odeiv_control *g = gsl_odeiv_control_yp_new(eps,eps); For interested users, I also attach the code. The command line after standard compilation is very simple, e.g., ./test_hmz yi=1 kpar=0.2 meth=bsimp xmax=100 eps=1e-14 (for meth you can set bsimp, rk4, gear1, gear2, rk8pd, rkck), yi is th initial value of the function (doesn't modify the general solution behavior) kpar is the parameter of the function (the higher kpar, the steepest the exponential decay) xmax is the right bound of the integration domain (which starts from x=1) eps is the precision of the GSL controlling function. You'll see the output written in the two-column file "results_hmz.dat", whose plot immediately shows the behaviour. I hope there are some tricks I don't know to get the right behavior. Thank you in advance Ruben
#include<stdlib.h> #include<stdio.h> #include <string.h> #include <stdarg.h> #include<math.h> #include<gsl/gsl_errno.h> #include<gsl/gsl_odeiv.h> #include<gsl/gsl_const_cgs.h> #include<gsl/gsl_integration.h> #include<gsl/gsl_matrix.h> double numpar (char * parameter); char * strrev(char * string); char* stringpar (char * parameter); /* ##################################################################################### */ /* Solution of the Poisson equation with screened potential */ /* using spherical coordinates */ /* y''[r]+2/r y[r]- k y[r]=0 */ /* The linearly independent solutions are */ /* y[r]=C1 Exp[- sqrt(k) r]/r+ C2 Exp[ sqrt(k) r]/(Sqrt[k]* r) */ /* thus there is an exponential decreasing and exponential increasing function. */ /* If one is interested only the the first one, then C2=0 */ /* Solving the equation with initial conditions requires to */ /* set the function at the value r0, y[r0] and then its derivative */ /* at the value derived analytically by derivation of the solution with C2=0 */ /* #################################################################################### */ #define Pi 3.14159 /* Jacobian */ int jac (double x, const double y[], double *dfdy, double dfdt[], void *params) { double kpar=((double *)params)[0]; double dyi=((double *)params)[1]; double x0=((double *)params)[2]; 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); gsl_matrix_set(m,0,1,1); gsl_matrix_set(m,1,0,kpar); gsl_matrix_set(m,1,1,-2/x); dfdt[0]=0; dfdt[1]=2/pow(x0,2)*dyi; printf("Jacobian y[0] %5.3e dfdt[0] %5.3e dfdt[1] %5.3e\n", y[0],dfdt[0], dyi); return GSL_SUCCESS; } double xmax; char *output; int funct (double x, const double y[], double f[], void *params); int main (int argc, char *argv[]) { FILE *dat; char *meth; double x,eps, xmin, kpar, yi, dyi, c1, zio; /* ######################################################################*/ if (argc < 2) { printf("Test the solution of the Helmotz equation in spherical coordinates\n"); printf("test_algorithm yi=yi kpar=kpar meth=meth eps=eps [xmax=xmax]\n\n"); exit(1); } /* ######################################################################*/ int t; for (t=1; t<argc; t++) { if (strstr(argv[t], "kpar=") != NULL) kpar=numpar(argv[t]); if (strstr(argv[t], "meth=") != NULL) meth=stringpar(argv[t]); if (strstr(argv[t], "eps=") != NULL) eps=numpar(argv[t]); if (strstr(argv[t], "xmax=") != NULL) xmax=numpar(argv[t]); if (strstr(argv[t], "yi=") != NULL) yi=numpar(argv[t]); /* if (strstr(argv[t], "dyi=") != NULL) dyi=numpar(argv[t]); */ if (strstr(argv[t], "zio=") != NULL) zio=numpar(argv[t]); } if (!kpar) { printf("Parameter kpar not set\n"); return(1); } if (! yi) { printf("Set the initial values for the function\n"); return(1); } if (!output) output="results_hmz.dat"; if (!eps) eps=1e-7; if (!xmax) xmax=100.; if (!meth) { printf("Parameter meth not set\n"); return(1); } printf("kpar %5.3f meth %s eps %5.3e\n", kpar, meth, eps); /* ######################################################################*/ /* Choose the integration methd */ /* ######################################################################*/ const gsl_odeiv_step_type *T; if (strcmp(meth,"rk4") ==0) { /* const gsl_odeiv_step_type *T = gsl_odeiv_step_rk4; */ T = gsl_odeiv_step_rk4; } else if (strcmp(meth,"gear1") ==0) { /* const gsl_odeiv_step_type *T = gsl_odeiv_step_gear1; */ T = gsl_odeiv_step_gear1; } else if (strcmp(meth,"gear2") ==0) { /* const gsl_odeiv_step_type *T = gsl_odeiv_step_gear2; */ T = gsl_odeiv_step_gear2; } else if (strcmp(meth,"rkck") ==0) { /* const gsl_odeiv_step_type *T = gsl_odeiv_step_rkck; */ T = gsl_odeiv_step_rkck; } else if (strcmp(meth,"rk8pd") ==0) { /* const gsl_odeiv_step_type *T = gsl_odeiv_step_rkck; */ T = gsl_odeiv_step_rk8pd; } else if (strcmp(meth,"bsimp") ==0) { /* const gsl_odeiv_step_type *T = gsl_odeiv_step_rkck; */ T = gsl_odeiv_step_bsimp; } else { printf("Allowed methods are: rk4, gear1, gear2, rkck, rk8pd, bsimp\n\n"); exit(1); } /* void *jac; */ gsl_odeiv_step *s = gsl_odeiv_step_alloc (T,2); gsl_odeiv_control *k = gsl_odeiv_control_y_new(eps,eps); gsl_odeiv_control *g = gsl_odeiv_control_yp_new(eps,eps); gsl_odeiv_evolve * e = gsl_odeiv_evolve_alloc (2); /* printf("Receveing r0=%5.4e pc=%5.4e alpha=%5.4e gamma_val=%5.4e\n", r0, pc, alpha, gamma_val); */ /* ######################################################################## */ /* Set the initial value of the independent variable and stepsize */ double xinit=pow(10,-8); xmin=1; x=xmin; double h=1e-4; /* Determine the value of the constant for y[xmin]=yi */ c1=exp(sqrt(kpar)*xmin)*xmin*yi; /* Compute value of the derivative */ dyi=-c1* exp(-sqrt(kpar)*xmin)/pow(xmin,2)- c1* exp(-sqrt(kpar)*xmin)*sqrt(kpar)/xmin; dyi=-yi*(sqrt(kpar)+1/xmin); /* ######################################################################## */ double params[3]; params[0]=kpar; params[1]=dyi; params[2]=xmin; gsl_odeiv_system sys={funct, jac, 2, params}; printf("!Value c1 %5.3f yi %5.3f dyi %5.3e\n", c1,yi, dyi); double y[2]={yi, dyi}; /* ######################################################################## */ /* Fixed step size integration */ /* double dydx_in[2], dydx_out[2], y_err[2]; */ /* GSL_ODEIV_FN_EVAL (&sys, t,y,dydx_in); */ /* ######################################################################## */ int status, count=0, count_loop=0; double xprev=-10; double minR=1000; int countns=0; dat=fopen(output, "w"); printf("!Value c1 %5.3f yi %5.3f dyi %5.3e x %5.3e xmax %5.3f\n", c1,y[0], y[1], x, xmax); while (x < xmax) { status = gsl_odeiv_evolve_apply (e,g,s,&sys, &x,xmax , &h, y); /* status = gsl_odeiv_step_apply (s,x,h,y, y_err, dydx_in, dydx_out, &sys); */ if (x > xprev) { fprintf(dat, "%5.4e %5.4e\n", x, y[0]); } if (status !=GSL_SUCCESS) { break; } /* ############################################################################################ */ xprev=x; count++; /* dydx_in[0]=dydx_out[0]; */ /* dydx_in[1]=dydx_out[1]; */ /* x=x+h; */ } fclose(dat); gsl_odeiv_evolve_free(e); gsl_odeiv_control_free(g); gsl_odeiv_step_free(s); } /* ######################################################################## */ /*Field equations*/ /* ######################################################################## */ int funct (double x, const double y[], double f[], void *params) { int static iter=0, iterns=0; double kpar=((double *)params)[0]; f[0] = y[1]; f[1] =-2 * y[1]/x + kpar* y[0]; printf("Function x %5.3e y[0] %5.3e f[0] %5.3e\n", x, y[0], f[0]); return GSL_SUCCESS; } /* ################################################################################################ */ char * strrev(char * string) { int length = strlen(string); char * result = malloc(length+1); if( result != NULL ) { int i,j; result[length] = '\0'; for ( i = length-1, j=0; i >= 0; i--, j++ ) result[j] = string[i]; } return result; } /* ################################################################################################ */ char* stringpar (char * parameter) { int t, ch='='; double value; char *file; int substr=strlen(strrev(parameter))-strlen(strchr(strrev(parameter),ch)); char *dest=malloc(substr+1); file=strrev((strncpy(dest, strrev(parameter), substr))); return(file); } double numpar (char * parameter) { int t, ch='='; double value; /* printf("%s\n", parameter); */ int substr=strlen(strrev(parameter))-strlen(strchr(strrev(parameter),ch)); char *dest=malloc(substr); value=atof(strrev((strncpy(dest, strrev(parameter), substr)))); /* printf("%s m=%lf\n", strrev(strncpy(dest, strrev(parameter), substr)), m); */ return(value); }