module ali_mod
  use param_mod
  use general_mod
 
  implicit none


contains

  subroutine methode_ali(S_ali,J_bar_ali,J_nu_ali)
    integer iter,i,j,k,compteur
    double precision, dimension(nxmod) ::  J_bar_ali
    double precision, dimension(nfr,nxmod) :: J_nu_ali
    double precision, dimension(nxmod,niter) :: S_ali
    double precision, dimension(nxmod) :: a,b,c,d,e ! coeff matrice tridiagonale

     S_ali(:,1) = BENU(nu_0,T_in)

   
     call elements_diag_lambda_etoile_mu_nu(a,b,c,d,e,lambda_etoile_mu_nu)
     call operateur_lambda_etoile(lambda_etoile_mu_nu,lambda_etoile,W)


     compteur = 1
     do iter = 2,niter
        call calcul_J_bar_ali(J_bar_ali,J_nu_ali,iter,S_ali)
        call calcul_S_ali(lambda_etoile,S_ali,iter,J_bar_ali)
        call calcul_population(S_ali,N1,N2,iter,NH)
! acceleration NG : 16 oct 2017
        if (iter == compteur+3+1) then
           call acceleration_ali(J_bar_ali,S_ali,iter)
           compteur = compteur + 3
        endif
     enddo

! gnuplot
     do j=1,nxmod  
         write(113,*) log10(xmod(j)),log10(S_ali(j,2)),log10(S_ali(j,5)),log10(S_ali(j,10)),log10(S_ali(j,20)),log10(S_ali(j,30)),log10(S_ali(j,50)),log10(S_ali(j,100)),log10(S_ali(j,150)),log10(S_ali(j,niter))       
      enddo

! gnuplot

!!$plot 'fort.113' u 1:2 w l title 'iteration 2','fort.113' u 1:3 w l title 'iteration 5', 'fort.113' u 1:4 w l title 'iteration 10', 'fort.113' u 1:5 w l title 'iteration 20', 'fort.113' u 1:6 w l title 'iteration 30', 'fort.113' u 1:7 w l title 'iteration 50','fort.113' u 1:8 w l title 'iteration 100','fort.113' u 1:9 w l title 'iteration 150','fort.113' u 1:10 w l title 'iteration 200'

! lecture des resultats
      write(100,1) (xmod(j),j=1,nxmod)
      do i =1,niter
         write(100,2) i
         write(101,2) i
         write(102,2) i
         write(100,1) (S_ali(j,i),j=1,nxmod)
         write(101,1) (N1(j,i),j=1,nxmod)
         write(102,1) (N2(j,i),j=1,nxmod)
      enddo

1     format(5E14.5) ! 5 nombres par ligne
2     format('iter=',I10)


    return
  end subroutine methode_ali

  subroutine elements_diag_lambda_etoile_mu_nu(a,b,c,d,e,lambda_etoile_mu_nu)
    double precision, dimension(nxmod,nfr,nmu) :: lambda_etoile_mu_nu
    double precision, dimension(nxmod) :: a,b,c,d,e
    integer i,imu,ifreq,itau,j,k

   
    lambda_etoile_mu_nu(:,:,:) = 0.d0
   
      d(:) = 0.d0
      e(:) = 0.d0

     do ifreq = 1,nfr
        do imu = 1,nmu
         
           call coeff_mat_tridiagonale(a,b,c,nxmod,imu,ifreq)
          
           e(nxmod) = a(nxmod)/b(nxmod)
           do i = nxmod-1,1,-1
              e(i) = a(i)/(b(i)-c(i)*e(i+1))
           enddo
           d(1) = c(1)/b(1)
           do i = 2,nxmod
              d(i) = c(i)/(b(i)-a(i)*d(i-1))
           enddo

           lambda_etoile_mu_nu(1,ifreq,imu) = 1.d0/(b(1)*(1.d0-d(1)*e(2)))
           lambda_etoile_mu_nu(nxmod,ifreq,imu) = 1.d0/(b(nxmod)-a(nxmod)*d(nxmod-1))
           do i =2,nxmod-1
              lambda_etoile_mu_nu(i,ifreq,imu) = 1.d0/((1.d0-d(i)*e(i+1))*(b(i)-a(i)*d(i-1)))
          enddo
        enddo
     enddo

    return
  end subroutine elements_diag_lambda_etoile_mu_nu
  
  subroutine operateur_lambda_etoile(lambda_etoile_mu_nu,lambda_etoile,W)
    double precision, dimension(nxmod) :: lambda_etoile
    double precision, dimension(nxmod,nfr,nmu) :: lambda_etoile_mu_nu
    integer i,j,k

    double precision, dimension(nfr) :: W

    lambda_etoile(:) = 0.d0

    do k = 1,nxmod
       do i = 1,nfr
          do j = 1,nmu
             lambda_etoile(k) = lambda_etoile(k) + lambda_etoile_mu_nu(k,i,j)*(1.d0/nmu)*W(i)
          enddo
       enddo
    enddo

    return
  end subroutine operateur_lambda_etoile
  

  subroutine calcul_S_ali(lambda_etoile,S_ali,iter,J_bar_ali)
    double precision, dimension(nxmod) :: lambda_etoile
    double precision, dimension(nxmod,niter) :: S_ali
    double precision, dimension(nxmod) :: J_bar_ali
    integer iter,k
    double precision, dimension(nxmod) :: delta_S_ali


    do k = 1,nxmod
       delta_S_ali(k) = ((1.d0-coeff_extinction(k))*J_bar_ali(k)+ &
       & coeff_extinction(k)*BENU(nu_0,T_in)-S_ali(k,iter-1))/(1.d0-(1.d0-coeff_extinction(k))* &
       & lambda_etoile(k))
       S_ali(k,iter) = S_ali(k,iter-1)+delta_S_ali(k)
    enddo
