diff --git a/homework/root-finding/Makefile b/homework/root-finding/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..5eeaabcb69948b499c819c920dc8deb55fe0f0b5 --- /dev/null +++ b/homework/root-finding/Makefile @@ -0,0 +1,70 @@ +CFLAGS = -Wall -O3 -std=gnu11 $(shell gsl-config --cflags) +LDLIBS = -lm $(shell gsl-config --libs) + +default: simple_wave.png improved_wave.png func.png + +simple_wave.png: paths exact.txt Makefile + echo '\ + set terminal png;\ + set output "$@";\ + set key top right;\ + set tics out;\ + set yrange [0:0.4];\ + set grid;\ + set xlabel "r (Bohr radius)";\ + set ylabel "f(r)";\ + set title "Shooting method with simple boundary condition";\ + plot\ + "simplepath2.txt" using 1:2 with line title "rmax = 2",\ + "simplepath4.txt" using 1:2 with line title "rmax = 4",\ + "simplepath6.txt" using 1:2 with line title "rmax = 6",\ + "simplepath8.txt" using 1:2 with line title "rmax = 8",\ + "simplepath10.txt" using 1:2 with line title "rmax = 10",\ + "exact.txt" using 1:2 with line title "exact solution",\ + ' | gnuplot + +improved_wave.png: paths exact.txt Makefile + echo '\ + set terminal png;\ + set output "$@";\ + set key top right;\ + set tics out;\ + set yrange [0:0.4];\ + set grid;\ + set xlabel "r (Bohr radius)";\ + set ylabel "f(r)";\ + set title "Shooting method with improved boundary condition";\ + plot\ + "improvedpath1.txt" using 1:2 with line title "rmax = 1",\ + "improvedpath2.txt" using 1:2 with line title "rmax = 2",\ + "improvedpath3.txt" using 1:2 with line title "rmax = 3",\ + "improvedpath4.txt" using 1:2 with line title "rmax = 4",\ + "exact.txt" using 1:2 with line title "exact solution",\ + ' | gnuplot + +func.png: Fe.txt Makefile + echo '\ + set terminal png;\ + set output "$@";\ + set key top right;\ + set tics out;\ + set xlabel "Energy";\ + set ylabel "Fe(rmax)";\ + set title "Zoom on Fe to show instability of ODE";\ + set xrange [-0.35:-0.32];\ + set yrange [-4.6:-4.2];\ + plot\ + "Fe.txt" using 1:2 with line title "rmax=8",\ + ' | gnuplot + +paths exact.txt Fe.txt: main + ./$< > out.txt + $(RM) N + +main: main.c functions.c + + +.PHONEY: clean + +clean: + $(RM) main *.o *.txt *.png \ No newline at end of file diff --git a/homework/root-finding/func.png b/homework/root-finding/func.png new file mode 100644 index 0000000000000000000000000000000000000000..c68e21e16175177fd8c646b0638142dee73cabf2 Binary files /dev/null and b/homework/root-finding/func.png differ diff --git a/homework/root-finding/functions.c b/homework/root-finding/functions.c new file mode 100755 index 0000000000000000000000000000000000000000..e836089f4902a00b845335ab6486cab7b8638d29 --- /dev/null +++ b/homework/root-finding/functions.c @@ -0,0 +1,249 @@ +#include "functions.h" + +static double E; +void f(gsl_vector* x, gsl_vector* fx) { + double x0 =gsl_vector_get(x,0); + double x1 =gsl_vector_get(x,1); + gsl_vector_set(fx,0,400*pow(x0,3)-400*x0*x1+2*x0-2); + gsl_vector_set(fx,1,200*(x1-pow(x0,2))); +} + +void radial(double r, gsl_vector* y, gsl_vector* dydr) { + double y0 = gsl_vector_get(y,0); + double y1 = gsl_vector_get(y,1); + gsl_vector_set(dydr,0,y1); + gsl_vector_set(dydr,1,2*(-1.0/r-E)*y0); +} + +double Fe_simple(double energy, double rmax, char* save_path) { + double rmin = 1e-3; + gsl_vector* ya = gsl_vector_alloc(2); + gsl_vector* yb = gsl_vector_alloc(2); + gsl_vector_set(ya,0,rmin-rmin*rmin); + gsl_vector_set(ya,1,1.0-2*rmin); + E = energy; + //printf("%g\n",E); + int steps = driver(radial,rmin,ya,rmax,yb,0.1,1e-4,1e-4,save_path); + double result = gsl_vector_get(yb,0); + gsl_vector_free(ya); + gsl_vector_free(yb); + return result; +} + +void print_vector(char s[], gsl_vector* v) { + printf("%s\n",s); + for(int i=0;i<v->size;i++) { + printf("%15g",gsl_vector_get(v,i)); + printf("\n"); + } +} + +void print_matrix(gsl_matrix* M) { + for(int i = 0; i < M->size1; i++) { + for(int j = 0; j < M->size2; j++) { + printf("%10g\t", gsl_matrix_get(M, i, j)); + } + printf("\n"); + } +} + +void GS_decomp(gsl_matrix* A, gsl_matrix* R) { + int n = A -> size1; + int m = A -> size2; + for(int i=0;i<m;i++) { + gsl_vector_view ai = gsl_matrix_column(A,i); + double Rii = gsl_blas_dnrm2(&(ai.vector)); + gsl_matrix_set(R,i,i,Rii); + gsl_vector_scale(&(ai.vector),1/Rii); + for(int j=i+1;j<m;j++) { + gsl_vector_view aj = gsl_matrix_column(A,j); + double Rij; + gsl_blas_ddot(&(ai.vector),&(aj.vector),&Rij); + gsl_matrix_set(R,i,j,Rij); + gsl_vector* qiRij = gsl_vector_alloc(n); + gsl_vector_memcpy(qiRij,&(ai.vector)); + gsl_vector_scale(qiRij,Rij); + gsl_vector_sub(&(aj.vector),qiRij); + gsl_vector_free(qiRij); + } + } +} + +void GS_solve(gsl_matrix* Q, gsl_matrix* R, gsl_vector* b, gsl_vector* x) { + assert(Q->size1==Q->size2); + int m = Q -> size2; + gsl_blas_dgemv(CblasTrans,1,Q,b,0,x); + for(int i=m-1;i>=0;i--) { + double xi = gsl_vector_get(x,i); + for(int j=i+1;j<m;j++) { + xi += -gsl_matrix_get(R,i,j)*gsl_vector_get(x,j); + } + xi /= gsl_matrix_get(R,i,i); + gsl_vector_set(x,i,xi); + } +} + +void rkstep12(void f(double t,gsl_vector* y,gsl_vector* dydt),double t,gsl_vector* yt,double h,gsl_vector* yh,gsl_vector* err) { + gsl_vector* k_zero = gsl_vector_alloc(yt->size); + f(t,yt,k_zero); + gsl_vector_memcpy(err,k_zero); + gsl_vector_scale(err,-1.0); + gsl_vector_scale(k_zero,h/2); + gsl_vector_add(k_zero,yt); + f(t+h/2,k_zero,yh); + gsl_vector_add(err,yh); + gsl_vector_scale(err,h); + gsl_vector_scale(yh,h); + gsl_vector_add(yh,yt); + gsl_vector_free(k_zero); +} + +int driver(void f(double,gsl_vector*,gsl_vector*),double a,gsl_vector* ya,double b,gsl_vector* yb,\ + double h,double acc,double eps, char* save_path) { + FILE* path_stream = fopen(save_path,"a"); + if(save_path!="N") { + fprintf(path_stream,"%g ",a); + for(int i=0;i<ya->size;i++) {fprintf(path_stream,"%g ",gsl_vector_get(ya,i));} fprintf(path_stream,"\n"); + } + gsl_vector_memcpy(yb,ya); + int n = 1; + double x = a; + double step_size = h; + while(x<b) { + gsl_vector* yx = gsl_vector_alloc(ya->size); + gsl_vector* err = gsl_vector_alloc(ya->size); + rkstep12(f,x,yb,step_size,yx,err); + double loc_tol = (eps*gsl_blas_dnrm2(yb)+acc)*sqrt(step_size/(b-a)); + double loc_err = gsl_blas_dnrm2(err); + if(loc_tol>loc_err) { + n++; + x += step_size; + gsl_vector_memcpy(yb,yx); + if(save_path!="N") { + fprintf(path_stream,"%g ",x); + for(int i=0;i<ya->size;i++) {fprintf(path_stream,"%g ",gsl_vector_get(yb,i));} fprintf(path_stream,"\n"); + } + } + step_size *= pow(loc_tol/loc_err,0.25)*0.95; + gsl_vector_free(yx); + gsl_vector_free(err); + } + fclose(path_stream); +return n; +} + +int search(int n, double* x, double z){ + assert(x[0]<=z && z<=x[n-1]); + int i=0, j=n-1; + while(j-i>1){ + int mid=(i+j)/2; + if(z>x[mid]) i=mid; else j=mid; + } +return i; +} + +void cubic_interpol(int n, double x[], double y[], cubic_coefs* a) { + gsl_matrix* A = gsl_matrix_alloc(n,n); + gsl_vector* b = gsl_vector_alloc(n); + gsl_vector* B = gsl_vector_alloc(n); + gsl_vector_set(B,0,(3*(y[1]-y[0])/(x[1]-x[0]))); + gsl_vector_set(B,n-1,(3*(y[n-1]-y[n-2])/(x[n-1]-x[n-2]))); + for(int i=0;i<n-2;i++) { + double B_i1 = 3*((y[i+1]-y[i])/(x[i+1]-x[i])+(y[i+2]-y[i+1])/(x[i+2]-x[i+1])*(x[i+1]-x[i])/(x[i+2]-x[i+1])); + gsl_vector_set(B,i+1,B_i1); + } + for(int i=0;i<n;i++) { + for(int j=0;j<n;j++) { + if(abs(i-j)>1) { + gsl_matrix_set(A,i,j,0); + } + if((i-j)==1) { + gsl_matrix_set(A,i,j,1); + } + if((i-j==-1)) { + if(i==0) {gsl_matrix_set(A,i,j,1);} + else { + double Qi = (x[i]-x[i-1])/(x[i+1]-x[i]); + gsl_matrix_set(A,i,j,Qi); + } + } + if((i-j)==0) { + if(i==0 || i==n-1) {gsl_matrix_set(A,i,j,2);} + else { + double Di = 2*((x[i]-x[i-1])/(x[i+1]-x[i]))+2; + gsl_matrix_set(A,i,j,Di); + } + } + } + } + gsl_linalg_HH_solve(A,B,b); + for(int i=0;i<n-1;i++) { + double pi = (y[i+1]-y[i])/(x[i+1]-x[i]); + double bi = gsl_vector_get(b,i); + double bi1 = gsl_vector_get(b,i+1); + (*a).b[i] = bi; + (*a).c[i] = (3*pi-2*bi-bi1)/(x[i+1]-x[i]); + (*a).d[i] = (bi+bi1-2*pi)/pow((x[i+1]-x[i]),2); + } + gsl_matrix_free(A); + gsl_vector_free(b); + gsl_vector_free(B); +} + +double cubic_eval(cubic_coefs coefs, int n, double* x, double* y, double z) { + int i = search(n,x,z); +return y[i]+(coefs.b)[i]*(z-x[i])+(coefs.c)[i]*pow((z-x[i]),2)+(coefs.d)[i]*pow((z-x[i]),3); +} + +void newton_root(void f(gsl_vector* x, gsl_vector* fx), gsl_vector* x, double eps) { + int dim = x->size; + gsl_matrix* J = gsl_matrix_alloc(dim,dim); + gsl_matrix* JR = gsl_matrix_alloc(dim,dim); + gsl_vector* fx = gsl_vector_alloc(dim); + gsl_vector* fdx = gsl_vector_alloc(dim); + gsl_vector* Dx = gsl_vector_alloc(dim); + f(x,fx); + //printf("Dim:%i\n",dim); + //printf("x: %g\n",gsl_vector_get(x,0)); + //printf("f(x): %g\n",gsl_vector_get(fx,0)); + double stepsize = 1; + while(gsl_blas_dnrm2(fx) > eps && stepsize > DX) { + for(int j=0;j<dim;j++) { + double* xk = gsl_vector_ptr(x,j); + for(int i=0;i<dim;i++) { + f(x,Dx); + double fi = gsl_vector_get(Dx,i); + //printf("%.10g\n",*xk); + //printf("fi: %.10g\n",fi); + *xk += DX; f(x,Dx); + double dfi = gsl_vector_get(Dx,i); + //printf("%.10g\n",*xk); + //printf("dfi: %.10g\n",dfi); + *xk -=DX; + gsl_matrix_set(J,i,j,(dfi-fi)/DX); + } + } + //printf("Derivative: %g\n",gsl_matrix_get(J,0,0)); + gsl_vector_scale(fx,-1.0); + GS_decomp(J,JR); + GS_solve(J,JR,fx,Dx); + gsl_vector_scale(fx,-1.0); + double l = 1; + gsl_blas_daxpy(l,Dx,x); + f(x,fdx); + while(gsl_blas_dnrm2(fdx) > (1-l)*gsl_blas_dnrm2(fx) && l > (1.0/64.0)) { + l /= 2; + gsl_blas_daxpy(-l,Dx,x); + f(x,fdx); + } + f(x,fx); + //printf("x: %g\n",gsl_vector_get(x,0)); + //printf("f(x): %g\n",gsl_vector_get(fx,0)); + stepsize = gsl_blas_dnrm2(Dx)*l; + } + gsl_matrix_free(J); + gsl_matrix_free(JR); + gsl_vector_free(fx); + gsl_vector_free(fdx); + gsl_vector_free(Dx); +} \ No newline at end of file diff --git a/homework/root-finding/functions.h b/homework/root-finding/functions.h new file mode 100755 index 0000000000000000000000000000000000000000..80358492f4b395d3727a5c529e098aada1d76237 --- /dev/null +++ b/homework/root-finding/functions.h @@ -0,0 +1,33 @@ +#ifndef FUNCTIONS_H +#define FUNCTIONS_H + +#include<math.h> +#include<time.h> +#include<stdio.h> +#include<float.h> +#include<assert.h> +#include<gsl/gsl_vector.h> +#include<gsl/gsl_matrix.h> +#include<gsl/gsl_blas.h> +#include<gsl/gsl_linalg.h> +#define RND (double)rand()/10000 +#define DX sqrt(DBL_EPSILON) +typedef struct {double* b; double* c; double* d;} cubic_coefs; + +void f(gsl_vector* x, gsl_vector* fx); +void radial(double r, gsl_vector* y, gsl_vector* dydr); +double Fe_simple(double energy, double rmax, char* save_path); +void aux(gsl_vector* x, gsl_vector* fx); +void print_vector(char s[], gsl_vector* v); +void print_matrix(gsl_matrix* M); +void GS_decomp(gsl_matrix* A, gsl_matrix* R); +void GS_solve(gsl_matrix* Q, gsl_matrix* R, gsl_vector* b, gsl_vector* x); +void rkstep12(void f(double t,gsl_vector* y,gsl_vector* dydt),double t,gsl_vector* yt,double h,gsl_vector* yh,gsl_vector* err); +int driver(void f(double,gsl_vector*,gsl_vector*),double a,gsl_vector* ya,double b,gsl_vector* yb,\ + double h,double acc,double eps,char* save_path); +int search(int n, double* x, double z); +void cubic_interpol(int n, double x[], double y[], cubic_coefs* a); +double cubic_eval(cubic_coefs coefs, int n, double* x, double* y, double z); +void newton_root(void f(gsl_vector* x, gsl_vector* fx), gsl_vector* x, double eps); + +#endif \ No newline at end of file diff --git a/homework/root-finding/improved_wave.png b/homework/root-finding/improved_wave.png new file mode 100644 index 0000000000000000000000000000000000000000..3c8fb2f4557dc16cc650cf0fb2dab8d7aec9abd3 Binary files /dev/null and b/homework/root-finding/improved_wave.png differ diff --git a/homework/root-finding/main.c b/homework/root-finding/main.c new file mode 100755 index 0000000000000000000000000000000000000000..456dd1e8725ad69b4b4fe481d40820c1ba855aa0 --- /dev/null +++ b/homework/root-finding/main.c @@ -0,0 +1,75 @@ +#include "functions.h" +#define nr 2*64 + +static double xs[nr]; static double ys[nr]; +static double my_cubic_b[nr-1]; +static double my_cubic_c[nr-1]; +static double my_cubic_d[nr-1]; +static cubic_coefs coefs = {.b=my_cubic_b,.c=my_cubic_c,.d=my_cubic_d}; + +void aux(gsl_vector* x, gsl_vector* fx) { + double energy = gsl_vector_get(x,0); + double M = cubic_eval(coefs,nr,xs,ys,energy); + gsl_vector_set(fx,0,M); +} + +int main() { + printf("Finding root of Rosenbrock's valley function:\n"); + gsl_vector* x0 = gsl_vector_alloc(2); + gsl_vector_set(x0,0,-3); + gsl_vector_set(x0,1,3); + print_vector("Starting guess:",x0); + newton_root(f,x0,1e-9); + print_vector("Found root:",x0); + gsl_vector_free(x0); + + printf("\n\nFinding bound states of hydrogen with simple boundary:\n"); + //Making spline of Fe(rmax)(e) since its instability makes newtons method inable to calculate proper derivates (See func.png) + for(int rmax=2;rmax<=10;rmax+=2) { + int index = 0; + for(double e=-2;e<0;e+=2.0/(nr)) {xs[index]=e;ys[index]=Fe_simple(e,rmax,"N");index+=1;} + cubic_interpol(nr,xs,ys,&coefs); + gsl_vector* x00 = gsl_vector_alloc(1); + double guess = -1.0; + gsl_vector_set(x00,0,guess); + printf("Rmax = %i\n",rmax); + print_vector("Starting guess:",x00); + newton_root(aux,x00,1e-9); + print_vector("Found root:",x00); + double energy = gsl_vector_get(x00,0); + char filename[30]; + sprintf(filename,"simplepath%i.txt",rmax); + Fe_simple(energy,rmax,filename); + gsl_vector_free(x00); + } + printf("\n\nFinding bound states of hydrogen with improved boundary:\n"); + for(int rmax=1;rmax<=4;rmax++) { + int index = 0; + double rd = (double)rmax; + for(double e=-2;e<0;e+=2.0/(nr)) {xs[index]=e;ys[index]=Fe_simple(e,rmax,"N")-rd*exp(-rd*sqrt(-2*e));index+=1;} + cubic_interpol(nr,xs,ys,&coefs); + gsl_vector* x00 = gsl_vector_alloc(1); + double guess = -1.0; + gsl_vector_set(x00,0,guess); + printf("Rmax = %i\n",rmax); + print_vector("Starting guess:",x00); + newton_root(aux,x00,1e-9); + print_vector("Found root:",x00); + double energy = gsl_vector_get(x00,0); + char filename[30]; + sprintf(filename,"improvedpath%i.txt",rmax); + Fe_simple(energy,rmax,filename); + gsl_vector_free(x00); + } + FILE* exact_stream = fopen("exact.txt","w"); + for(double r=1e-3;r<8;r+=1.0/64) { + fprintf(exact_stream,"%g %g\n",r,r*exp(-r)); + } + fclose(exact_stream); + FILE* plot_stream = fopen("Fe.txt","w"); + for(double r=-0.35;r<-0.32;r+=1.0e-4) { + fprintf(plot_stream,"%g %g\n",r,Fe_simple(r,8,"N")); + } + fclose(plot_stream); +return 0; +} \ No newline at end of file diff --git a/homework/root-finding/out.txt b/homework/root-finding/out.txt new file mode 100644 index 0000000000000000000000000000000000000000..fb3a8a455ece5e03fc6a4fcf19f6bdda0e582738 --- /dev/null +++ b/homework/root-finding/out.txt @@ -0,0 +1,58 @@ +Finding root of Rosenbrock's valley function: +Starting guess: + -3 + 3 +Found root: + 1 + 1 + + +Finding bound states of hydrogen with simple boundary: +Rmax = 2 +Starting guess: + -1 +Found root: + -0.127929 +Rmax = 4 +Starting guess: + -1 +Found root: + -0.483549 +Rmax = 6 +Starting guess: + -1 +Found root: + -0.499289 +Rmax = 8 +Starting guess: + -1 +Found root: + -0.499977 +Rmax = 10 +Starting guess: + -1 +Found root: + -0.5 + + +Finding bound states of hydrogen with improved boundary: +Rmax = 1 +Starting guess: + -1 +Found root: + -0.500014 +Rmax = 2 +Starting guess: + -1 +Found root: + -0.500873 +Rmax = 3 +Starting guess: + -1 +Found root: + -0.500605 +Rmax = 4 +Starting guess: + -1 +Found root: + -0.500018 diff --git a/homework/root-finding/simple_wave.png b/homework/root-finding/simple_wave.png new file mode 100644 index 0000000000000000000000000000000000000000..d032b1aa7191d94db1af02ef66ff14a135fdb74e Binary files /dev/null and b/homework/root-finding/simple_wave.png differ