program CG ! Conjugate Gradient ! Solve 1D heat equation ! Solve A T = 0, with A the matrix corresponding to the laplacian ! ! Heat equation : dT/dt = alpha d^2 T/dx^2 ! When converged, dT/dt = 0, the equation becomes : 0 = alpha d^2 T/dx^2 <--> 0 = d^2 T/dx^2 ! Numericaly, this means : (T(i+1)-2.0*T(i)+T(i-1)) * 1/(Dx*Dx) = 0 <--> A T = 0 with the matrix A, a diagonal symetric positiv definit matrix ! The matrix is like : ! -2/(dx*dx) 1/(dx*dx) 0 0 0 0 .... ! 1/(dx*dx) -2/(dx*dx) 1/(dx*dx) 0 0 0 .... ! 0 1/(dx*dx) -2/(dx*dx) 1/(dx*dx) 0 0 .... ! 0 0 1/(dx*dx) -2/(dx*dx) 1/(dx*dx) 0 .... ! 0 0 0 1/(dx*dx) -2/(dx*dx) 1/(dx*dx) 0 ! etc implicit none integer, parameter :: ndim = 1 real(8), dimension(1:ndim) :: Lx,Dx,InvDxDx integer, dimension(1:ndim) :: Nx real(8) :: beta, rho, rho0, gam integer :: n,i real(8), allocatable, dimension(:) :: T,Residut,p,q Nx(1) = 100 Lx(:) = 0.1d0 Dx(:) = Lx(:)/((Nx(:)-1)*1.0d0) InvDxDx(:) = 1.0d0/(Dx(:)*Dx(:)) allocate(T(0:Nx(1)+1),Residut(0:Nx(1)+1),p(0:Nx(1)+1),q(0:Nx(1)+1)) ! Initial Solution T(1:Nx(1)) = 0.0d0 T(0) = 10.0d0 T(Nx(1)+1) = -1.0d0 ! Initialisation do i=1,Nx(1) Residut(i) = - (T(i+1)-2.0d0*T(i)+T(i-1)) * InvDxDx(1) end do p(:) = 0.0d0 beta = 0.0d0 rho = 0.0d0 do i=1,Nx(1) rho = rho + Residut(i)*Residut(i) end do ! Iteration n = 0 do n = n + 1 do i=1,Nx(1) p(i) = Residut(i) + beta * p(i) end do ! Matrix Operation : q = A p do i=1,Nx(1) q(i) = (p(i+1)-2.0d0*p(i)+p(i-1)) * InvDxDx(1) end do gam = 0.0d0 do i=1,Nx(1) gam = gam + p(i)*q(i) end do gam = rho / gam do i=1,Nx(1) T(i) = T(i) + gam * p(i) end do do i=1,Nx(1) Residut(i) = Residut(i) - gam * q(i) end do ! Test if residut is < 1.e-7 so that solution is converged if(maxval(dabs(Residut(1:Nx(1)))) < 1d-7) exit ! Converged Solution write(*,*) "CG step ",n,"Residut",maxval(dabs(Residut(1:Nx(1)))) rho0 = rho ! Save old rho value rho = 0.0d0 do i=1,Nx(1) rho = rho + Residut(i)*Residut(i) end do beta = rho / rho0 end do write(*,*) "Solution converged in ", n ,"Iterations, with a res of ", maxval(abs(Residut(1:Nx(1)))) ! Solution plot open(10,file="out-GC.dat") do i=1,Nx(1) write(10,*) Dx(1)*(i-1),T(i) end do close(10) deallocate(T,Residut,p,q) end program CG
C version above has been translated from fortran by Adrien Cassagne.
#include<math.h> #include<stdio.h> #include<stdlib.h> int main(int argc, char** argv) { // Conjugate Gradient // Solve 1D heat equation // Solve A T = 0, with A the matrix corresponding to the laplacian // // Heat equation : dT/dt = alpha d^2 T/dx^2 // When converged, dT/dt = 0, the equation becomes : 0 = alpha d^2 T/dx^2 <--> 0 = d^2 T/dx^2 // Numericaly, this means : (T(i+1)-2.0*T(i)+T(i-1)) * 1/(Dx*Dx) = 0 <--> A T = 0 with the matrix A, a diagonal symetric positiv definit matrix // The matrix is like : // -2/(dx*dx) 1/(dx*dx) 0 0 0 0 .... // 1/(dx*dx) -2/(dx*dx) 1/(dx*dx) 0 0 0 .... // 0 1/(dx*dx) -2/(dx*dx) 1/(dx*dx) 0 0 .... // 0 0 1/(dx*dx) -2/(dx*dx) 1/(dx*dx) 0 .... // 0 0 0 1/(dx*dx) -2/(dx*dx) 1/(dx*dx) 0 // etc int i, n, Nx, ndim = 1; double Lx, Dx, InvDxDx; double beta, rho, rho0, gam, maxResidut; double *T, *Residut, *p, *q; // pointers FILE *f; Nx = 100; Lx = 0.1; Dx = Lx / ((Nx -1) * 1.0); InvDxDx = 1.0 / (Dx * Dx); T = (double*)malloc((Nx +1) * sizeof(double)); Residut = (double*)malloc((Nx +1) * sizeof(double)); p = (double*)malloc((Nx +1) * sizeof(double)); q = (double*)malloc((Nx +1) * sizeof(double)); // Initial Solution T[0] = 10; for(i = 1; i < Nx; ++i) T[i] = 0.0; T[Nx] = -1.0; // Initialisation for(i = 1; i < Nx; ++i) Residut[i] = -( T[i +1] - 2.0 * T[i] + T[i -1] ) * InvDxDx; for(i = 0; i < Nx +1; ++i) p[i] = 0.0; beta = 0.0; rho = 0.0; for(i = 1; i < Nx; ++i) rho += Residut[i] * Residut[i]; // Iteration n = 0; while(1) { n++; for(i = 1; i < Nx; ++i) p[i] = Residut[i] + beta * p[i]; // Matrix Operation : q = A p for(i = 1; i < Nx; ++i) q[i] = (p[i +1] - 2.0 * p[i] + p[i -1]) * InvDxDx; gam = 0.0; for(i = 1; i < Nx; ++i) gam = gam + p[i] * q[i]; gam = rho / gam; for(i = 1; i < Nx; ++i) T[i] = T[i] + gam * p[i]; for(i = 1; i < Nx; ++i) Residut[i] = Residut[i] - gam * q[i]; // find maxResidut maxResidut = 0; for(i = 1; i < Nx; ++i) if(fabs(Residut[i]) > maxResidut) maxResidut = fabs(Residut[i]); // Test if residut is < 1.e-7 so that solution is converged if(maxResidut < 1e-7) break; // Converged Solution printf("CG step %d, maxResidut %lf.\n", n, maxResidut); rho0 = rho; // Save old rho value rho = 0.0; for(i = 1; i < Nx; ++i) rho += Residut[i] * Residut[i]; beta = rho / rho0; } printf("Solution converged in %d iterations, with a residut of %g\n", n, maxResidut); // Solution plot f = fopen("out-GC.dat", "w"); for(i = 1; i < Nx; ++i) fprintf(f, "%lf %lf\n", Dx * (i -1), T[i]); fclose(f); free(T); free(Residut); free(p); free(q); return 0; }