!
!23456789a123456789b123456789c123456789d123456789e123456789f123456789g12
! D.J. Jeffery, 2020jan06
!      include 'saha_solver.f'  ! The Saha solver.
!23456789a123456789b123456789c123456789d123456789e123456789f123456789g12
      include 'xne_acceleration.f'   ! Electron density solution iteration acceleration.
      include 'partition_function_read.f'  ! Reads in the partition function table.
      include 'saha_solver_functions.f'  ! Includes some saha_solver.f functions.
!23456789a123456789b123456789c123456789d123456789e123456789f123456789g12
      subroutine saha_solver(kkel,kel,imassnumfrac,xel,                     &
     &                       rho,tem,r_dilution,                            &
     &                       iacceleration,idiagnostic,ih_minus_not,        &
     &                       xne_converged,                                 &
     &                       ixne_initial,x_reduced,xx_reduced,             &
     &                       xne,xne_h,aname,aweight,xne_atom_ratio,        &
     &                       fraction,iter)
      include 'saha_solver_declarations.f'
!
      if(ipartfunc .eq. 0  .or.  idiagnostic .eq. 3)then
         ipartfunc=1
         jel_ion(1,1)=-1      ! We allow for the H- ion.
         jel_ion(1,2:nel)=0   ! All other elements start with the neutral atom.
         do402 : do k_atom=1,nion  ! We allow for C6+ = CVII mainly for testing purposes. 
           jel_ion(2,k_atom)=k_atom
         end do do402 
         jel_ion(2,nion+1:nel)=nion-1 ! Standard upper limit on ionization stages.
!
         call partition_function_read(nel,nion,jel_ion,idiagnostic,                          &
     &                  aname,aweight,xion_en,partfunc)
!          This code uses the partition functions themselves, not their ratios
!          as in Mihalas-1978-113--114.
         if(idiagnostic .eq. 3) then
             do405 : do k_atom=1,nel      ! k_atom is atomic number as for Mihalas-1978-112.
               jmax=jel_ion(2,k_atom)
               write(*,fmt=910) aname(k_atom),k_atom,aweight(k_atom),                         &
     &                          xion_en(-1:jmax,k_atom)
               write(*,fmt=920) partfunc(-1:jmax-1,k_atom)
  910          format(1x,a2,i4,f6.0,18x,8f9.3)
  920          format(31x,8f9.3)
             end do do405
             return    ! See MRC-78 for return statement.
         end if
      end if
!
      if(iacceleration .lt. 0  .or.  iacceleration .gt. 3) then
          print*,'You have given iacceleration=',iacceleration
          print*,'Allowed iacceleration values 0,1,2,3'
          stop 'saha_solver.f'
      end if
      if(kkel .le. 0) then
          print*,'You have kkel=',kkel
          print*,'kkel must be greater than zero.'
          stop 'saha_solver.f'
      end if
!
      do410 : do k_index=1,kkel    
        aweight_1(k_index)=aweight(kel(k_index))
      end do do410
!
      sumel=sum(xel(:))   ! For normalization if that was not set initially.
      if(imassnumfrac .eq. 1) then    ! For mass fractions as input parameters.
          xnum(:)=rho*(xel(:)/sumel)/(aweight_1(:)*amu)
          xnum_total=sum(xnum(:))
        else                          ! For number fractions as input parameters.
          xnum_total=rho/sum( (xel(:)/sumel)*aweight_1(:)*amu )
          xnum(:)=xnum_total*(xel(:)/sumel)
      end if
!
      if(r_dilution .le. 0.0_np) then
         tem_use=tem
        else
         w_dilution=0.5_np*(1.0_np-sqrt(1.0_np-r_dilution**(-2)))  ! Mihalas-1978-120
         tem_use=tem*w_dilution**0.25_np
      end if
!
      tmp=func_phi(partfunc(0,1),partfunc(1,1),                          &
     &    1.0_np,xion_en,tem_use) 
! With ene=1.0_np, this is exactly ithe phi-tilde function (Mihalas-1978-113)
! tmp = 1/n_fiducial_electron_density_sort_of.
      if(ixne_initial .eq. 1) then
          xne_h=func_xne_h_analytic_exact(xnum_total*tmp)/tmp
           if(idiagnostic .ge. 1) then
              print*,'xne_h,xnum_total,tmp'
              write(*,'(1p,3e15.7)') xne_h,xnum_total,tmp
           end if
          xne=xne_h                      ! The hydrogen approximation.
!                                        !   I suspect it is usually an 
!                                        !   underestimate, but not by more
!                                        !   than a factor of 100 for large ionization
!                                        !   since atoms can at most yield about 100 electons each.
!                                        !   For low ionization, since H has a relatively
!                                        !   1st ionization, it might also be low often.
!                                        !   But it is exactly right in the limit of
!                                        !   pure hydrogen (with no H-).
        else if(ixne_initial .eq. 2) then
          if(xne .lt. -xprecision) then
              print*,'For ixne_initial=2 you need xne > = 0'
              print*,'Your input value is xne= ',xne
              stop 'saha_solver.f'
          end if
        else 
         xne=x_reduced/tmp
         xnum_total=xx_reduced/tmp
         xnum(1)=xnum_total
         if(kkel .ne. 1  .or. kel(1) .ne. 1                                &
     &    .or. ih_minus_not .ne. 1                                         &
     &    .or. abs(kel(1)-1.0_np) .gt. xprecision) then
            print*,'This must be a pure hydrogen case'
            print*,'(no H-) since it is for testing.'
            print*,'So one of the following has a wrong value.'
           print*,'kkel,kel(1),ih_minus_not,kel(1)'
           print*,kkel,kel(1),ih_minus_not,kel(1)
           stop 'saha_solver.f'
         end if
      end if
