!
!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