! bricolage car CL d'ordre 1
    S_ali(1,iter) = S_ali(2,iter)
    S_ali(nxmod,iter) = S_ali(nxmod-1,iter)

    return
  end subroutine calcul_S_ali

  subroutine calcul_J_bar_ali(J_bar_ali,J_nu_ali,iter,S_ali)
    integer j,k,iter
    double precision, dimension(nxmod) ::  J_bar_ali  
    double precision, dimension(nfr,nxmod) :: J_nu_ali
    double precision, dimension(nxmod,niter) :: S_ali
    double precision, dimension(nxmod) :: a,b,c,d,e ! coeff matrice tridiagonale
    
    do j = 1,nfr  ! frequence
       do k = 1,nmu ! direction
          call coeff_mat_tridiagonale(a,b,c,nxmod,k,j)
          call elimination_gauss(a,b,c,d,u_ali,iter,k,j,S_ali,I_inf)
       enddo
    enddo
     call calcul_J_nu(u_ali,nxmod,J_nu_ali)
     call calcul_J_bar(J_bar_ali,J_nu_ali,W)

    return
  end subroutine calcul_J_bar_ali

  subroutine acceleration_ali(J_bar_ali,S_ali,iter)
    double precision, dimension(nxmod,niter) :: S_ali
    double precision, dimension(nxmod) ::  J_bar_ali,W_acc
    double precision S_intermediaire,a_acc,b_acc,A1,A2,B1,B2,C1,C2,aux1,aux2,aux3
    integer iter,k
    
    W_acc(:) = 1.d0/J_bar_ali(:) 
    A1 = 0.d0
    A2 = 0.d0
    B1 = 0.d0
    B2 = 0.d0
    C1 = 0.d0
    C2 = 0.d0
    
    do k = 1,nxmod
       aux1 = 0.d0
       aux2 = 0.d0
       aux3 = 0.d0
       
       aux1 = S_ali(k,iter)-2.d0*S_ali(k,iter-1)+S_ali(k,iter-2)
       aux2 = S_ali(k,iter)-S_ali(k,iter-1)-S_ali(k,iter-2)+S_ali(k,iter-3)
       aux3 = S_ali(k,iter)-S_ali(k,iter-1)

       A1 = A1+(aux1**2.d0)*W_acc(k)
       B1 = B1+aux2*W_acc(k)*aux1
       B2 = B2+(aux2**2.d0)*W_acc(k)
       C1 = C1+aux1*aux3*W_acc(k)
       C2 = C2+aux2*aux3*W_acc(k)
    enddo
    A2 = B1
    a_acc = (C1*B2-C2*B1)/(A1*B2-A2*B1)
    b_acc = (C2*A1-C1*A2)/(A1*B2-A2*B1)

    write(120,*) a_acc,b_acc

!  15/11/2017
    if ((a_acc == 0.d0) .or. (b_acc == 0.d0)) then
       write(*,*) 'Le schema ALI a convergé, le programme est terminé'
       STOP
    endif
! fin modif 

    do k = 1,nxmod
       S_intermediaire = (1.d0-a_acc-b_acc)*S_ali(k,iter)+a_acc*S_ali(k,iter-1)+b_acc*S_ali(k,iter-2)
       S_ali(k,iter) = S_intermediaire
    enddo

  end subroutine acceleration_ali

  subroutine calcul_population(S_ali,N1,N2,iter,NH)
    double precision, dimension(nxmod,niter) :: S_ali,N1,N2
    integer iter
    double precision, dimension(nxmod) :: t,NH

    t(:) = (gg1/gg2)*(1.d0+(2.d0*h*(nu_0)**3.d0)/(cl*cl*S_ali(:,iter)))
    N2(:,iter) = NH(:)/(1.d0+t(:))
    N1(:,iter) = NH(:)-N2(:,iter)
    
  end subroutine calcul_population



end module ali_mod