!
      if(idiagnostic .ge. 1) then
        write(*,'(a)') 'The Saha solution for:'
        write(*,fmt=930) iacceleration,rho,tem_use,xne
  930   format('iacceleration=',i5,1p,' rho=',e15.7,                        &
     &    ' T=',e15.7,' xne_initial=',e15.7)
        write(*,*) 'kel(:)',kel(:)
        write(*,*) 'xel(:)',xel(:)
        write(*,fmt=940)
      end if
!
      iter=0
      pair(:,:)=0.0_np
      do510 : do
        iter=iter+1
        xne_out=0.0_np
        do520 : do k_index=1,kkel
          k_atom=kel(k_index)
          if(k_atom .gt. 1  .or.  ih_minus_not .eq. 0) then
              jmin=jel_ion(1,k_atom)
            else
              jmin=0  ! The case where H- is excluded. 
          end if
          jmax=jel_ion(2,k_atom)
          do530 : do j=jmin,jmax-1         
             phi_j=func_phi(partfunc(j,k_atom),partfunc(j+1,k_atom),         &
     &                      xne,xion_en(j,k_atom),tem_use)
!               The phi_j functions always grow with j (I think).
!               The higher the ionization stage, the higher the ionization energy.
!               So if very low ionization, phi_j grows from the start and jfid=jmin.
!               If the very high ionization, then jmax becomes jfid, since N_j/N_j+1
!               is infinite.
             if(phi_j .ge. 1.0_np) exit do530
          end do do530 
          jfid=j     ! MRC-61 confirms this should be j of exit or j=(jmax-1)+1=jmax for normal leave.
!
          fraction(jfid,k_index)=1.0_np   ! The fraction is normalized below.
          xne_j=jfid                      ! The unnormalzed contribution of j=jfid is jfid. 
          product=1.0_np/partfunc(jfid,k_atom)
          do540 : do j=jfid-1,jmin,-1     ! No execution if jfid=jmin
            product=product                                                  &
     &        *func_phi_r(xne,xion_en(j,k_atom),tem_use)
            if(product .lt. xprecision) then
                fraction(jmin:j,k_index)=0.0_np    ! These cannot contribute relative to 1
!                                                  !   and underflows are uncertain (MRC-225).
                exit do540
            end if 
            fraction(j,k_index)=partfunc(j,k_atom)*product
            xne_j=xne_j+real(j,kind=np)*fraction(j,k_index)   ! Mihalas-1978-114--115
          end do do540
!
          product=1.0_np/partfunc(jfid,k_atom)
          do550 : do j=jfid+1,jmax,1       ! No execution is jfid=jmax
            product=product                                                   &
     &        *func_phi_r_inverse(xne,xion_en(j,k_atom),tem_use)
            if(product .lt. xprecision) then
                fraction(j:jmax,k_index)=0.0_np    ! These cannot contribute relative to 1
!                                                  !   and underflows are uncertain (MRC-225).
                exit do550
            end if
            fraction(j,k_index)=partfunc(j,k_atom)*product
            xne_j=xne_j+real(j,kind=np)*fraction(j,k_index)   ! Mihalas-1978-114--115.
          end do do550 
          denom=sum(fraction(jmin:jmax,k_index))  ! What order of summation in sum?
!                                                 !   One should add from smallest
!                                                 !   to largest for each sign first.
!                                                 !   It may be too finicky to worry
!                                                 !   About question in this procedure. 
          if(k_atom .eq. 6) then
              write(*,"('frac',7e15.7)") fraction(jmin:jmax,k_index)
          end if
          fraction(:,k_index)=fraction(:,k_index)/denom
          if(k_atom .eq. 6) then
              write(*,"('frac',7e15.7)") fraction(jmin:jmax,k_index)
          end if
          xne_out=xne_out+xnum(k_index)*xne_j/denom
        end do do520
!
!        print*,xne,xne_out
        relerr=(xne_out-xne)/xne
        if(abs(relerr) .le. xne_converged  .or.                           &
     &     abs(sum(fraction(0,1:kkel))/real(kkel,kind=np)-1.0_np)         &
     &     .le. xprecision) then
            xne_atom_ratio=xne_out/xnum_total
            if(idiagnostic .ge. 1) then
                write(*,fmt=942) iter,xne,xne_out,0.0_np,relerr,          &
     &                                xne_atom_ratio 
                if(kel(1) .eq. 6) then
                   print*,'fraction(3,6),denom'
                   print*,fraction(3,6),denom
                   write(*,"('frac',7e15.7)")                             &
     &               fraction(0:6,1)
                end if 
            end if
            xne=xne_out   ! Convergence achieved.
            exit do510
        end if
        pair(:,1)=pair(:,2)
        pair(:,2)=pair(:,3)
        pair(1,3)=xne
        pair(2,3)=xne_out
        call xne_acceleration(iacceleration,iter,                         &
     &                 pair,xne,xne_out,                                  &
     &                 xne_min,xne_max,xne_mid,xne_L,xne_q,xne_accel)
        if(idiagnostic .eq. 2) then
           write(*,fmt=942) iter,xne,xne_out,xne_accel,relerr,            &
     &                      xne_accel/xnum_total
           if(iter .eq. 50) then
               print*,'The iteration failing iter=500'
               return
           end if 
        end if
        xne=xne_accel   ! This must come after the idiagnostic printout.
      end do do510
!
  940 format(' iter',12x,'xne',8x,'xne_out',6x,'xne_accel',9x,'relerr',   &
     &       5x,'Ionization')
  942 format(i5,1p,5e15.7)
!
      end subroutine saha_solver
!23456789a123456789b123456789c123456789d123456789e123456789f123456789g12