From 59788944f212b209c285b792afd2daef3eca2dad Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 3 Oct 2023 11:18:57 +0200 Subject: [PATCH 01/46] first commit of dust + atom transfer --- src/dust_transfer.f90 | 2 ++ src/parameters.f90 | 1 + src/read_spherical_grid.f90 | 41 +++++++++++++++++++++++++++++-------- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/dust_transfer.f90 b/src/dust_transfer.f90 index b378287a7..aa4fee60a 100644 --- a/src/dust_transfer.f90 +++ b/src/dust_transfer.f90 @@ -246,6 +246,8 @@ subroutine transfert_poussiere() else etape_i=2 letape_th=.false. +!B. Tessore: !i ltemp == False (don't compute T) but we don't have dust so we don't want to read dust T +!or dust T is in the model, we need to leave here if (.not.(ldust_prop.and.lstop_after_init)) then ! we do not need the temperature if we only compute the dust prop call lect_Temperature() endif diff --git a/src/parameters.f90 b/src/parameters.f90 index 3a6bb054b..8305898d2 100644 --- a/src/parameters.f90 +++ b/src/parameters.f90 @@ -55,6 +55,7 @@ module parametres character(len=512) :: tab_wavelength !gas transfer here + logical :: ldust_gas ! Emission moleculaire logical :: lemission_mol, lpop, lprecise_pop, lmol_LTE, ldust_mol, lonly_top, lonly_bottom diff --git a/src/read_spherical_grid.f90 b/src/read_spherical_grid.f90 index 4e02d42eb..eb72fefd7 100644 --- a/src/read_spherical_grid.f90 +++ b/src/read_spherical_grid.f90 @@ -13,6 +13,7 @@ module read_spherical_grid use messages use utils use cylindrical_grid + use density use stars, only : T_hp, T_preshock use read1d_models, only : print_info_model @@ -122,15 +123,6 @@ subroutine read_spherical_grid_parameters(filename) return endsubroutine read_spherical_grid_parameters - !building (cleaner version) - subroutine accomodate_spherical_grid() - !redifine the limits of the spherical grid - !to match the limits read with read_spherical_grid_parameters - - return - end subroutine accomodate_spherical_grid - - subroutine read_spherical_model(filename) ! ----------------------------------------------------- ! ! read spherical grid data defined at cell centres. @@ -142,6 +134,7 @@ subroutine read_spherical_model(filename) integer, allocatable :: dz(:,:,:) real, allocatable :: vtmp(:,:,:,:) real(kind=dp), allocatable :: rho(:,:,:), T_tmp(:,:,:), ne_tmp(:,:,:), vt_tmp(:,:,:) + real(kind=dp) :: mass, facteur call alloc_atomrt_grid call read_abundance !can be move in atom_transfer, but then rho must be changed in nHtot @@ -185,6 +178,10 @@ subroutine read_spherical_model(filename) icell = cell_map(i,jj,k) T(icell) = T_tmp(i,j,k) nHtot(icell) = rho(i,j,k) * 1d3 / masseH / wght_per_H + densite_gaz(icell) = rho(i,j,k) * 1d3 !for dust, in [g] + !At the moment the dust density / properties / g/d ratio are + !set from the parameter file and not read from the binary model. + densite_pouss(:,icell) = densite_gaz(icell) icompute_atomRT(icell) = dz(i,j,k) vfield3d(icell,:) = vtmp(i,j,k,:) enddo @@ -192,6 +189,32 @@ subroutine read_spherical_model(filename) enddo deallocate(rho,ne_tmp,T_tmp,vt_tmp,dz,vtmp) + !dust part see read_pluto.f90 + ! ********************************** ! + mass = 0. !in g/m^3, volume in AU^3 + do icell=1,n_cells + mass = mass + densite_gaz(icell) * volume(icell) + enddo !icell + mass = mass * AU3_to_m3 * g_to_Msun !in Msun + + ! Normalisation + if (mass > 0.0) then ! pour le cas ou gas_to_dust = 0. + facteur = disk_zone(1)%diskmass * disk_zone(1)%gas_to_dust / mass + + ! Somme sur les zones pour densite finale + do icell=1,n_cells + densite_gaz(icell) = 1d-3 * densite_gaz(icell) * facteur !g/AU^3 + masse_gaz(icell) = densite_gaz(icell) * volume(icell) * AU3_to_m3 !g + nHtot(icell) = nHtot(icell) * facteur !for consistency + enddo ! icell + else + call error('Gas mass is 0') + endif + + write(*,*) 'Total gas mass in model:', real(sum(masse_gaz) * g_to_Msun),' Msun' + call normalize_dust_density() + ! ********************************** ! + call check_for_zero_electronic_density() call print_info_model() From 9108283f9ade4c3eeb65f387c3b6ca800f5b28de Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Thu, 5 Oct 2023 11:46:52 +0200 Subject: [PATCH 02/46] handling cases with very low to zero LTE populations --- src/gas/atom_type.f90 | 1 + src/gas/collision_atom.f90 | 3 +- src/gas/io_atom.f90 | 2 + src/gas/lte.f90 | 78 ++++++++++++++++++++++++-------------- src/gas/opacity_atom.f90 | 9 +++-- src/gas/see.f90 | 3 +- 6 files changed, 63 insertions(+), 33 deletions(-) diff --git a/src/gas/atom_type.f90 b/src/gas/atom_type.f90 index e2161b3e3..eeaff140a 100644 --- a/src/gas/atom_type.f90 +++ b/src/gas/atom_type.f90 @@ -87,6 +87,7 @@ module atom_type logical :: NLTEpops, set_ltepops real(kind=dp), allocatable :: Gamma(:,:,:), dgdne(:,:,:) !derivative of Gamma to ne (n_iterate_ne>0) real(kind=dp), dimension(:,:), pointer :: n, nstar + real(kind=dp), dimension(:,:), allocatable :: ni_on_nj_star ! real(kind=dp), dimension(:,:) :: phi_T !such that nexphi_T = ni/nj type (AtomicLine), allocatable, dimension(:) :: lines type (AtomicContinuum) , allocatable, dimension(:) :: continua diff --git a/src/gas/collision_atom.f90 b/src/gas/collision_atom.f90 index 26ca38fbb..fd53c83f5 100644 --- a/src/gas/collision_atom.f90 +++ b/src/gas/collision_atom.f90 @@ -38,7 +38,8 @@ subroutine collision_rates_hydrogen_loc(id,icell) j = hydrogen%Nlevel do i=1, j-1 !ni_on_nj_star = ne(icell) * phi_T(icell, hydrogen%g(i)/hydrogen%g(hydrogen%Nlevel), hydrogen%E(hydrogen%Nlevel)-hydrogen%E(i)) - ni_on_nj_star = hydrogen%nstar(i,icell) / hydrogen%nstar(j,icell) + ! ni_on_nj_star = hydrogen%nstar(i,icell) / hydrogen%nstar(j,icell) + ni_on_nj_star = hydrogen%ni_on_nj_star(i,icell) kr = hydrogen%ij_to_trans(i,j) - hydrogen%Nline hydrogen%continua(kr)%Cij(id) = ne(icell) * CI(i) !deriv = Cij/ne hydrogen%continua(kr)%Cji(id) = ne(icell) * CI(i) * ni_on_nj_star !deriv = 2*Cji/ne diff --git a/src/gas/io_atom.f90 b/src/gas/io_atom.f90 index 2eebd20e1..54cd03c85 100644 --- a/src/gas/io_atom.f90 +++ b/src/gas/io_atom.f90 @@ -107,6 +107,8 @@ subroutine read_model_atom(atomunit, atom) allocate(parse_labs(atom%Nlevel)) !atomic level's population at LTE (n^*) allocate(atom%nstar(atom%Nlevel,n_cells)) + allocate(atom%ni_on_nj_star(atom%Nlevel-1,n_cells)); atom%ni_on_nj_star = 0.0_dp + write(*,*) "size ni*/nj*=", sizeof(atom%ni_on_nj_star)/1024.**3, " GB" !total number of transitions for this model atom%Ntr = atom%Nline + atom%Ncont !-> to remove tab_trans ?? diff --git a/src/gas/lte.f90 b/src/gas/lte.f90 index 146073755..77a6cfac1 100644 --- a/src/gas/lte.f90 +++ b/src/gas/lte.f90 @@ -16,6 +16,7 @@ module lte implicit none integer, dimension(101) :: ndebye + real(kind=dp), parameter :: nsmall = 1.0! [m^-3], small LTE populations are replaced by this. contains @@ -147,7 +148,7 @@ subroutine LTEpops_H_loc (k) hydrogen%nstar(1,k) = hydrogen%Abund*nHtot(k)/sum !test positivity, can be 0 - if ((hydrogen%nstar(1,k) < 0)) then !<= tiny_dp) then + if ((hydrogen%nstar(1,k) < tiny_dp)) then write(*,*) " ************************************* " write(*,*) "Warning too small gs pop", hydrogen%ID, hydrogen%nstar(i,k) write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) @@ -158,18 +159,19 @@ subroutine LTEpops_H_loc (k) do i=2,hydrogen%Nlevel !debug hydrogen%nstar(i,k) = hydrogen%nstar(i,k)*hydrogen%nstar(1,k) - if (hydrogen%nstar(i,k) < 0) then !<= tiny_dp) then - write(*,*) " ************************************* " - write(*,*) "Warning population of hydrogen ", hydrogen%ID, "lvl=", i, "nstar=",hydrogen%nstar(i,k), " lower than", & - " tiny_dp." - write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & - " n0=", hydrogen%nstar(1,k) - write(*,*) " ************************************* " - stop + if (hydrogen%nstar(i,k) < tiny_dp) then + !--> debug + ! write(*,*) " ************************************* " + ! write(*,*) "Warning population of hydrogen ", hydrogen%ID, "lvl=", i, "nstar=",hydrogen%nstar(i,k), " lower than", & + ! " tiny_dp." + ! write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & + ! " n0=", hydrogen%nstar(1,k) + ! write(*,*) " ************************************* " + hydrogen%nstar(i,k) = nsmall end if end do - if (maxval(hydrogen%nstar(:,k)) >= huge_dp) then + if (maxval(hydrogen%nstar(:,k)) > huge_dp) then write(*,*) " ************************************* " write(*,*) "ERROR, populations of hydrogen larger than huge_dp" write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) @@ -189,6 +191,16 @@ subroutine LTEpops_H_loc (k) hydrogen%nstar(1,k) = hydrogen%nstar(1,k) * wocc endif + !Set ni/nj ratio for continuum transitions in case ne-> 0 and nj ->0 + !should be ok for lines (the ratio for lines is used only in the collision) + do i=1, hydrogen%Ncont + if (hydrogen%nstar(hydrogen%continua(i)%j,k)>nsmall) then + hydrogen%ni_on_nj_star(hydrogen%continua(i)%i,k) = & + hydrogen%nstar(hydrogen%continua(i)%i,k)/hydrogen%nstar(hydrogen%continua(i)%j,k) + else + hydrogen%ni_on_nj_star(hydrogen%continua(i)%i,k) = 0.0 + endif + enddo return end subroutine LTEpops_H_loc @@ -294,28 +306,28 @@ subroutine LTEpops_atom_loc(k,atom,debye) atom%nstar(1,k) = atom%Abund*nHtot(k)/sum !test positivity, can be 0 - if (atom%nstar(1,k) < 0) then !<= tiny_dp) then + if (atom%nstar(1,k) < tiny_dp) then write(*,*) " ************************************* " write(*,*) "Warning too small ground state population ", atom%ID, "n0=", atom%nstar(1,k) write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) - !atom%nstar(1,k) = tiny_dp write(*,*) " ************************************* " - stop !only if we test >= 0 + stop end if do i=2,atom%Nlevel !debug atom%nstar(i,k) = atom%nstar(i,k)*atom%nstar(1,k) - if (atom%nstar(i,k) < 0) then !<= tiny_dp) then - write(*,*) " ************************************* " - write(*,*) "Warning population of atom ", atom%ID, "lvl=", i, "nstar=",atom%nstar(i,k), " lower than", & - " tiny_dp."! Replacing by tiny_dp" - write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & - " n0=", atom%nstar(1,k) - write(*,*) " ************************************* " - stop + if (atom%nstar(i,k) < tiny_dp) then + !--> debug + ! write(*,*) " ************************************* " + ! write(*,*) "Warning population of atom ", atom%ID, "lvl=", i, "nstar=",atom%nstar(i,k), " lower than", & + ! " tiny_dp." + ! write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & + ! " n0=", atom%nstar(1,k) + ! write(*,*) " ************************************* " + atom%nstar(i,k) = nsmall end if end do - if (maxval(atom%nstar(:,k)) >= huge_dp) then + if (maxval(atom%nstar(:,k)) > huge_dp) then write(*,*) " ************************************* " write(*,*) "ERROR, populations of atom larger than huge_dp" write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) @@ -337,6 +349,16 @@ subroutine LTEpops_atom_loc(k,atom,debye) enddo endif + !Set ni/nj ratio for continuum transitions in case ne-> 0 and nj ->0 + !should be ok for lines (the ratio for lines is used only in the collision) + do i=1, atom%Ncont + if (atom%nstar(atom%continua(i)%j,k)>nsmall) then + atom%ni_on_nj_star(atom%continua(i)%i,k) = atom%nstar(atom%continua(i)%i,k)/atom%nstar(atom%continua(i)%j,k) + else + atom%ni_on_nj_star(atom%continua(i)%i,k) = 0.0 + endif + enddo + return end subroutine LTEpops_atom_loc @@ -478,7 +500,7 @@ subroutine LTEpops_H() hydrogen%nstar(1,k) = hydrogen%Abund*nHtot(k)/sum !test positivity, can be 0 - if ((hydrogen%nstar(1,k) < 0)) then !<= tiny_dp) then + if ((hydrogen%nstar(1,k) < tiny_dp)) then write(*,*) " ************************************* " write(*,*) "Warning too small gs pop", hydrogen%ID, hydrogen%nstar(i,k) write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) @@ -489,7 +511,7 @@ subroutine LTEpops_H() do i=2,hydrogen%Nlevel !debug hydrogen%nstar(i,k) = hydrogen%nstar(i,k)*hydrogen%nstar(1,k) - if (hydrogen%nstar(i,k) < 0) then !<= tiny_dp) then + if (hydrogen%nstar(i,k) < tiny_dp) then write(*,*) " ************************************* " write(*,*) "Warning population of hydrogen ", hydrogen%ID, "lvl=", i, "nstar=",hydrogen%nstar(i,k), & " lower than tiny_dp." @@ -500,7 +522,7 @@ subroutine LTEpops_H() end if end do - if (maxval(hydrogen%nstar(:,k)) >= huge_dp) then + if (maxval(hydrogen%nstar(:,k)) > huge_dp) then write(*,*) " ************************************* " write(*,*) "ERROR, populations of hydrogen larger than huge_dp" write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) @@ -674,7 +696,7 @@ subroutine LTEpops_atom(atom, debye) atom%nstar(1,k) = atom%Abund*nHtot(k)/sum !test positivity, can be 0 - if (atom%nstar(1,k) < 0) then !<= tiny_dp) then + if (atom%nstar(1,k) < tiny_dp) then write(*,*) " ************************************* " write(*,*) "Warning too small ground state population ", atom%ID, "n0=", atom%nstar(1,k) write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) @@ -684,7 +706,7 @@ subroutine LTEpops_atom(atom, debye) end if do i=2,atom%Nlevel !debug atom%nstar(i,k) = atom%nstar(i,k)*atom%nstar(1,k) - if (atom%nstar(i,k) < 0) then !<= tiny_dp) then + if (atom%nstar(i,k) < tiny_dp) then write(*,*) " ************************************* " write(*,*) "Warning population of atom ", atom%ID, "lvl=", i, "nstar=",atom%nstar(i,k), " lower than", & " tiny_dp."! Replacing by tiny_dp" @@ -695,7 +717,7 @@ subroutine LTEpops_atom(atom, debye) end if end do - if (maxval(atom%nstar(:,k)) >= huge_dp) then + if (maxval(atom%nstar(:,k)) > huge_dp) then write(*,*) " ************************************* " write(*,*) "ERROR, populations of atom larger than huge_dp" write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) diff --git a/src/gas/opacity_atom.f90 b/src/gas/opacity_atom.f90 index f0db9b5ba..97bc33f44 100644 --- a/src/gas/opacity_atom.f90 +++ b/src/gas/opacity_atom.f90 @@ -421,7 +421,8 @@ subroutine opacity_atom_bf_loc(icell,N,lambda,chi,Snu) Nred = atom%continua(kr)%Nrc; Nblue = atom%continua(kr)%Nbc i = atom%continua(kr)%i; j = atom%continua(kr)%j !ni_on_nj_star = ne(icell) * phi_T(icell, at%g(i)/at%g(j), at%E(j)-at%E(i)) - ni_on_nj_star = atom%nstar(i,icell)/(atom%nstar(j,icell) + 1d-100) + ! ni_on_nj_star = atom%nstar(i,icell)/atom%nstar(j,icell) + ni_on_nj_star = atom%ni_on_nj_star(i,icell) gij = ni_on_nj_star * exp(-hc_k/T(icell)/atom%continua(kr)%lambda0) if ((atom%n(i,icell) - atom%n(j,icell) * gij) <= 0.0_dp) then @@ -657,7 +658,8 @@ subroutine cross_coupling_cont(id,icell,at) Nl = Nr-Nb+1 !ni_on_nj_star = ne(icell) * phi_T(icell, at%g(i)/at%g(j), at%E(j)-at%E(i)) - ni_on_nj_star = at%nstar(i,icell)/(at%nstar(j,icell) + 1d-100) + ! ni_on_nj_star = at%nstar(i,icell)/at%nstar(j,icell) + ni_on_nj_star = at%ni_on_nj_star(i,icell) gij_0 = ni_on_nj_star * exp(-hc_k/T(icell)/at%continua(kr)%lambda0) @@ -721,7 +723,8 @@ subroutine cross_coupling_cont_i(id,icell,at) N1 = at%continua(kr)%Nb; N2 = at%continua(kr)%Nr !ni_on_nj_star = ne(icell) * phi_T(icell, at%g(i)/at%g(j), at%E(j)-at%E(i)) - ni_on_nj_star = at%nstar(i,icell)/(at%nstar(j,icell) + 1d-100) + ! ni_on_nj_star = at%nstar(i,icell)/at%nstar(j,icell) + ni_on_nj_star = at%ni_on_nj_star(i,icell) gij = ni_on_nj_star * exp(-hc_k/T(icell)/at%continua(kr)%lambda0) diff --git a/src/gas/see.f90 b/src/gas/see.f90 index 8a7defd2b..b99849aea 100644 --- a/src/gas/see.f90 +++ b/src/gas/see.f90 @@ -634,7 +634,8 @@ subroutine accumulate_radrates_mali(id, icell, iray, domega) i = atom%continua(kr)%i; j = atom%continua(kr)%j !ni_on_nj_star = ne(icell) * phi_T(icell, aatom%g(i)/aatom%g(j), aatom%E(j)-aatom%E(i)) - ni_on_nj_star = atom%nstar(i,icell)/atom%nstar(j,icell) + ! ni_on_nj_star = atom%nstar(i,icell)/atom%nstar(j,icell) + ni_on_nj_star = atom%ni_on_nj_star(i,icell) gij = ni_on_nj_star * exp(-hc_k/T(icell)/atom%continua(kr)%lambda0) if ((atom%n(i,icell) - atom%n(j,icell) * gij) <= 0.0_dp) cycle cont_loop From f1e6881a5313d2262850637a49a550b1ea264e09 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Thu, 5 Oct 2023 12:04:57 +0200 Subject: [PATCH 03/46] introduced a phi_T function to compute ni*/nj* on the fly, handling 0 electronic density. --- src/gas/collision_atom.f90 | 2 +- src/gas/elements_type.f90 | 18 ++++++++++++++---- src/gas/opacity_atom.f90 | 7 ++++--- src/gas/see.f90 | 2 +- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/gas/collision_atom.f90 b/src/gas/collision_atom.f90 index fd53c83f5..49e162afd 100644 --- a/src/gas/collision_atom.f90 +++ b/src/gas/collision_atom.f90 @@ -37,7 +37,7 @@ subroutine collision_rates_hydrogen_loc(id,icell) call Johnson_CI(icell, CI) !bound-free i->Nlevel j = hydrogen%Nlevel do i=1, j-1 - !ni_on_nj_star = ne(icell) * phi_T(icell, hydrogen%g(i)/hydrogen%g(hydrogen%Nlevel), hydrogen%E(hydrogen%Nlevel)-hydrogen%E(i)) + ! ni_on_nj_star = ne(icell) * phi_T(T(icell), hydrogen%g(i), hydrogen%g(j), hydrogen%E(j)-hydrogen%E(i)) ! ni_on_nj_star = hydrogen%nstar(i,icell) / hydrogen%nstar(j,icell) ni_on_nj_star = hydrogen%ni_on_nj_star(i,icell) kr = hydrogen%ij_to_trans(i,j) - hydrogen%Nline diff --git a/src/gas/elements_type.f90 b/src/gas/elements_type.f90 index fcf347f5a..4f3b11404 100644 --- a/src/gas/elements_type.f90 +++ b/src/gas/elements_type.f90 @@ -43,6 +43,7 @@ module elements_type real(kind=dp), parameter :: phi_min_limit = 1d-100!tiny_dp!1d-100 !1d-50, tiny_dp integer :: Max_ionisation_stage + real(kind=dp), parameter :: CI = 0.5*(HP**2 / (2.*PI*mel*kb))**1.5 ! Atomic properties constants @@ -358,6 +359,17 @@ function get_pf(elem, j, temp) result (Uk) return end function get_pf + function phi_T(temp, gi, gj, dE)!Ui_on_Uj, + !Similar to phi_jl with less tests. + !Mainly here for on-fly calculations of ni*/nj* for continua which is + !also equal to ne * phi_T. This prevents divding by 0. + real(kind=dp) :: phi_T + real(kind=dp), intent(in) :: temp, dE, gi, gj!, Ui_on_Uj + + phi_T = gi/gj * CI * temp**(-1.5) * exp(dE / ( kb*temp ))!* Ui_on_Uj * + + return + end function phi_T function phi_jl(temp, Ujl, Uj1l, ionpot) ! -------------------------------------------------------------- ! @@ -376,10 +388,8 @@ function phi_jl(temp, Ujl, Uj1l, ionpot) ! -------------------------------------------------------------- ! real(kind=dp), intent(in) :: temp real(kind=dp) :: phi_jl - real(kind=dp) :: C1, expo + real(kind=dp) :: expo real(kind=dp), intent(in) :: Ujl, Uj1l, ionpot - C1 = 0.5*(HP**2 / (2.*PI*mel*kb))**1.5 - !C1 = (HPLANCK**2 / (2.*PI*M_ELECTRON*KBOLTZMANN))**1.5 !!ionpot = ionpot * 100.*HPLANCK*CLIGHT !cm1->J !! -> avoiding dividing by big numbers causing overflow. @@ -388,7 +398,7 @@ function phi_jl(temp, Ujl, Uj1l, ionpot) if (ionpot/(kb*temp) >= 600d0) expo = huge_dp !if exp(300) it means phi is "infinity", exp(300) == 2e130 so that's enough - phi_jl = C1 * (Ujl / Uj1l) * expo / (temp**1.5 + tiny_dp) + phi_jl = CI * (Ujl / Uj1l) * expo / (temp**1.5 + tiny_dp) if (phi_jl < phi_min_limit) phi_jl = 0d0 !tiny_dp ! or phi = 0d0 should be more correct ? ! but test to not divide by 0 diff --git a/src/gas/opacity_atom.f90 b/src/gas/opacity_atom.f90 index 97bc33f44..69a004877 100644 --- a/src/gas/opacity_atom.f90 +++ b/src/gas/opacity_atom.f90 @@ -7,6 +7,7 @@ module Opacity_atom use broad, Only : line_damping use voigts, only : voigt use occupation_probability, only : f_dissolve + use elements_type, only : phi_T use gas_contopac, only : H_bf_Xsection, alloc_gas_contopac, background_continua_lambda, & dealloc_gas_contopac, hnu_k use wavelengths, only : n_lambda @@ -420,7 +421,7 @@ subroutine opacity_atom_bf_loc(icell,N,lambda,chi,Snu) Nred = atom%continua(kr)%Nrc; Nblue = atom%continua(kr)%Nbc i = atom%continua(kr)%i; j = atom%continua(kr)%j - !ni_on_nj_star = ne(icell) * phi_T(icell, at%g(i)/at%g(j), at%E(j)-at%E(i)) + ! ni_on_nj_star = ne(icell) * phi_T(T(icell), atom%g(i), atom%g(j), atom%E(j)-atom%E(i)) ! ni_on_nj_star = atom%nstar(i,icell)/atom%nstar(j,icell) ni_on_nj_star = atom%ni_on_nj_star(i,icell) @@ -657,7 +658,7 @@ subroutine cross_coupling_cont(id,icell,at) Nb = at%continua(kr)%Nbc; Nr = at%continua(kr)%Nrc Nl = Nr-Nb+1 - !ni_on_nj_star = ne(icell) * phi_T(icell, at%g(i)/at%g(j), at%E(j)-at%E(i)) + ! ni_on_nj_star = ne(icell) * phi_T(T(icell), at%g(i), at%g(j), at%E(j)-at%E(i)) ! ni_on_nj_star = at%nstar(i,icell)/at%nstar(j,icell) ni_on_nj_star = at%ni_on_nj_star(i,icell) @@ -722,7 +723,7 @@ subroutine cross_coupling_cont_i(id,icell,at) Nl = Nr-Nb+1 N1 = at%continua(kr)%Nb; N2 = at%continua(kr)%Nr - !ni_on_nj_star = ne(icell) * phi_T(icell, at%g(i)/at%g(j), at%E(j)-at%E(i)) + ! ni_on_nj_star = ne(icell) * phi_T(T(icell), atom%g(i), atom%g(j), atom%E(j)-atom%E(i)) ! ni_on_nj_star = at%nstar(i,icell)/at%nstar(j,icell) ni_on_nj_star = at%ni_on_nj_star(i,icell) diff --git a/src/gas/see.f90 b/src/gas/see.f90 index b99849aea..e002ea8a1 100644 --- a/src/gas/see.f90 +++ b/src/gas/see.f90 @@ -633,7 +633,7 @@ subroutine accumulate_radrates_mali(id, icell, iray, domega) i = atom%continua(kr)%i; j = atom%continua(kr)%j - !ni_on_nj_star = ne(icell) * phi_T(icell, aatom%g(i)/aatom%g(j), aatom%E(j)-aatom%E(i)) + ! ni_on_nj_star = ne(icell) * phi_T(T(icell), atom%g(i), atom%g(j), atom%E(j)-atom%E(i)) ! ni_on_nj_star = atom%nstar(i,icell)/atom%nstar(j,icell) ni_on_nj_star = atom%ni_on_nj_star(i,icell) gij = ni_on_nj_star * exp(-hc_k/T(icell)/atom%continua(kr)%lambda0) From 7b66ab25cfebf6e97eafd5475a24449da6f775be Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Thu, 5 Oct 2023 14:08:07 +0200 Subject: [PATCH 04/46] minor fix --- src/gas/lte.f90 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gas/lte.f90 b/src/gas/lte.f90 index 77a6cfac1..d4748894c 100644 --- a/src/gas/lte.f90 +++ b/src/gas/lte.f90 @@ -148,7 +148,7 @@ subroutine LTEpops_H_loc (k) hydrogen%nstar(1,k) = hydrogen%Abund*nHtot(k)/sum !test positivity, can be 0 - if ((hydrogen%nstar(1,k) < tiny_dp)) then + if ((hydrogen%nstar(1,k) < nsmall)) then write(*,*) " ************************************* " write(*,*) "Warning too small gs pop", hydrogen%ID, hydrogen%nstar(i,k) write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) @@ -159,7 +159,7 @@ subroutine LTEpops_H_loc (k) do i=2,hydrogen%Nlevel !debug hydrogen%nstar(i,k) = hydrogen%nstar(i,k)*hydrogen%nstar(1,k) - if (hydrogen%nstar(i,k) < tiny_dp) then + if (hydrogen%nstar(i,k) < nsmall) then !--> debug ! write(*,*) " ************************************* " ! write(*,*) "Warning population of hydrogen ", hydrogen%ID, "lvl=", i, "nstar=",hydrogen%nstar(i,k), " lower than", & @@ -306,7 +306,7 @@ subroutine LTEpops_atom_loc(k,atom,debye) atom%nstar(1,k) = atom%Abund*nHtot(k)/sum !test positivity, can be 0 - if (atom%nstar(1,k) < tiny_dp) then + if (atom%nstar(1,k) < nsmall) then write(*,*) " ************************************* " write(*,*) "Warning too small ground state population ", atom%ID, "n0=", atom%nstar(1,k) write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) @@ -315,7 +315,7 @@ subroutine LTEpops_atom_loc(k,atom,debye) end if do i=2,atom%Nlevel !debug atom%nstar(i,k) = atom%nstar(i,k)*atom%nstar(1,k) - if (atom%nstar(i,k) < tiny_dp) then + if (atom%nstar(i,k) < nsmall) then !--> debug ! write(*,*) " ************************************* " ! write(*,*) "Warning population of atom ", atom%ID, "lvl=", i, "nstar=",atom%nstar(i,k), " lower than", & @@ -500,7 +500,7 @@ subroutine LTEpops_H() hydrogen%nstar(1,k) = hydrogen%Abund*nHtot(k)/sum !test positivity, can be 0 - if ((hydrogen%nstar(1,k) < tiny_dp)) then + if ((hydrogen%nstar(1,k) < nsmall)) then write(*,*) " ************************************* " write(*,*) "Warning too small gs pop", hydrogen%ID, hydrogen%nstar(i,k) write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) @@ -511,7 +511,7 @@ subroutine LTEpops_H() do i=2,hydrogen%Nlevel !debug hydrogen%nstar(i,k) = hydrogen%nstar(i,k)*hydrogen%nstar(1,k) - if (hydrogen%nstar(i,k) < tiny_dp) then + if (hydrogen%nstar(i,k) < nsmall) then write(*,*) " ************************************* " write(*,*) "Warning population of hydrogen ", hydrogen%ID, "lvl=", i, "nstar=",hydrogen%nstar(i,k), & " lower than tiny_dp." @@ -696,7 +696,7 @@ subroutine LTEpops_atom(atom, debye) atom%nstar(1,k) = atom%Abund*nHtot(k)/sum !test positivity, can be 0 - if (atom%nstar(1,k) < tiny_dp) then + if (atom%nstar(1,k) < nsmall) then write(*,*) " ************************************* " write(*,*) "Warning too small ground state population ", atom%ID, "n0=", atom%nstar(1,k) write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) @@ -706,7 +706,7 @@ subroutine LTEpops_atom(atom, debye) end if do i=2,atom%Nlevel !debug atom%nstar(i,k) = atom%nstar(i,k)*atom%nstar(1,k) - if (atom%nstar(i,k) < tiny_dp) then + if (atom%nstar(i,k) < nsmall) then write(*,*) " ************************************* " write(*,*) "Warning population of atom ", atom%ID, "lvl=", i, "nstar=",atom%nstar(i,k), " lower than", & " tiny_dp."! Replacing by tiny_dp" From cbc64a38496176952309056c1d815cf9f6cac672 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 10 Oct 2023 15:29:15 +0200 Subject: [PATCH 05/46] allowing for null LTE populations but checking positivity --- src/gas/lte.f90 | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/gas/lte.f90 b/src/gas/lte.f90 index d4748894c..7d64531b3 100644 --- a/src/gas/lte.f90 +++ b/src/gas/lte.f90 @@ -148,9 +148,9 @@ subroutine LTEpops_H_loc (k) hydrogen%nstar(1,k) = hydrogen%Abund*nHtot(k)/sum !test positivity, can be 0 - if ((hydrogen%nstar(1,k) < nsmall)) then + if ((hydrogen%nstar(1,k) < 0)) then write(*,*) " ************************************* " - write(*,*) "Warning too small gs pop", hydrogen%ID, hydrogen%nstar(i,k) + write(*,*) "error negative gs pop", hydrogen%ID, hydrogen%nstar(i,k) write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) write(*,*) " ************************************* " stop @@ -159,15 +159,15 @@ subroutine LTEpops_H_loc (k) do i=2,hydrogen%Nlevel !debug hydrogen%nstar(i,k) = hydrogen%nstar(i,k)*hydrogen%nstar(1,k) - if (hydrogen%nstar(i,k) < nsmall) then + if (hydrogen%nstar(i,k) < 0) then !--> debug - ! write(*,*) " ************************************* " - ! write(*,*) "Warning population of hydrogen ", hydrogen%ID, "lvl=", i, "nstar=",hydrogen%nstar(i,k), " lower than", & - ! " tiny_dp." - ! write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & - ! " n0=", hydrogen%nstar(1,k) - ! write(*,*) " ************************************* " - hydrogen%nstar(i,k) = nsmall + write(*,*) " ************************************* " + write(*,*) "Warning population of hydrogen ", hydrogen%ID, "lvl=", i, "nstar=",hydrogen%nstar(i,k), " negative!" + write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & + " n0=", hydrogen%nstar(1,k) + write(*,*) " ************************************* " + stop + ! hydrogen%nstar(i,k) = nsmall end if end do @@ -306,23 +306,23 @@ subroutine LTEpops_atom_loc(k,atom,debye) atom%nstar(1,k) = atom%Abund*nHtot(k)/sum !test positivity, can be 0 - if (atom%nstar(1,k) < nsmall) then + if (atom%nstar(1,k) < 0) then write(*,*) " ************************************* " - write(*,*) "Warning too small ground state population ", atom%ID, "n0=", atom%nstar(1,k) + write(*,*) "Error negative ground state population ", atom%ID, "n0=", atom%nstar(1,k) write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) write(*,*) " ************************************* " stop end if do i=2,atom%Nlevel !debug atom%nstar(i,k) = atom%nstar(i,k)*atom%nstar(1,k) - if (atom%nstar(i,k) < nsmall) then + if (atom%nstar(i,k) < 0) then !--> debug - ! write(*,*) " ************************************* " - ! write(*,*) "Warning population of atom ", atom%ID, "lvl=", i, "nstar=",atom%nstar(i,k), " lower than", & - ! " tiny_dp." - ! write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & - ! " n0=", atom%nstar(1,k) - ! write(*,*) " ************************************* " + write(*,*) " ************************************* " + write(*,*) "Warning population of atom ", atom%ID, "lvl=", i, "nstar=",atom%nstar(i,k), " negative !" + write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & + " n0=", atom%nstar(1,k) + write(*,*) " ************************************* " + stop atom%nstar(i,k) = nsmall end if end do From 425aa2057488af06fe87fb415cbbf8f78f3743ee Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Thu, 12 Oct 2023 11:32:45 +0200 Subject: [PATCH 06/46] handling low LTE populations --- src/gas/atom_transfer.f90 | 2 +- src/gas/lte.f90 | 58 +++++++++++++++++++++++---------------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index c7c823b9b..d14a1cce8 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -16,7 +16,7 @@ module atom_transfer use elecdensity, only : solve_ne, write_electron, read_electron use grid, only : T, vturb,nHtot, nHmin, pos_em_cellule, lcalc_ne, move_to_grid, vfield3d, icompute_atomRT, & ne, Voronoi, r_grid, phi_grid, z_grid - use lte, only : ltepops_atoms, ltepops_atoms_1, print_pops, LTEpops_atom_loc, LTEpops_H_loc, nH_minus + use lte, only : ltepops_atoms, LTEpops_atom_loc, LTEpops_H_loc, nH_minus use atom_type, only : atoms, atomtype, n_atoms, nactiveatoms, activeAtoms, passiveAtoms, npassiveatoms, & hydrogen, helium, adjust_cswitch_atoms, & maxval_cswitch_atoms, lcswitch_enabled, vbroad diff --git a/src/gas/lte.f90 b/src/gas/lte.f90 index 7d64531b3..30c94c5a8 100644 --- a/src/gas/lte.f90 +++ b/src/gas/lte.f90 @@ -155,20 +155,21 @@ subroutine LTEpops_H_loc (k) write(*,*) " ************************************* " stop end if + if (hydrogen%nstar(1,k) < nsmall) hydrogen%nstar(1,k) = nsmall do i=2,hydrogen%Nlevel !debug - hydrogen%nstar(i,k) = hydrogen%nstar(i,k)*hydrogen%nstar(1,k) - - if (hydrogen%nstar(i,k) < 0) then - !--> debug - write(*,*) " ************************************* " - write(*,*) "Warning population of hydrogen ", hydrogen%ID, "lvl=", i, "nstar=",hydrogen%nstar(i,k), " negative!" - write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & - " n0=", hydrogen%nstar(1,k) - write(*,*) " ************************************* " - stop - ! hydrogen%nstar(i,k) = nsmall - end if + hydrogen%nstar(i,k) = max(hydrogen%nstar(i,k)*hydrogen%nstar(1,k), nsmall) + + ! if (hydrogen%nstar(i,k) < 0) then + ! !--> debug + ! write(*,*) " ************************************* " + ! write(*,*) "Warning population of hydrogen ", hydrogen%ID, "lvl=", i, "nstar=",hydrogen%nstar(i,k), " negative!" + ! write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & + ! " n0=", hydrogen%nstar(1,k) + ! write(*,*) " ************************************* " + ! stop + ! end if + ! if (hydrogen%nstar(i,k) < nsmall) hydrogen%nstar(i,k) = nsmall end do if (maxval(hydrogen%nstar(:,k)) > huge_dp) then @@ -305,7 +306,7 @@ subroutine LTEpops_atom_loc(k,atom,debye) ! write(*,*) "ntot", ntotal_atom(k,atom), " nHtot=",nHtot(k) atom%nstar(1,k) = atom%Abund*nHtot(k)/sum - !test positivity, can be 0 + !test positivity, can be 0 if (atom%nstar(1,k) < 0) then write(*,*) " ************************************* " write(*,*) "Error negative ground state population ", atom%ID, "n0=", atom%nstar(1,k) @@ -313,18 +314,21 @@ subroutine LTEpops_atom_loc(k,atom,debye) write(*,*) " ************************************* " stop end if + if (atom%nstar(1,k) < nsmall) atom%nstar(1,k) = nsmall + do i=2,atom%Nlevel !debug - atom%nstar(i,k) = atom%nstar(i,k)*atom%nstar(1,k) - if (atom%nstar(i,k) < 0) then - !--> debug - write(*,*) " ************************************* " - write(*,*) "Warning population of atom ", atom%ID, "lvl=", i, "nstar=",atom%nstar(i,k), " negative !" - write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & - " n0=", atom%nstar(1,k) - write(*,*) " ************************************* " - stop - atom%nstar(i,k) = nsmall - end if + atom%nstar(i,k) = max(atom%nstar(i,k)*atom%nstar(1,k), nsmall) + ! if (atom%nstar(i,k) < 0) then + ! !--> debug + ! write(*,*) " ************************************* " + ! write(*,*) "Warning population of atom ", atom%ID, "lvl=", i, "nstar=",atom%nstar(i,k), " negative !" + ! write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & + ! " n0=", atom%nstar(1,k) + ! write(*,*) " ************************************* " + ! stop + ! atom%nstar(i,k) = nsmall + ! end if + ! if (atom%nstar(i,k) < nsmall) atom%nstar(i,k) = nsmall end do if (maxval(atom%nstar(:,k)) > huge_dp) then @@ -422,6 +426,8 @@ subroutine ltepops_atoms return end subroutine ltepops_atoms +!-> TO DO: need to handle very low populations + atom%ni_on_nj_star +!-> not used subroutine LTEpops_H() ! -------------------------------------------------------------- ! ! computed wrt the ground state of H I @@ -575,6 +581,8 @@ subroutine LTEpops_H() return end subroutine LTEpops_H +!-> TO DO: need to handle very low populations + atom%ni_on_nj_star +!-> not used subroutine LTEpops_atom(atom, debye) ! -------------------------------------------------------------- ! ! Computes LTE populations of each level of the atom. @@ -762,6 +770,8 @@ subroutine LTEpops_atom(atom, debye) return end subroutine LTEpops_atom +!-> TO DO: need to handle very low populations + atom%ni_on_nj_star +!-> not used subroutine ltepops_atoms_1 () ! -------------------------------------------------------------- ! ! Computes LTE populations for each atom From 16040e4e975779d40cea923db774a597b6d4319e Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Fri, 20 Oct 2023 08:30:19 +0200 Subject: [PATCH 07/46] reducing threshold to force convergence --- src/gas/atom_transfer.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index d14a1cce8..f00c30630 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -480,7 +480,7 @@ subroutine nlte_loop_mali() endif endif if (lng_turned_on) then - if (unconverged_fraction < 15.0) lng_turned_on = .false. + if (unconverged_fraction < 10.0) lng_turned_on = .false. endif endif !***********************************************************! @@ -783,8 +783,8 @@ subroutine nlte_loop_mali() !force convergence if there are only few unconverged cells remaining ! if ((n_iter > maxIter/4).and.(unconverged_fraction < 5.0)) then - if ( (n_iter > maxIter/4).and.(unconverged_fraction < 5.0).or.& - ((unconverged_fraction < 5.0).and.(time_nlte + time_iteration >= 0.5*safe_stop_time)) ) then + if ( (n_iter > maxIter/4).and.(unconverged_fraction < 3.0).or.& + ((unconverged_fraction < 3.0).and.(time_nlte + time_iteration >= 0.5*safe_stop_time)) ) then write(*,'("WARNING: there are less than "(1F6.2)" % of unconverged cells after "(1I4)" iterations")') & unconverged_fraction, n_iter write(*,*) " -> forcing convergence" From 4a3de8df32a381a0398d1aba62961223b31a4f1f Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Fri, 20 Oct 2023 08:30:49 +0200 Subject: [PATCH 08/46] cleaning --- src/gas/atom_transfer.f90 | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index f00c30630..f65b37528 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -726,10 +726,7 @@ subroutine nlte_loop_mali() diff_old = diff conv_acc = conv_speed - if ((diff < precision).and.(.not.lcswitch_enabled))then!maxval_cswitch_atoms()==1.0_dp - ! if ( (unconverged_fraction < 3.0).and.maxval_cswitch_atoms()==1.0_dp)then - ! if ( ((unconverged_fraction < 3.0).and.maxval_cswitch_atoms()==1.0_dp).or.& - ! ((diff < precision).and.maxval_cswitch_atoms()==1.0_dp) )then + if ((diff < precision).and.(.not.lcswitch_enabled))then if (lprevious_converged) then lconverged = .true. else From 66b33dd4636de2081170e36e6012f1f039fe5152 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Fri, 20 Oct 2023 08:33:00 +0200 Subject: [PATCH 09/46] reducing threshold to skip converged cells in the main loop --- src/gas/atom_transfer.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index f65b37528..51562f836 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -359,7 +359,7 @@ subroutine nlte_loop_mali() !$ id = omp_get_thread_num() + 1 l_iterate = (icompute_atomRT(icell)>0) stream(id) = init_sprng(gtype, id-1,nb_proc,seed,SPRNG_DEFAULT) - if( (diff_loc(icell) < 1d-1 * precision).and..not.lcswitch_enabled ) cycle + if( (diff_loc(icell) < 5d-2 * precision).and..not.lcswitch_enabled ) cycle if (l_iterate) then @@ -447,7 +447,7 @@ subroutine nlte_loop_mali() !$omp atomic n_cells_done = n_cells_done + 1 ! n_cells_remaining = size(pack(diff_loc, & - ! mask=(diff_loc < 1d-1 * precision))) + ! mask=(diff_loc < 5d-2 * precision))) if (real(n_cells_done) > 0.02*ibar*n_cells) then call progress_bar(ibar) !$omp atomic From 21589bea16de0fb07187c3f24083054432150a7e Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Sun, 22 Oct 2023 18:15:44 +0200 Subject: [PATCH 10/46] stopping electronic density iteration if dne <<< precision --- src/gas/atom_transfer.f90 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index 51562f836..55a003110 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -592,12 +592,12 @@ subroutine nlte_loop_mali() ! write(*,'(" NEW ne(min)="(1ES16.8E3)" m^-3 ;ne(max)="(1ES16.8E3)" m^-3")') & ! minval(ne,mask=(icompute_atomRT>0)), maxval(ne) ! write(*,*) '' - ! if ((dne < 1d-2 * precision).and.(.not.lcswitch_enabled)) then - ! !Or compare with 3 previous values of dne ? that should be below 1e-2 precision - ! !Do we need to restart it eventually ? - ! write(*,*) " *** stopping electronic density convergence at iteration ", n_iter - ! n_iterate_ne = 0 - ! endif + if ((dne < 1d-4 * precision).and.(.not.lcswitch_enabled)) then + !Do we need to restart it eventually ? + write(*,*) " *** dne", dne + write(*,*) " *** stopping electronic density convergence at iteration ", n_iter + n_iterate_ne = 0 + endif end if !***********************************************************! From 3c7a2746c5df4f96e8bf77bc6cd7fbeb2038bb83 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 24 Oct 2023 10:29:48 +0200 Subject: [PATCH 11/46] first commit --- src/gas/collision_atom.f90 | 6 ++++- src/gas/electron_density.f90 | 35 ++++++++++++++-------------- src/gas/lte.f90 | 45 +++++++++++++++++++++--------------- src/gas/see.f90 | 10 +++++++- 4 files changed, 57 insertions(+), 39 deletions(-) diff --git a/src/gas/collision_atom.f90 b/src/gas/collision_atom.f90 index 49e162afd..de3026937 100644 --- a/src/gas/collision_atom.f90 +++ b/src/gas/collision_atom.f90 @@ -54,7 +54,11 @@ subroutine collision_rates_hydrogen_loc(id,icell) do i=1,hydrogen%Nlevel do j=i+1,hydrogen%Nlevel-1 kr = hydrogen%ij_to_trans(i,j) - ni_on_nj_star = hydrogen%nstar(i,icell) / hydrogen%nstar(j,icell) + if (hydrogen%nstar(j,icell)>0.0) then + ni_on_nj_star = hydrogen%nstar(i,icell) / hydrogen%nstar(j,icell) + else + ni_on_nj_star = 0.0 !correct ? + endif hydrogen%lines(kr)%Cij(id) = ne(icell) * CE(i,j) !deriv = Cij/ne hydrogen%lines(kr)%Cji(id) = ne(icell) * CE(i,j) * ni_on_nj_star !deriv = 2*Cji/ne enddo diff --git a/src/gas/electron_density.f90 b/src/gas/electron_density.f90 index c3cf1610c..5db883b1f 100644 --- a/src/gas/electron_density.f90 +++ b/src/gas/electron_density.f90 @@ -39,9 +39,7 @@ module elecdensity integer, parameter :: N_MAX_ELEMENT=26!stops at Iron. real(kind=dp) :: min_f_HII, max_f_HII character(len=10) :: ne_filename = "ne.fits.gz" - real(kind=dp), parameter :: ne_min_limit = 1d-10 ! ne_min_limit * nHtot = electron per cubic meters. - !if ne is below ne_min_limit, we set it to 1 electron per cc (ne_one) ! - real(kind=dp), parameter :: ne_one = 1.0_dp !one electron per cubic meters. + real(kind=dp), parameter :: ne_small = 1d0 ! [m^-3] !Introducing a lock for ne iterations with icompute_atomRT == 2 !the transfer (and opacity) is solved for icompute_atomRT > 0 @@ -397,7 +395,7 @@ subroutine solve_ne_loc(k,ne_init) if (is_nan_infinity(ne(k))>0) then write(*,*) niter, "icell=",k," T=",T(k)," nH=",nHtot(k), "dne = ",dne, " ne=",ne(k), " nedag = ", ne_old, " sum=", sum call error("electron density is nan or inf!") - else if (ne(k) <= 0.0) then + else if (ne(k) < 0.0) then write(*,*) niter, "icell=",k," T=",T(k)," nH=",nHtot(k), " ne0=", ne_init write(*,*) "dne = ",dne, " ne=",ne(k), " nedag = ", ne_old, "sum=", sum call error("Negative electron density!") @@ -405,12 +403,12 @@ subroutine solve_ne_loc(k,ne_init) niter = niter + 1 if (dne <= MAX_ELECTRON_ERROR) then - if (ne(k) < nHtot(k)*ne_min_limit) then - write(*,*) " (Solve ne) ne < ne_min_limit, setting cell transparent!", k + if (ne(k) < ne_small) then + write(*,*) " (Solve ne) ne < ne_small at cell",k!, " ; setting cell transparent!" write(*,*) "T=", T(k), ' nHtot=', nHtot(k), " ne=", ne(k) - write(*,*) " -> setting ne to ", ne_one, " m^-3" - ne(k) = ne_one - icompute_atomRT(k) = 0 + write(*,*) " -> setting ne to ", ne_small, " m^-3" + ne(k) = ne_small + ! icompute_atomRT(k) = 0 endif exit else if (niter >= N_MAX_ELECTRON_ITERATIONS) then @@ -527,17 +525,18 @@ subroutine solve_ne(initial, verbose, epsilon) !if Abund << 1. and chiM << chiH then ! ne (H+M) = ne(H) + ne(M) ne0 = ne0 + ne_oldM - if (ne0 < nHtot(k)*ne_min_limit) ne0 = ne_one + ne0 = max(ne0, ne_small) end if - if (t(k) > 1d6) then - !fully ionised - ne(k) = 1.2 * nHtot(k) - else - !Loop starts - call solve_ne_loc(k, ne0) - endif + ! if (t(k) > 1d6) then + ! !fully ionised + ! ne(k) = 1.2 * nHtot(k) + ! else + ! !Loop starts + ! call solve_ne_loc(k, ne0) + ! endif + call solve_ne_loc(k, ne0) if (abs(1.0_dp - ne0 / ne(k)) > eps_id(id)) then @@ -560,7 +559,7 @@ subroutine solve_ne(initial, verbose, epsilon) !$omp end parallel call progress_bar(50) epsilon = maxval(eps_id) - ik_max = ik_max_id(locate(eps_id, epsilon)) + ik_max = max(ik_max_id(locate(eps_id, epsilon)),1) if (verbose) then write(*,*) " ---------------------------------------------------- " diff --git a/src/gas/lte.f90 b/src/gas/lte.f90 index 30c94c5a8..f1e681b39 100644 --- a/src/gas/lte.f90 +++ b/src/gas/lte.f90 @@ -16,7 +16,7 @@ module lte implicit none integer, dimension(101) :: ndebye - real(kind=dp), parameter :: nsmall = 1.0! [m^-3], small LTE populations are replaced by this. + real(kind=dp), parameter :: nsmall = 1d0 ! [m^-3], small LTE populations are replaced by this. contains @@ -107,7 +107,7 @@ subroutine LTEpops_H_loc (k) ! -------------------------------------------------------------- ! integer, intent(in) :: k logical :: locupa_prob - real(kind=dp) :: dEion, dE, sum, c2, phik, phiHmin + real(kind=dp) :: dEion, dE, sum, c2, phik, phiHmin, ntotal real(kind=dp) :: n_eff, wocc, chi0, wocc0, E00, E, Egs integer :: Z, dZ, i, m @@ -118,6 +118,7 @@ subroutine LTEpops_H_loc (k) sum = 1.0 phik = ne(k)*phi_jl(T(k),1.d0,1.d0,0.d0) !a constant of the temperature and electron density + ntotal = hydrogen%Abund*nHtot(k) do i=2, hydrogen%Nlevel @@ -142,10 +143,13 @@ subroutine LTEpops_H_loc (k) endif end do + !handle very low populations + mass conservation + if (hydrogen%nstar(i,k) < 1d-50 * ntotal) hydrogen%nstar(i,k) = 0.0 + sum = sum+hydrogen%nstar(i,k) end do - hydrogen%nstar(1,k) = hydrogen%Abund*nHtot(k)/sum + hydrogen%nstar(1,k) = ntotal/sum !test positivity, can be 0 if ((hydrogen%nstar(1,k) < 0)) then @@ -155,22 +159,25 @@ subroutine LTEpops_H_loc (k) write(*,*) " ************************************* " stop end if - if (hydrogen%nstar(1,k) < nsmall) hydrogen%nstar(1,k) = nsmall - - do i=2,hydrogen%Nlevel !debug - hydrogen%nstar(i,k) = max(hydrogen%nstar(i,k)*hydrogen%nstar(1,k), nsmall) - - ! if (hydrogen%nstar(i,k) < 0) then - ! !--> debug - ! write(*,*) " ************************************* " - ! write(*,*) "Warning population of hydrogen ", hydrogen%ID, "lvl=", i, "nstar=",hydrogen%nstar(i,k), " negative!" - ! write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & - ! " n0=", hydrogen%nstar(1,k) - ! write(*,*) " ************************************* " - ! stop - ! end if - ! if (hydrogen%nstar(i,k) < nsmall) hydrogen%nstar(i,k) = nsmall - end do + !-> never 0 by construction + ! if (hydrogen%nstar(1,k) < nsmall) hydrogen%nstar(1,k) = nsmall + + + hydrogen%nstar(:,k) = hydrogen%nstar(:,k)*hydrogen%nstar(1,k) + ! do i=2,hydrogen%Nlevel !debug + ! hydrogen%nstar(i,k) = max(hydrogen%nstar(i,k)*hydrogen%nstar(1,k), nsmall) + + ! ! if (hydrogen%nstar(i,k) < 0) then + ! ! !--> debug + ! ! write(*,*) " ************************************* " + ! ! write(*,*) "Warning population of hydrogen ", hydrogen%ID, "lvl=", i, "nstar=",hydrogen%nstar(i,k), " negative!" + ! ! write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & + ! ! " n0=", hydrogen%nstar(1,k) + ! ! write(*,*) " ************************************* " + ! ! stop + ! ! end if + ! ! if (hydrogen%nstar(i,k) < nsmall) hydrogen%nstar(i,k) = nsmall + ! end do if (maxval(hydrogen%nstar(:,k)) > huge_dp) then write(*,*) " ************************************* " diff --git a/src/gas/see.f90 b/src/gas/see.f90 index e002ea8a1..b4f20a53b 100644 --- a/src/gas/see.f90 +++ b/src/gas/see.f90 @@ -504,8 +504,11 @@ subroutine init_radrates_atom(id,icell,atom) atom%continua(kr)%Rij(id) = 0.0_dp !updated value of ni and nj! !-> 0 if cont does not contribute to opac. + ! atom%continua(kr)%Rji(id) = nlte_fact * tab_Aji_cont(kr,atom%activeindex,icell) * & + ! atom%nstar(i,icell)/atom%nstar(j,icell) atom%continua(kr)%Rji(id) = nlte_fact * tab_Aji_cont(kr,atom%activeindex,icell) * & - atom%nstar(i,icell)/atom%nstar(j,icell) + atom%ni_on_nj_star(i,icell) + !check ratio ni_on_nj_star for the continua when there are multiple ionisation states (works for H, test for He) enddo do kr=1,atom%Nline @@ -951,6 +954,9 @@ subroutine see_atoms_ne(id,icell,dM,dne) call particle_conservation (icell, Neq_ne, xvar(:,id), fvar(:,id), dfvar(:,:,id)) !newton raphson! + write(*,*) "T=", T(icell), ne(icell), nHtot(icell) + write(*,*) "nstar=", hydrogen%nstar(:,icell) + write(*,*) "n=", hydrogen%n(:,icell) call multivariate_newton_raphson (neq_ne, dfvar(:,:,id), fvar(:,id), xvar(:,id)) !update atomic populations and ne @@ -1288,6 +1294,8 @@ subroutine multivariate_newton_raphson (neq, df, f, x) ! *********************** ! ! call GaussSlv(df,f,neq) + write(*,*) "f=", f + write(*,*) "df=", df call solve_lin(df,f,neq) if (is_nan_infinity_vector(f)>0) then ! write(*,*) "fdag=", bdag From e45b21cd5b62e2d1aae9deb59c55c88e08f70bb2 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 24 Oct 2023 10:55:36 +0200 Subject: [PATCH 12/46] second commit --- src/gas/electron_density.f90 | 10 +----- src/gas/lte.f90 | 69 ++++++++++++------------------------ src/gas/see.f90 | 12 +++---- 3 files changed, 29 insertions(+), 62 deletions(-) diff --git a/src/gas/electron_density.f90 b/src/gas/electron_density.f90 index 5db883b1f..ac6829961 100644 --- a/src/gas/electron_density.f90 +++ b/src/gas/electron_density.f90 @@ -529,15 +529,7 @@ subroutine solve_ne(initial, verbose, epsilon) end if - ! if (t(k) > 1d6) then - ! !fully ionised - ! ne(k) = 1.2 * nHtot(k) - ! else - ! !Loop starts - ! call solve_ne_loc(k, ne0) - ! endif - call solve_ne_loc(k, ne0) - + call solve_ne_loc(k, ne0) if (abs(1.0_dp - ne0 / ne(k)) > eps_id(id)) then eps_id(id) = abs(1.0_dp - ne0 / ne(k)) diff --git a/src/gas/lte.f90 b/src/gas/lte.f90 index f1e681b39..95b83d2ca 100644 --- a/src/gas/lte.f90 +++ b/src/gas/lte.f90 @@ -16,7 +16,7 @@ module lte implicit none integer, dimension(101) :: ndebye - real(kind=dp), parameter :: nsmall = 1d0 ! [m^-3], small LTE populations are replaced by this. + real(kind=dp), parameter :: small_lte_fraction = 1d-10 contains @@ -144,14 +144,17 @@ subroutine LTEpops_H_loc (k) end do !handle very low populations + mass conservation - if (hydrogen%nstar(i,k) < 1d-50 * ntotal) hydrogen%nstar(i,k) = 0.0 + if (hydrogen%nstar(i,k) < small_lte_fraction * ntotal) hydrogen%nstar(i,k) = 0.0 sum = sum+hydrogen%nstar(i,k) end do hydrogen%nstar(1,k) = ntotal/sum + !denorm the other levels + hydrogen%nstar(2:hydrogen%Nlevel,k) = hydrogen%nstar(2:hydrogen%Nlevel,k)*hydrogen%nstar(1,k) - !test positivity, can be 0 + !test positivity. Must be > 0. + !sum is either 1 (all in ground state) or infinity (fully ionised). And ntotal here > 0. if ((hydrogen%nstar(1,k) < 0)) then write(*,*) " ************************************* " write(*,*) "error negative gs pop", hydrogen%ID, hydrogen%nstar(i,k) @@ -159,26 +162,9 @@ subroutine LTEpops_H_loc (k) write(*,*) " ************************************* " stop end if - !-> never 0 by construction - ! if (hydrogen%nstar(1,k) < nsmall) hydrogen%nstar(1,k) = nsmall - - - hydrogen%nstar(:,k) = hydrogen%nstar(:,k)*hydrogen%nstar(1,k) - ! do i=2,hydrogen%Nlevel !debug - ! hydrogen%nstar(i,k) = max(hydrogen%nstar(i,k)*hydrogen%nstar(1,k), nsmall) - - ! ! if (hydrogen%nstar(i,k) < 0) then - ! ! !--> debug - ! ! write(*,*) " ************************************* " - ! ! write(*,*) "Warning population of hydrogen ", hydrogen%ID, "lvl=", i, "nstar=",hydrogen%nstar(i,k), " negative!" - ! ! write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & - ! ! " n0=", hydrogen%nstar(1,k) - ! ! write(*,*) " ************************************* " - ! ! stop - ! ! end if - ! ! if (hydrogen%nstar(i,k) < nsmall) hydrogen%nstar(i,k) = nsmall - ! end do + !never set to 0 the ground-state population. + !sanity check if (maxval(hydrogen%nstar(:,k)) > huge_dp) then write(*,*) " ************************************* " write(*,*) "ERROR, populations of hydrogen larger than huge_dp" @@ -202,7 +188,7 @@ subroutine LTEpops_H_loc (k) !Set ni/nj ratio for continuum transitions in case ne-> 0 and nj ->0 !should be ok for lines (the ratio for lines is used only in the collision) do i=1, hydrogen%Ncont - if (hydrogen%nstar(hydrogen%continua(i)%j,k)>nsmall) then + if (hydrogen%nstar(hydrogen%continua(i)%j,k)>small_lte_fraction*ntotal) then hydrogen%ni_on_nj_star(hydrogen%continua(i)%i,k) = & hydrogen%nstar(hydrogen%continua(i)%i,k)/hydrogen%nstar(hydrogen%continua(i)%j,k) else @@ -225,7 +211,7 @@ subroutine LTEpops_atom_loc(k,atom,debye) logical, intent(in) :: debye logical :: locupa_prob, print_diff real(kind=dp) :: dEion, dE, sum, c2, phik, phiHmin - real(kind=dp) :: n_eff, wocc, chi0, wocc0 + real(kind=dp) :: n_eff, wocc, chi0, wocc0, ntotal integer :: Z, dZ, i, m ! debye shielding activated: @@ -256,6 +242,7 @@ subroutine LTEpops_atom_loc(k,atom,debye) sum = 1.0 phik = ne(k)*phi_jl(T(k),1.d0,1.d0,0.d0) !a constant of the temperature and electron density + ntotal = atom%Abund*nHtot(k) do i=2, atom%Nlevel @@ -297,6 +284,7 @@ subroutine LTEpops_atom_loc(k,atom,debye) atom%nstar(i,k) = 0d0 endif end do + if (atom%nstar(i,k) < small_lte_fraction * ntotal) atom%nstar(i,k) = 0.0 sum = sum+atom%nstar(i,k) !compute total pop = Sum_jSum_i nij !with Sum_i nij = Nj @@ -311,9 +299,11 @@ subroutine LTEpops_atom_loc(k,atom,debye) ! write(*,*) "-------------------" ! write(*,*) "Atom=",atom%ID, " A=", atom%Abund ! write(*,*) "ntot", ntotal_atom(k,atom), " nHtot=",nHtot(k) - atom%nstar(1,k) = atom%Abund*nHtot(k)/sum + atom%nstar(1,k) = ntotal/sum + !denorm the other levels + atom%nstar(2:atom%Nlevel,k) = atom%nstar(2:atom%Nlevel,k)*atom%nstar(1,k) - !test positivity, can be 0 + !test positivity. Must be > 0 if (atom%nstar(1,k) < 0) then write(*,*) " ************************************* " write(*,*) "Error negative ground state population ", atom%ID, "n0=", atom%nstar(1,k) @@ -321,22 +311,7 @@ subroutine LTEpops_atom_loc(k,atom,debye) write(*,*) " ************************************* " stop end if - if (atom%nstar(1,k) < nsmall) atom%nstar(1,k) = nsmall - - do i=2,atom%Nlevel !debug - atom%nstar(i,k) = max(atom%nstar(i,k)*atom%nstar(1,k), nsmall) - ! if (atom%nstar(i,k) < 0) then - ! !--> debug - ! write(*,*) " ************************************* " - ! write(*,*) "Warning population of atom ", atom%ID, "lvl=", i, "nstar=",atom%nstar(i,k), " negative !" - ! write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k), & - ! " n0=", atom%nstar(1,k) - ! write(*,*) " ************************************* " - ! stop - ! atom%nstar(i,k) = nsmall - ! end if - ! if (atom%nstar(i,k) < nsmall) atom%nstar(i,k) = nsmall - end do + !never set to 0 the ground-state population. if (maxval(atom%nstar(:,k)) > huge_dp) then write(*,*) " ************************************* " @@ -363,7 +338,7 @@ subroutine LTEpops_atom_loc(k,atom,debye) !Set ni/nj ratio for continuum transitions in case ne-> 0 and nj ->0 !should be ok for lines (the ratio for lines is used only in the collision) do i=1, atom%Ncont - if (atom%nstar(atom%continua(i)%j,k)>nsmall) then + if (atom%nstar(atom%continua(i)%j,k)>small_lte_fraction*ntotal) then atom%ni_on_nj_star(atom%continua(i)%i,k) = atom%nstar(atom%continua(i)%i,k)/atom%nstar(atom%continua(i)%j,k) else atom%ni_on_nj_star(atom%continua(i)%i,k) = 0.0 @@ -513,7 +488,7 @@ subroutine LTEpops_H() hydrogen%nstar(1,k) = hydrogen%Abund*nHtot(k)/sum !test positivity, can be 0 - if ((hydrogen%nstar(1,k) < nsmall)) then + if ((hydrogen%nstar(1,k) < 0.0)) then write(*,*) " ************************************* " write(*,*) "Warning too small gs pop", hydrogen%ID, hydrogen%nstar(i,k) write(*,*) "cell=",k, hydrogen%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) @@ -524,7 +499,7 @@ subroutine LTEpops_H() do i=2,hydrogen%Nlevel !debug hydrogen%nstar(i,k) = hydrogen%nstar(i,k)*hydrogen%nstar(1,k) - if (hydrogen%nstar(i,k) < nsmall) then + if (hydrogen%nstar(i,k) < 0.0) then write(*,*) " ************************************* " write(*,*) "Warning population of hydrogen ", hydrogen%ID, "lvl=", i, "nstar=",hydrogen%nstar(i,k), & " lower than tiny_dp." @@ -711,7 +686,7 @@ subroutine LTEpops_atom(atom, debye) atom%nstar(1,k) = atom%Abund*nHtot(k)/sum !test positivity, can be 0 - if (atom%nstar(1,k) < nsmall) then + if (atom%nstar(1,k) < 0.0) then write(*,*) " ************************************* " write(*,*) "Warning too small ground state population ", atom%ID, "n0=", atom%nstar(1,k) write(*,*) "cell=",k, atom%ID, "dark?=",icompute_atomRT(k), "T=",T(k), "nH=",nHtot(k), "ne=",ne(k) @@ -721,7 +696,7 @@ subroutine LTEpops_atom(atom, debye) end if do i=2,atom%Nlevel !debug atom%nstar(i,k) = atom%nstar(i,k)*atom%nstar(1,k) - if (atom%nstar(i,k) < nsmall) then + if (atom%nstar(i,k) < 0.0) then write(*,*) " ************************************* " write(*,*) "Warning population of atom ", atom%ID, "lvl=", i, "nstar=",atom%nstar(i,k), " lower than", & " tiny_dp."! Replacing by tiny_dp" diff --git a/src/gas/see.f90 b/src/gas/see.f90 index b4f20a53b..e620010f7 100644 --- a/src/gas/see.f90 +++ b/src/gas/see.f90 @@ -17,7 +17,7 @@ module see implicit none !populations below that threshold not taken into account in convergence. - real(kind=dp), parameter :: frac_limit_pops = 1d-15!1d-50 + real(kind=dp), parameter :: small_nlte_fraction = 1d-15!1d-50 !Variables for Non-LTE loop and MALI method real(kind=dp), allocatable :: ngpop(:,:,:,:) real(kind=dp), allocatable :: tab_Aji_cont(:,:,:), tab_Vij_cont(:,:,:) @@ -357,7 +357,7 @@ subroutine see_atom(id,icell,atom,dM) do l=1,atom%Nlevel atom%n(l,icell) = atom%n(l,icell) * ntotal - if (atom%n(l,icell) < frac_limit_pops * ntotal) then + if (atom%n(l,icell) < small_nlte_fraction * ntotal) then Nsmall_pops = Nsmall_pops + 1 level_index(lp) = l lp = lp + 1 @@ -967,7 +967,7 @@ subroutine see_atoms_ne(id,icell,dM,dne) do j=1,at%Nlevel at%n(j,icell) = at%n(j,icell) * ( 1.0_dp + fvar((i-1)+j,id)/(1.0_dp + d_damp * abs(fvar((i-1)+j,id))) ) if (at%n(j,icell) < 0.0) neg_pops = .true. - ! if (at%n(j,icell) < frac_limit_pops * at%Abund*nHtot(icell) )then + ! if (at%n(j,icell) < small_nlte_fraction * at%Abund*nHtot(icell) )then ! write(*,*) "small pops for level ", j ! endif enddo @@ -979,9 +979,9 @@ subroutine see_atoms_ne(id,icell,dM,dne) if (verbose)write(*,*) ( 1.0 + fvar(neq_ne,id)/(1.0_dp + d_damp * abs(fvar(neq_ne,id))) ) if (verbose)write(*,*) fvar(neq_ne,id), d_damp ! 1d-16 - ! if (ne(icell) < frac_limit_pops * nhtot(icell)) write(*,*) "** small ne at cell ", icell - ! if ( (ne(icell) < frac_limit_pops * nHtot(icell)).or.(neg_pops) ) rest_damping = .true. - if ( (ne(icell) < frac_limit_pops * sum(pops_ion(:,:,id))).or.(neg_pops) ) rest_damping = .true. + ! if (ne(icell) < small_nlte_fraction * nhtot(icell)) write(*,*) "** small ne at cell ", icell + ! if ( (ne(icell) < small_nlte_fraction * nHtot(icell)).or.(neg_pops) ) rest_damping = .true. + if ( (ne(icell) < small_nlte_fraction * sum(pops_ion(:,:,id))).or.(neg_pops) ) rest_damping = .true. !-> here pops_ion has the old values ! !restart with more iterations and larger damping (more stable, slower convergence) if (rest_damping .and. d_damp < (damp_char + 1.0)) then From 55bb8dc1a00db99f8abebe8b3e0ff213fec996a2 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 24 Oct 2023 16:48:23 +0200 Subject: [PATCH 13/46] added jacobi and sparse jacobi solver --- src/utils.f90 | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/src/utils.f90 b/src/utils.f90 index ad2d96f8c..c27bf8c96 100644 --- a/src/utils.f90 +++ b/src/utils.f90 @@ -226,6 +226,102 @@ real(kind=dp) function interp_dp(y, x, xp) end function interp_dp !********************************************************************** +function matdiag(A,n) + !return the diagonal of a square matrix A(N,N) + !as a vector of length n. + integer, intent(in) :: n + real(kind=dp), intent(in) :: A(n*n) + ! real(kind=dp), intent(in) :: A(n,n) + real(kind=dp) :: matdiag(n) + integer :: i + + ! do i = 1, n + ! matdiag(i) = A(i,i) + ! end do + matdiag(:) = A(1::n+1) + + return +end function matdiag + +subroutine Jacobi(a,b,x,n) +!solve a system Ax=b with the iterative jacobi method + integer, intent(in) :: n + real(kind=dp) :: a(n,n), b(n) + real(kind=dp), intent(inout) :: x(n) + + real(kind=dp), parameter :: tol = 1d-10 ! Convergence tolerance + !eventually, omega would be defined as a function of the eigen values of A + real(kind=dp), parameter :: omega = 1.0 ! Damping factor (0 < omega < 1) + integer, parameter :: nIterMax = 20000 + + integer :: niter, i + real(kind=dp) :: diff + + logical :: lconverged + real(kind=dp) :: diag(n), x_new(n) + + diff = 0 + niter = 0 + lconverged = .false. + do while (.not. lconverged) + niter = niter + 1 + + ! Calculate the new x values using the damped Jacobi method + diag(:) = matdiag(A,n) + x_new(:) = omega * (b(:) - matmul(A,x) + x(:) * diag(:)) / diag(:) + & + (1.0_dp - omega) * x(:) + + diff = maxval(abs((x_new - x)/x_new)) + lconverged = (diff < tol) + + x = x_new + if (niter > nIterMax) exit + + end do + + return +end subroutine jacobi + +subroutine Jacobi_sparse(a,b,x,n) +!solve a system Ax=b with the iterative jacobi method for a sparse A matrix. +!This routine only iterates over x where diag(a) is != 0. + integer, intent(in) :: n + real(kind=dp) :: a(n,n), b(n) + real(kind=dp), intent(inout) :: x(n) + + real(kind=dp), parameter :: tol = 1d-10 ! Convergence tolerance + !eventually, omega would be defined as a function of the eigen values of A + real(kind=dp), parameter :: omega = 1.0 ! Damping factor (0 < omega < 1) + integer, parameter :: nIterMax = 20000 + + integer :: niter, i + real(kind=dp) :: diff + + logical :: lconverged + real(kind=dp) :: diag(n), x_new(n) + + diff = 0 + niter = 0 + lconverged = .false. + do while (.not. lconverged) + niter = niter + 1 + + ! Calculate the new x values using the damped Jacobi method + diag(:) = matdiag(A,n) + where (diag /= 0.0) + x_new(:) = omega * (b(:) - matmul(A,x) + x(:) * diag(:)) / diag(:) + & + (1.0_dp - omega) * x(:) + endwhere + diff = maxval(abs((x_new - x)/x_new),x_new > 0.0) + lconverged = (diff < tol) + + x = x_new + if (niter > nIterMax) exit + + end do + + return +end subroutine jacobi_sparse subroutine GaussSlv(a, b, n) ! Resolution d'un systeme d'equation par methode de Gauss From 7eb8832fc596b04013e99606cd437cbe27afc383 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 24 Oct 2023 16:48:54 +0200 Subject: [PATCH 14/46] minor fix --- src/gas/electron_density.f90 | 18 ++++++++++-------- src/gas/lte.f90 | 6 +++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/gas/electron_density.f90 b/src/gas/electron_density.f90 index ac6829961..f1274ef84 100644 --- a/src/gas/electron_density.f90 +++ b/src/gas/electron_density.f90 @@ -39,7 +39,7 @@ module elecdensity integer, parameter :: N_MAX_ELEMENT=26!stops at Iron. real(kind=dp) :: min_f_HII, max_f_HII character(len=10) :: ne_filename = "ne.fits.gz" - real(kind=dp), parameter :: ne_small = 1d0 ! [m^-3] + real(kind=dp), parameter :: ne_small = 1d3 ! [m^-3] !Introducing a lock for ne iterations with icompute_atomRT == 2 !the transfer (and opacity) is solved for icompute_atomRT > 0 @@ -403,13 +403,14 @@ subroutine solve_ne_loc(k,ne_init) niter = niter + 1 if (dne <= MAX_ELECTRON_ERROR) then - if (ne(k) < ne_small) then - write(*,*) " (Solve ne) ne < ne_small at cell",k!, " ; setting cell transparent!" - write(*,*) "T=", T(k), ' nHtot=', nHtot(k), " ne=", ne(k) - write(*,*) " -> setting ne to ", ne_small, " m^-3" - ne(k) = ne_small - ! icompute_atomRT(k) = 0 - endif + !set transparent ? dark ? + ! if (ne(k) < ne_small) then + ! write(*,*) " (Solve ne) ne < ne_small at cell",k!, " ; setting cell transparent!" + ! write(*,*) "T=", T(k), ' nHtot=', nHtot(k), " ne=", ne(k) + ! write(*,*) " -> setting ne to ", ne_small, " m^-3" + ! ne(k) = ne_small + ! icompute_atomRT(k) = 0 + ! endif exit else if (niter >= N_MAX_ELECTRON_ITERATIONS) then if (dne > 0.0) then !shows the warning only if dne is actually greater than 1 @@ -565,6 +566,7 @@ subroutine solve_ne(initial, verbose, epsilon) ! call show_electron_given_per_elem(0, 0, max_fjk) write(*,*) " ---------------------------------------------------- " endif + ! where (ne < ne_small) ne = 0.0 !that's because I use the sum as a variable so the function doesn't exist. do k=2, nb_proc diff --git a/src/gas/lte.f90 b/src/gas/lte.f90 index 95b83d2ca..54dd8597e 100644 --- a/src/gas/lte.f90 +++ b/src/gas/lte.f90 @@ -16,7 +16,7 @@ module lte implicit none integer, dimension(101) :: ndebye - real(kind=dp), parameter :: small_lte_fraction = 1d-10 + real(kind=dp), parameter :: small_lte_fraction = 1d-15 contains @@ -144,7 +144,7 @@ subroutine LTEpops_H_loc (k) end do !handle very low populations + mass conservation - if (hydrogen%nstar(i,k) < small_lte_fraction * ntotal) hydrogen%nstar(i,k) = 0.0 + if (hydrogen%nstar(i,k) < small_lte_fraction) hydrogen%nstar(i,k) = 0.0 sum = sum+hydrogen%nstar(i,k) end do @@ -284,7 +284,7 @@ subroutine LTEpops_atom_loc(k,atom,debye) atom%nstar(i,k) = 0d0 endif end do - if (atom%nstar(i,k) < small_lte_fraction * ntotal) atom%nstar(i,k) = 0.0 + if (atom%nstar(i,k) < small_lte_fraction) atom%nstar(i,k) = 0.0 sum = sum+atom%nstar(i,k) !compute total pop = Sum_jSum_i nij !with Sum_i nij = Nj From 4b47220b98d231d172b344f80de9ee8711f06613 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 24 Oct 2023 16:49:28 +0200 Subject: [PATCH 15/46] renamed variable --- src/gas/atom_transfer.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index 55a003110..2edc7e1e9 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -25,7 +25,7 @@ module atom_transfer use opacity_atom, only : alloc_atom_opac, Itot, psi, dealloc_atom_opac, xcoupling, write_opacity_emissivity_bin, & lnon_lte_loop, vlabs, calc_contopac_loc, set_max_damping, deactivate_lines, activate_lines, & activate_continua, deactivate_continua - use see, only : ngpop, Neq_ng, ngpop, alloc_nlte_var, dealloc_nlte_var, frac_limit_pops, & + use see, only : ngpop, Neq_ng, ngpop, alloc_nlte_var, dealloc_nlte_var, small_nlte_fraction, & init_rates, update_populations, accumulate_radrates_mali, write_rates, init_radrates_atom use optical_depth, only : integ_ray_atom use utils, only : cross_product, gauss_legendre_quadrature, progress_bar, rotation_3d, vacuum2air, & @@ -628,7 +628,7 @@ subroutine nlte_loop_mali() at => ActiveAtoms(nact)%p do ilevel=1,at%Nlevel - if ( ngpop(ilevel,nact,icell,1) >= frac_limit_pops * at%Abund*nHtot(icell) ) then + if ( ngpop(ilevel,nact,icell,1) >= small_nlte_fraction * at%Abund*nHtot(icell) ) then dN1 = abs(1d0-at%n(ilevel,icell)/ngpop(ilevel,nact,icell,1)) dN = max(dN1, dN) dM(nact) = max(dM(nact), dN1) From f1a1b7cd5636079deaf90bbd7dcecef6179982e7 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 24 Oct 2023 16:49:50 +0200 Subject: [PATCH 16/46] handling very low population and sparse iteration matrix --- src/gas/see.f90 | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/gas/see.f90 b/src/gas/see.f90 index e620010f7..cfcefd364 100644 --- a/src/gas/see.f90 +++ b/src/gas/see.f90 @@ -8,7 +8,8 @@ module see use wavelengths, only : n_lambda use wavelengths_gas, only : Nlambda_max_line, Nlambda_max_trans, Nlambda_max_cont, n_lambda_cont, & tab_lambda_cont, tab_lambda_nm - use utils, only : gaussslv, solve_lin, is_nan_infinity_vector, linear_1D_sorted, is_nan_infinity_matrix + use utils, only : gaussslv, solve_lin, is_nan_infinity_vector, linear_1D_sorted, is_nan_infinity_matrix, & + matdiag, jacobi_sparse use opacity_atom, only : phi_loc, psi, chi_up, chi_down, uji_down, Itot, eta_atoms, xcoupling_cont, cross_coupling_cont_i use messages, only : warning, error use collision_atom, only : collision_rates_atom_loc, collision_rates_hydrogen_loc @@ -954,11 +955,12 @@ subroutine see_atoms_ne(id,icell,dM,dne) call particle_conservation (icell, Neq_ne, xvar(:,id), fvar(:,id), dfvar(:,:,id)) !newton raphson! - write(*,*) "T=", T(icell), ne(icell), nHtot(icell) - write(*,*) "nstar=", hydrogen%nstar(:,icell) - write(*,*) "n=", hydrogen%n(:,icell) + ! write(*,*) id, icell, "T=", T(icell), ne(icell), nHtot(icell) + ! write(*,*) "nstar=", hydrogen%nstar(:,icell) + ! write(*,*) "n=", hydrogen%n(:,icell) call multivariate_newton_raphson (neq_ne, dfvar(:,:,id), fvar(:,id), xvar(:,id)) - +! write(*,*) fvar(:,id) +! stop !update atomic populations and ne neg_pops = .false. i = 1 @@ -1052,7 +1054,7 @@ subroutine see_atoms_ne(id,icell,dM,dne) i = 1 do n=1,NactiveAtoms at => Activeatoms(n)%p - dM = max(dM,maxval(abs(1.0 - npop_dag(i:(i-1)+at%Nlevel,id)/at%n(:,icell)))) + dM = max(dM,maxval(abs(1.0 - npop_dag(i:(i-1)+at%Nlevel,id)/at%n(:,icell)),at%n(:,icell)>0)) ngpop(1:at%Nlevel,at%activeindex,icell,1) = at%n(:,icell) !reset at%n(:,icell) = npop_dag(i:(i-1)+at%Nlevel,id) !the first value before iterations @@ -1279,6 +1281,7 @@ subroutine multivariate_newton_raphson (neq, df, f, x) real(kind=dp), intent(in) :: x(neq) real(kind=dp), intent(inout) :: df(neq,neq), f(neq) integer :: ieq, jvar + real(kind=dp) :: xp(neq), diag(neq) ! real(kind=dp) :: Adag(neq,neq), bdag(neq), res(neq) do ieq=1, neq @@ -1288,14 +1291,24 @@ subroutine multivariate_newton_raphson (neq, df, f, x) enddo enddo + !check sparsity + diag(:) = abs(matdiag(df,neq)) + if (minval(diag)==0.0_dp) then + ! call warning("(Newton-Raphson) df is sparse!") + xp(:) = x(:) + call Jacobi_sparse(df,f,xp,neq) + f(:) = xp(:) + return + endif + ! *********************** ! ! Adag(:,:) = df(:,:) ! bdag(:) = f(:) ! *********************** ! ! call GaussSlv(df,f,neq) - write(*,*) "f=", f - write(*,*) "df=", df + ! write(*,*) "f=", f + ! write(*,*) "df=", df call solve_lin(df,f,neq) if (is_nan_infinity_vector(f)>0) then ! write(*,*) "fdag=", bdag From 0b672be777b538b5aff7cad5e6e974418df52fe4 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Wed, 25 Oct 2023 10:49:08 +0200 Subject: [PATCH 17/46] cleaning --- src/gas/see.f90 | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/gas/see.f90 b/src/gas/see.f90 index cfcefd364..fac2f7ce4 100644 --- a/src/gas/see.f90 +++ b/src/gas/see.f90 @@ -955,12 +955,8 @@ subroutine see_atoms_ne(id,icell,dM,dne) call particle_conservation (icell, Neq_ne, xvar(:,id), fvar(:,id), dfvar(:,:,id)) !newton raphson! - ! write(*,*) id, icell, "T=", T(icell), ne(icell), nHtot(icell) - ! write(*,*) "nstar=", hydrogen%nstar(:,icell) - ! write(*,*) "n=", hydrogen%n(:,icell) call multivariate_newton_raphson (neq_ne, dfvar(:,:,id), fvar(:,id), xvar(:,id)) -! write(*,*) fvar(:,id) -! stop + !update atomic populations and ne neg_pops = .false. i = 1 From 75b9ffd62f9d4f68f96e83f753f08f53cfea7ffb Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 31 Oct 2023 15:58:02 +0100 Subject: [PATCH 18/46] first commint of dust+atom RT --- src/Makefile | 2 +- src/dust_transfer.f90 | 2 +- src/gas/atom_transfer.f90 | 97 +++++++++++++++++++++++++++++++++++-- src/gas/wavelengths_gas.f90 | 10 ++-- src/input.f90 | 14 ++++-- src/mem.f90 | 67 +++++++++++++++++++++++++ src/optical_depth.f90 | 54 ++++++++++----------- src/read_spherical_grid.f90 | 76 +++++++++++++++-------------- 8 files changed, 246 insertions(+), 76 deletions(-) diff --git a/src/Makefile b/src/Makefile index 57c579281..f43b6e839 100644 --- a/src/Makefile +++ b/src/Makefile @@ -235,8 +235,8 @@ SOURCES = mcfost_env.f90 parameters.f90 constants.f90 healpix_mod.f90 sha.f90 me read_DustEM.f90 Temperature.f90 density.f90 read_opacity.f90 scattering.f90 \ read_fargo3d.f90 hdf5_utils.f90 utils_hdf5.f90 read_athena++.f90 \ readVTK.f90 read_idefix.f90 read_pluto.f90 voigts.f90 \ - read1d_models.f90 read_spherical_grid.f90 \ coated_sphere.f90 dust_prop.f90 molecular_emission.f90 PAH.f90 \ + read1d_models.f90 read_spherical_grid.f90 \ input.f90 benchmarks.f90 atom_type.f90 \ wavelengths_gas.f90 broad.f90 \ read_param.f90 dust_ray_tracing.f90 uplow.f90 abo.f90 \ diff --git a/src/dust_transfer.f90 b/src/dust_transfer.f90 index aa4fee60a..038c3d6eb 100644 --- a/src/dust_transfer.f90 +++ b/src/dust_transfer.f90 @@ -763,7 +763,7 @@ subroutine transfert_poussiere() call ecriture_temperature(1) call ecriture_sed(1) - if (lapprox_diffusion.and.l_is_dark_zone.and.(lemission_mol.or.lprodimo.or.lML.or.lforce_diff_approx)) then + if (lapprox_diffusion.and.l_is_dark_zone.and.(lemission_mol.or.lprodimo.or.lML.or.lforce_diff_approx.or.lemission_atom)) then call Temp_approx_diffusion_vertical() ! call Temp_approx_diffusion() call diffusion_approx_nLTE_nRE() diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index 2edc7e1e9..050bb0f85 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -39,6 +39,10 @@ module atom_transfer use messages, only : error, warning use voigts, only : Voigt use broad, only : line_damping + use density, only : densite_pouss + use temperature, only : Tdust + use mem, only : clean_mem_dust_mol, realloc_dust_atom, deallocate_em_th_mol + use dust_prop, only : prop_grains, opacite, init_indices_optiques, kappa_abs_lte, kappa, kappa_factor use healpix_mod !$ use omp_lib @@ -1027,7 +1031,7 @@ subroutine setup_image_grid() !keep somewhere tab_lambda_sed = tab_lambda because tab_lambda is overwritten in non-LTE integer :: kr, nat - call deallocate_wavelengths_gasrt(tab_lambda) + call deallocate_wavelengths_gasrt() call dealloc_atom_opac() call init_directions_ray_tracing() @@ -1054,8 +1058,9 @@ subroutine setup_image_grid() call make_wavelengths_raytracing(tab_lambda_nm) endif n_lambda = size(tab_lambda_nm) - tab_lambda = tab_lambda_nm * nm_to_m!micron + tab_lambda = tab_lambda_nm * m_to_km ! [mic] + call init_dust_atom() !even in 1d mode. call alloc_atom_opac(n_lambda, tab_lambda_nm, .true.) call allocate_atom_maps() if (laccretion_shock) then @@ -1086,6 +1091,14 @@ subroutine atom_line_transfer() tab_lambda_sed = tab_lambda endif + !associate the temperature in the regions where the dusty of dust is non-zero (if any) to the dust + !temperature. + if (maxval(densite_pouss)>0.0_dp) then + call deallocate_em_th_mol() + lscatt_ray_tracing = .false. ! tmp : scatt ray-tracing has no sense yet for atomic emssion + call init_dust_temperature() + endif + !before LTE pops, electronic density and eventually chemical equilibrium. !read atomic models call read_atomic_Models() @@ -1134,10 +1147,12 @@ subroutine atom_line_transfer() !Even if we split the transfer un group of wavelength that's probably best to keep indexes. !otherwise, we pass group wavelength and check contributing opacities for each group !but it is like indexes at the end? - deallocate(tab_lambda, tab_lambda_inf, tab_lambda_sup, tab_delta_lambda) + call deallocate_wavelengths_gasrt() call make_wavelengths_nlte(tab_lambda_nm,vmax_overlap=v_char) n_lambda = size(tab_lambda_nm) - tab_lambda = tab_lambda_nm * m_to_km + tab_lambda = tab_lambda_nm * m_to_km ! [micron] + + call init_dust_atom() ! !allocate quantities in space and for this frequency grid call alloc_atom_opac(n_lambda, tab_lambda_nm, .false.) @@ -1196,6 +1211,78 @@ subroutine atom_line_transfer() return end subroutine atom_line_transfer + subroutine init_dust_temperature() + !lowering too much the treshold might create some convergence issues in the non-LTE pops or in + ! the electronic density calculations (0 division mainly for low values). + real(kind=dp), parameter :: T_formation = 1500.0 ! [K] + write(*,*) " *** Associating the dust temperature in the model..." + !If the dust temperature is above T_formation the gas will follow that temperature + !and atomic opacities will be considered. + write(*,*) "Tdust:", maxval(Tdust), minval(Tdust) + where(sum(densite_pouss,dim=1) > 0.0_dp) T(:) = Tdust(:) + if (any(T < T_formation)) call warning('(atom_transfer) Setting the gas transparent where T < 1500 K.') + where (T < T_formation) icompute_atomRT = 0 + if (any(icompute_atomRT>0)) then + write(*,*) "T:", maxval(T,icompute_atomRT>0), minval(T,icompute_atomRT>0) + else + call warning("(init_dust_temperature) The (atomic) gas is all transparent in dusty regions !") + endif + write(*,*) " *** done." + return + end subroutine init_dust_temperature + + subroutine init_dust_atom() + use scattering + !see mol_transfer.f90 / init_dust_mol() for TO DOs. + logical :: ldust_atom + integer :: la, p_lambda + integer, target :: icell + integer, pointer :: p_icell + + ldust_atom = (maxval(densite_pouss) > 0.0_dp) + + if (.not.ldust_atom) return ! not dust + !init anyways the dust opac ? ? + + ! On n'est interesse que par les prop d'abs : pas besoin des matrices de mueller + ! -> pas de polarisation, on utilise une HG + scattering_method=1 ; lscattering_method1 = .true. ; p_lambda = 1 + aniso_method = 2 ; lmethod_aniso1 = .false. + lsepar_pola = .false. + ltemp = .false. + lmono = .true. ! equivalent au mode sed2 + + if (lvariable_dust) then + p_icell => icell + else + p_icell => icell_ref + endif + + call realloc_dust_atom() + + !BEWARE: by default tab_lambda is associated to tab_lambda_nm which can be long. + ! Consider using tab_lambda_cont and then interpolate on tab_lambda_nm + write(*,*) " *** initialising optical indices" + call init_indices_optiques() + + ! Computing optical dust properties + write(*,*) " *** Computing dust properties for", n_lambda, "wavelengths..." + do la=1, n_lambda !works also for ray-traced lines + call prop_grains(la) + call opacite(la, la, no_scatt=.true.) + enddo +!introduce switch for continuum + ! cell_loop : do icell=1, n_cells + ! if (maxval(densite_pouss(:,icell)) <= 0.0) cycle cell_loop + ! !here T (icell) is Tdust(icell) + ! ! chi_c(:,icell) = kappa(p_icell,:) ! [m^-1] + ! eta_cont(:,icell) = kappa_abs_LTE(p_icell,:) * kappa_factor(icell) * Bpnu(n_lambda,tab_lambda_nm,T(icell)) ![W/m^3/Hz/sr] + ! enddo cell_loop + + call clean_mem_dust_mol() + write(*,*) " *** done." + return + end subroutine init_dust_atom subroutine intensite_pixel_atom(id,ibin,iaz,n_iter_min,n_iter_max,ipix,jpix,pixelcorner,pixelsize,dx,dy,u,v,w) ! -------------------------------------------------------------- ! @@ -1619,7 +1706,7 @@ subroutine spectrum_1d() allocate(cos_theta(Nimpact), weight_mu(Nimpact), p(Nimpact)) !prepare wavelength grid and indexes for continua and lines !including max extension due to velocity shiftS. - call deallocate_wavelengths_gasrt(tab_lambda) + call deallocate_wavelengths_gasrt() call dealloc_atom_opac() if (lsed) then call make_wavelengths_flux(tab_lambda_sed,.true.) diff --git a/src/gas/wavelengths_gas.f90 b/src/gas/wavelengths_gas.f90 index eed7d2a23..0ae9c86d8 100644 --- a/src/gas/wavelengths_gas.f90 +++ b/src/gas/wavelengths_gas.f90 @@ -258,9 +258,13 @@ function line_lambda_grid_dv(line,Nlambda) return end function line_lambda_grid_dv - subroutine deallocate_wavelengths_gasrt(lambda) - real(kind=dp), intent(inout), allocatable, dimension(:) :: lambda - if (allocated(lambda)) deallocate(lambda) + subroutine deallocate_wavelengths_gasrt()!(lambda) + use wavelengths, only : n_lambda, tab_lambda, tab_lambda_inf, tab_lambda_sup, tab_delta_lambda, n_lambda2, tab_lambda2 + ! real(kind=dp), intent(inout), allocatable, dimension(:) :: lambda + if (allocated(tab_lambda)) then !lambda + deallocate(tab_lambda) !lambda + deallocate(tab_lambda_inf, tab_lambda_sup, tab_delta_lambda) + endif if (allocated(tab_lambda_nm)) deallocate(tab_lambda_cont, tab_lambda_nm) !deallocate atom grid.. !deallocate group.. diff --git a/src/input.f90 b/src/input.f90 index 365b7e851..8ac85fe55 100644 --- a/src/input.f90 +++ b/src/input.f90 @@ -181,9 +181,17 @@ subroutine lect_Temperature() integer :: status, readwrite, unit, blocksize,nfound,group,firstpix,nbuffer,npixels, hdutype real :: nullval integer, dimension(5) :: naxes - logical :: anynull - - if (lemission_atom) return !B. Tessore., Temporary + logical :: anynull, there_is_dust + + !future: lgas_transfer. Dust could not always be present in the gas RT. + if (lemission_atom) then + !note sure the test on ltemp is necessary here + there_is_dust = (maxval(densite_pouss) > 0_dp) + if ( (.not.ltemp).and.(.not.there_is_dust) ) then + call warning("(lect_Temperature) Do not attempt to read Tdust file when there is not dust!") + return + endif + endif if (lRE_LTE) then status=0 diff --git a/src/mem.f90 b/src/mem.f90 index 2593f612a..12e61c9da 100644 --- a/src/mem.f90 +++ b/src/mem.f90 @@ -444,6 +444,73 @@ subroutine clean_mem_dust_mol() end subroutine clean_mem_dust_mol +subroutine realloc_dust_atom() +!this routine should be the mirror of the mol one, except for the tab_lambda which is allocated +!when the gas atom RT grid is defined (from reading the atomic species). +!Still, the test on the allocation and the call of clean_mem_dust_mol in init_dust_atom means +!that theya re not deallocated after temperature calculation. What am I missing ? + +! use stars, only : allocate_stellar_spectra !-> not use yet in atom transfer. + + + integer :: alloc_status + real :: mem_size + + + !Note: tab_lambda(n_lambda) is already allocated in atomic_transfer + ! the tab_lambda_* or tab_delta_lambda should be de-allocated when tab_lambda is allocated in atom_rt. + allocate(tab_lambda_inf(n_lambda), tab_lambda_sup(n_lambda), tab_delta_lambda(n_lambda), & + tab_amu1(n_lambda, n_pop), tab_amu2(n_lambda, n_pop), & + tab_amu1_coating(n_lambda, n_pop), tab_amu2_coating(n_lambda, n_pop), stat=alloc_status) + if (alloc_status > 0) call error('Allocation error tab_lambda (realloc)') +! tab_lambda=0.0 + tab_lambda_inf = 0.0 ; tab_lambda_sup = 0.0 ; tab_delta_lambda= 0.0 ; + tab_amu1=0.0 ; tab_amu2=0.0 ; tab_amu1_coating=0.0 ; tab_amu2_coating=0.0 + + allocate(tab_albedo(n_grains_tot,n_lambda), stat=alloc_status) + if (alloc_status > 0) call error('Allocation error tab_albedo (realloc)') + tab_albedo = 0 + + allocate(C_ext(n_grains_tot,n_lambda), C_sca(n_grains_tot,n_lambda), & + C_abs(n_grains_tot,n_lambda), C_abs_norm(n_grains_tot,n_lambda), tab_g(n_grains_tot,n_lambda), stat=alloc_status) + if (alloc_status > 0) call error('Allocation error C_ext (realloc)') + C_ext = 0 ; C_sca = 0 ; C_abs = 0 ; C_abs_norm = 0 ; tab_g = 0 + + ! Tableaux relatifs aux prop optiques des cellules + if (allocated(kappa)) deallocate(kappa) + if (allocated(kappa_abs_LTE)) deallocate(kappa_abs_LTE) + if (allocated(kappa_factor)) deallocate(kappa_factor) + allocate(kappa(p_n_cells,n_lambda),kappa_abs_LTE(p_n_cells,n_lambda), kappa_factor(n_cells), stat=alloc_status) + if (alloc_status > 0) call error('Allocation error emissivite_dust (realloc atom)') + kappa = 0.0 ; kappa_abs_LTE = 0.0 + !emissivite_dust(n_cells,n_lambda),emissivite_dust = 0.0 + !I don't store the dust emissivity in a separate array. + + if (lRE_nLTE) then + if (allocated(kappa_abs_nlte)) deallocate(kappa_abs_nlte) + allocate(kappa_abs_nLTE(p_n_cells,n_lambda), stat=alloc_status) + if (alloc_status > 0) call error('Allocation error kappa_abs_nLTE (realloc atom)') + kappa_abs_nLTE = 0.0 + endif + + allocate(tab_albedo_pos(p_n_cells,n_lambda),stat=alloc_status) + if (alloc_status > 0) call error('Allocation error tab_albedo_pos (realloc atom)') + tab_albedo_pos = 0 + + if (aniso_method==2) then + allocate(tab_g_pos(p_n_cells,n_lambda),stat=alloc_status) + if (alloc_status > 0) call error('Allocation error tab_g_pos (realloc atom)') + tab_g_pos = 0.0 + endif + +! call allocate_stellar_spectra(n_lambda) + + return + +end subroutine realloc_dust_atom + +!****************************************************************************** + !****************************************************************************** subroutine realloc_step2() diff --git a/src/optical_depth.f90 b/src/optical_depth.f90 index 1f3f8dccf..61fb0cddb 100644 --- a/src/optical_depth.f90 +++ b/src/optical_depth.f90 @@ -1101,7 +1101,9 @@ subroutine integ_ray_atom(id,icell_in,x,y,z,u,v,w,iray,labs,N,lambda) real(kind=dp), dimension(N), intent(in) :: lambda real(kind=dp) :: x0, y0, z0, x1, y1, z1, l, l_contrib, l_void_before, Q, P(4) real(kind=dp), dimension(N) :: Snu, tau, dtau, chi, coronal_irrad - integer :: nbr_cell, icell, next_cell, previous_cell, icell_star, i_star, la, icell_prev + integer, target :: icell + integer, pointer :: p_icell + integer :: nbr_cell, next_cell, previous_cell, icell_star, i_star, la, icell_prev logical :: lcellule_non_vide, lsubtract_avg, lintersect_stars x1=x;y1=y;z1=z @@ -1114,6 +1116,9 @@ subroutine integ_ray_atom(id,icell_in,x,y,z,u,v,w,iray,labs,N,lambda) Itot(:,iray,id) = 0.0_dp + p_icell => icell_ref + if (lvariable_dust) p_icell => icell + ! Will the ray intersect a star call intersect_stars(x,y,z, u,v,w, lintersect_stars, i_star, icell_star) ! Boucle infinie sur les cellules (we go over the grid.) @@ -1123,11 +1128,6 @@ subroutine integ_ray_atom(id,icell_in,x,y,z,u,v,w,iray,labs,N,lambda) x0=x1 ; y0=y1 ; z0=z1 lcellule_non_vide = (icell <= n_cells) - ! if (icell <= n_cells) then - ! lcellule_non_vide=.true. - ! else - ! lcellule_non_vide=.false. - ! endif ! Test sortie ! "The ray has reach the end of the grid" if (test_exit_grid(icell, x0, y0, z0)) return @@ -1139,23 +1139,15 @@ subroutine integ_ray_atom(id,icell_in,x,y,z,u,v,w,iray,labs,N,lambda) return end if endif - !With the Voronoi grid, somme cells can have a negative index - !therefore we need to test_exit_grid before using icompute_atom_rt - if (icell <= n_cells) then - lcellule_non_vide = (icompute_atomRT(icell) > 0) - if (icompute_atomRT(icell) < 0) then - if (icompute_atomRT(icell) == -1) then - !If the optically thick region (dark zone) has a temperature - !add a black body emission and leave. - if (T(icell) > 0.0_dp) Itot(:,iray,id) = Itot(:,iray,id) + & - exp(-tau) * Bpnu(N,lambda,T(icell)) - return - else - !Does not return but cell is empty (lcellule_non_vide is .false.) - coronal_irrad = linear_1D_sorted(atmos_1d%Ncorona,atmos_1d%x_coro(:), & + + !Special handling of coronal irradiation from "above". + if (lcellule_non_vide) then + if (icompute_atomRT(icell) == -2) then + !Does not return but cell is empty (lcellule_non_vide is .false.) + coronal_irrad = linear_1D_sorted(atmos_1d%Ncorona,atmos_1d%x_coro(:), & atmos_1d%I_coro(:,1),N,lambda) - Itot(:,iray,id) = Itot(:,iray,id) + exp(-tau) * coronal_irrad - endif + Itot(:,iray,id) = Itot(:,iray,id) + exp(-tau) * coronal_irrad + lcellule_non_vide = .false. endif endif @@ -1168,12 +1160,20 @@ subroutine integ_ray_atom(id,icell_in,x,y,z,u,v,w,iray,labs,N,lambda) !count opacity only if the cell is filled, else go to next cell if (lcellule_non_vide) then lsubtract_avg = ((nbr_cell == 1).and.labs) + chi(:) = 1d-300 + Snu(:) = 0.0 ! opacities in m^-1, l_contrib in au - - call contopac_atom_loc(icell, N, lambda, chi, Snu) - call opacity_atom_bb_loc(id,icell,iray,x0,y0,z0,x1,y1,z1,u,v,w,& - l_void_before,l_contrib,lsubtract_avg,N,lambda,chi,Snu) + if (icompute_atomRT(icell) > 0) then + !re-init chi + call contopac_atom_loc(icell, N, lambda, chi, Snu) + call opacity_atom_bb_loc(id,icell,iray,x0,y0,z0,x1,y1,z1,u,v,w,& + l_void_before,l_contrib,lsubtract_avg,N,lambda,chi,Snu) + endif + if (maxval(densite_pouss(:,icell))>0) then + chi(:) = chi(:) + kappa(p_icell,:) * kappa_factor(icell) * m_to_AU ! [m^-1] + Snu(:) = Snu(:) + kappa_abs_LTE(p_icell,:) * kappa_factor(icell) * m_to_AU * Bpnu(N,lambda,T(icell)) ! [W m^-3 Hz^-1 sr^-1] + endif dtau(:) = l_contrib * chi(:) * AU_to_m !au * m^-1 * au_to_m @@ -1188,7 +1188,7 @@ subroutine integ_ray_atom(id,icell_in,x,y,z,u,v,w,iray,labs,N,lambda) Snu = Snu / chi - Itot(:,iray,id) = Itot(:,iray,id) + exp(-tau) * (1.0_dp - exp(-dtau)) * Snu + Itot(:,iray,id) = Itot(:,iray,id) + Snu!exp(-tau) * (1.0_dp - exp(-dtau)) * Snu tau(:) = tau(:) + dtau(:) !for next cell end if ! lcellule_non_vide diff --git a/src/read_spherical_grid.f90 b/src/read_spherical_grid.f90 index eb72fefd7..87025a995 100644 --- a/src/read_spherical_grid.f90 +++ b/src/read_spherical_grid.f90 @@ -14,6 +14,7 @@ module read_spherical_grid use utils use cylindrical_grid use density + use dust_prop, only : dust_pop use stars, only : T_hp, T_preshock use read1d_models, only : print_info_model @@ -40,6 +41,7 @@ subroutine read_spherical_grid_parameters(filename) vfield_coord = 3 ! spherical grid_type = 2 n_rad_in = 1 + n_zones = 1 open(unit=1, file=trim(filename), status="old",access="stream",form='unformatted') !read size along each direction + cell limits (size + 1) @@ -105,14 +107,14 @@ subroutine read_spherical_grid_parameters(filename) if (l3d) then nz = pluto%nx2/2 if (mod(pluto%nx2,2)>0) call warning("odd nx2") - ! dphi = pluto%x3(2) - pluto%x3(1) - ! do i=2, size(pluto%x3) - ! if ( abs((pluto%x3(i) - pluto%x3(i-1)) - dphi) > 1e-6 ) then - ! write(*,*) dphi, (pluto%x3(i) - pluto%x3(i-1)),abs((pluto%x3(i) - pluto%x3(i-1)) - dphi) - ! call error("(spherical input grid) Non-linear phi space is not allowed!") - ! endif - ! dphi = pluto%x3(i) - pluto%x3(i-1) - ! enddo + dphi = pluto%x3(2) - pluto%x3(1) + do i=2, size(pluto%x3) + if ( abs((pluto%x3(i) - pluto%x3(i-1)) - dphi) > 1e-6 ) then + write(*,*) dphi, (pluto%x3(i) - pluto%x3(i-1)),abs((pluto%x3(i) - pluto%x3(i-1)) - dphi) + call error("(spherical input grid) Non-linear phi space is not allowed!") + endif + dphi = pluto%x3(i) - pluto%x3(i-1) + enddo endif Nsize = pluto%nx2 * pluto%nx3 * pluto%nx1 @@ -130,11 +132,12 @@ subroutine read_spherical_model(filename) character(len=*), intent(in) :: filename integer :: ios, i, Nsize - integer :: j, k, jj, icell + integer :: j, k, jj, icell, read_dust integer, allocatable :: dz(:,:,:) real, allocatable :: vtmp(:,:,:,:) - real(kind=dp), allocatable :: rho(:,:,:), T_tmp(:,:,:), ne_tmp(:,:,:), vt_tmp(:,:,:) - real(kind=dp) :: mass, facteur + real(kind=dp), allocatable :: rho(:,:,:), rho_dust(:,:,:) + real(kind=dp), allocatable :: T_tmp(:,:,:), ne_tmp(:,:,:), vt_tmp(:,:,:) + real(kind=dp) :: mass, disk_dust_mass call alloc_atomrt_grid call read_abundance !can be move in atom_transfer, but then rho must be changed in nHtot @@ -167,8 +170,15 @@ subroutine read_spherical_model(filename) read(1, iostat=ios) vtmp(:,:,:,:) read(1, iostat=ios) vt_tmp(:,:,:) read(1, iostat=ios) dz(:,:,:) + read(1, iostat=ios) read_dust + !read total dust density + if (read_dust > 0) then + allocate(rho_dust(pluto%nx1,pluto%nx2,pluto%nx3)) + read(1, iostat=ios) rho_dust(:,:,:) + endif close(unit=1) + densite_pouss = 0.0_dp ! init just in case. do i=1, n_rad j = 0 bz : do jj=j_start+1,nz-1 ! 1 extra empty cell in theta on each side @@ -177,42 +187,36 @@ subroutine read_spherical_model(filename) do k=1, n_az icell = cell_map(i,jj,k) T(icell) = T_tmp(i,j,k) - nHtot(icell) = rho(i,j,k) * 1d3 / masseH / wght_per_H - densite_gaz(icell) = rho(i,j,k) * 1d3 !for dust, in [g] - !At the moment the dust density / properties / g/d ratio are - !set from the parameter file and not read from the binary model. - densite_pouss(:,icell) = densite_gaz(icell) + nHtot(icell) = rho(i,j,k) * 1d3 / masseH / wght_per_H ! [m^-3] icompute_atomRT(icell) = dz(i,j,k) vfield3d(icell,:) = vtmp(i,j,k,:) + + !-> wrapper for dust RT. + densite_gaz(icell) = nHtot(icell) * wght_per_H + if (read_dust > 0) densite_pouss(:,icell) = rho_dust(i,j,k) * 1d3 / masseH ! [m^-3] enddo enddo bz enddo deallocate(rho,ne_tmp,T_tmp,vt_tmp,dz,vtmp) + if (allocated(rho_dust)) deallocate(rho_dust) !dust part see read_pluto.f90 ! ********************************** ! - mass = 0. !in g/m^3, volume in AU^3 - do icell=1,n_cells - mass = mass + densite_gaz(icell) * volume(icell) - enddo !icell - mass = mass * AU3_to_m3 * g_to_Msun !in Msun - - ! Normalisation - if (mass > 0.0) then ! pour le cas ou gas_to_dust = 0. - facteur = disk_zone(1)%diskmass * disk_zone(1)%gas_to_dust / mass - - ! Somme sur les zones pour densite finale - do icell=1,n_cells - densite_gaz(icell) = 1d-3 * densite_gaz(icell) * facteur !g/AU^3 - masse_gaz(icell) = densite_gaz(icell) * volume(icell) * AU3_to_m3 !g - nHtot(icell) = nHtot(icell) * facteur !for consistency - enddo ! icell - else - call error('Gas mass is 0') - endif + !technically is it masseH or masse_mol_gaz for H2 ? + mass = sum(densite_gaz * volume) * AU3_to_m3 * masseH * g_to_Msun + if (mass <= 0.0) call error('Gas mass is 0') + masse_gaz(:) = masseH * densite_gaz(:) * volume(:) * AU3_to_m3 ! [g] + + disk_dust_mass = sum(densite_pouss(1,:)*volume) * AU3_to_m3 * masseH * g_to_Msun + + !--> no normalisation of density. The dust and gas densities are provided in the model. write(*,*) 'Total gas mass in model:', real(sum(masse_gaz) * g_to_Msun),' Msun' - call normalize_dust_density() + ! write(*,*) 'Total dust mass in model:', real(disk_dust_mass),' Msun' + if (disk_dust_mass > 0.0_dp) then + dust_pop(:)%masse = disk_dust_mass + call normalize_dust_density(disk_dust_mass) + endif ! ********************************** ! call check_for_zero_electronic_density() From c63bd03999182f55c89f461a34b48e4f95868918 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 31 Oct 2023 16:02:00 +0100 Subject: [PATCH 19/46] cleaning --- src/voigts.f90 | 45 --------------------------------------------- 1 file changed, 45 deletions(-) diff --git a/src/voigts.f90 b/src/voigts.f90 index b2eba4076..610ce91a3 100644 --- a/src/voigts.f90 +++ b/src/voigts.f90 @@ -153,49 +153,4 @@ function dmax_lorentz(vth, a, eps) return end function dmax_lorentz - !building - function VoigtAller(N,a,v) - integer, intent(in) :: N - real(kind=dp), intent(in) :: a, v(N) - real(kind=dp) :: VoigtAller(N) - integer :: i,j - real(kind=dp) :: sum1, base - complex(kind=dp) :: ksi, sum2 - - if (a <= 0.1) then - do i=1,N - if (abs(v(i)) >= 2.5) then - base = (1.0+a*a*(1-2*v(i)**2))*exp(-v(i)**2) - sum1 = 0 - do j=1,7 - sum1 = sum1 + cj(j)*v(i)**(-2*(j-1)) - enddo - VoigtAller(i) = a/v(i)/v(i) * sum1 + base - else - ksi = cmplx(a, -v(i)) - sum1 = 0 - sum2 = ksi**7 - do j=1,7 - sum1 = sum1 + Aj(j)*ksi**(j-1) - sum2 = sum2 + Bj(j)*ksi**(j-1) - enddo - VoigtAller(i) = real(sum1/sum2, kind=dp) - endif - enddo - else - do i=1,N - ksi = cmplx(a, -v(i)) - sum1 = 0 - sum2 = ksi**7 - do j=1,7 - sum1 = sum1 + Aj(j)*ksi**(j-1) - sum2 = sum2 + Bj(j)*ksi**(j-1) - enddo - VoigtAller(i) = real(sum1/sum2, kind=dp) - enddo - endif - - return - end function VoigtAller - end module voigts \ No newline at end of file From 7bfd7ae3a23b1b64ff82d93a8051d7ab84a8dc40 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 31 Oct 2023 19:12:21 +0100 Subject: [PATCH 20/46] fix issue + ldust_atom flag. adding a temp flag ldust_atom to add dust opacities during the propagation in atomic RT mode. --- src/gas/atom_transfer.f90 | 28 +++++++++++----------------- src/optical_depth.f90 | 14 ++++++++------ src/parameters.f90 | 2 +- src/read_spherical_grid.f90 | 2 ++ 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index 050bb0f85..1a70b0072 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -39,7 +39,6 @@ module atom_transfer use messages, only : error, warning use voigts, only : Voigt use broad, only : line_damping - use density, only : densite_pouss use temperature, only : Tdust use mem, only : clean_mem_dust_mol, realloc_dust_atom, deallocate_em_th_mol use dust_prop, only : prop_grains, opacite, init_indices_optiques, kappa_abs_lte, kappa, kappa_factor @@ -1093,7 +1092,7 @@ subroutine atom_line_transfer() !associate the temperature in the regions where the dusty of dust is non-zero (if any) to the dust !temperature. - if (maxval(densite_pouss)>0.0_dp) then + if (ldust_atom) then call deallocate_em_th_mol() lscatt_ray_tracing = .false. ! tmp : scatt ray-tracing has no sense yet for atomic emssion call init_dust_temperature() @@ -1212,6 +1211,7 @@ subroutine atom_line_transfer() end subroutine atom_line_transfer subroutine init_dust_temperature() + use density, only : densite_pouss !lowering too much the treshold might create some convergence issues in the non-LTE pops or in ! the electronic density calculations (0 division mainly for low values). real(kind=dp), parameter :: T_formation = 1500.0 ! [K] @@ -1234,15 +1234,15 @@ end subroutine init_dust_temperature subroutine init_dust_atom() use scattering !see mol_transfer.f90 / init_dust_mol() for TO DOs. - logical :: ldust_atom integer :: la, p_lambda integer, target :: icell integer, pointer :: p_icell - ldust_atom = (maxval(densite_pouss) > 0.0_dp) - - if (.not.ldust_atom) return ! not dust - !init anyways the dust opac ? ? + if (.not.ldust_atom) then + !still add kappa etc in the total contopac to not care about testing if dust + !in the propagation (+limit_mem options). + return ! no dust + endif ! On n'est interesse que par les prop d'abs : pas besoin des matrices de mueller ! -> pas de polarisation, on utilise une HG @@ -1266,18 +1266,12 @@ subroutine init_dust_atom() call init_indices_optiques() ! Computing optical dust properties + ! TO DO: limit_mem options. write(*,*) " *** Computing dust properties for", n_lambda, "wavelengths..." do la=1, n_lambda !works also for ray-traced lines call prop_grains(la) call opacite(la, la, no_scatt=.true.) enddo -!introduce switch for continuum - ! cell_loop : do icell=1, n_cells - ! if (maxval(densite_pouss(:,icell)) <= 0.0) cycle cell_loop - ! !here T (icell) is Tdust(icell) - ! ! chi_c(:,icell) = kappa(p_icell,:) ! [m^-1] - ! eta_cont(:,icell) = kappa_abs_LTE(p_icell,:) * kappa_factor(icell) * Bpnu(n_lambda,tab_lambda_nm,T(icell)) ![W/m^3/Hz/sr] - ! enddo cell_loop call clean_mem_dust_mol() write(*,*) " *** done." @@ -1375,16 +1369,16 @@ subroutine intensite_pixel_atom(id,ibin,iaz,n_iter_min,n_iter_max,ipix,jpix,pixe ! Prise en compte de la surface du pixel (en sr) ! Flux out of a pixel in W/m2/Hz/pix - normF = ( pixelsize / (distance*pc_to_AU) )**2 + normF = c_light / nm_to_m * ( pixelsize / (distance*pc_to_AU) )**2 if (RT_line_method==1) then - Flux_total(:,ibin,iaz,id) = Flux_total(:,ibin,iaz,id) + I0(:) * normF + Flux_total(:,ibin,iaz,id) = Flux_total(:,ibin,iaz,id) + I0(:) * normF / tab_lambda_nm else do nat=1,N_atoms atom => atoms(nat)%p do kr=1,atom%nTrans_rayTracing krr = atom%ij_to_trans(atom%i_Trans_rayTracing(kr),atom%j_Trans_rayTracing(kr)) - atom%lines(krr)%map(ipix,jpix,:,ibin,iaz) = I0(atom%lines(krr)%nb:atom%lines(krr)%nr)*normF + atom%lines(krr)%map(ipix,jpix,:,ibin,iaz) = I0(atom%lines(krr)%nb:atom%lines(krr)%nr)*normF/ tab_lambda_nm(atom%lines(krr)%nb:atom%lines(krr)%nr) enddo atom => NULL() enddo diff --git a/src/optical_depth.f90 b/src/optical_depth.f90 index 61fb0cddb..8c42ca1ca 100644 --- a/src/optical_depth.f90 +++ b/src/optical_depth.f90 @@ -1141,6 +1141,7 @@ subroutine integ_ray_atom(id,icell_in,x,y,z,u,v,w,iray,labs,N,lambda) endif !Special handling of coronal irradiation from "above". + !mainly for 1d stellar atmosphere if (lcellule_non_vide) then if (icompute_atomRT(icell) == -2) then !Does not return but cell is empty (lcellule_non_vide is .false.) @@ -1160,8 +1161,7 @@ subroutine integ_ray_atom(id,icell_in,x,y,z,u,v,w,iray,labs,N,lambda) !count opacity only if the cell is filled, else go to next cell if (lcellule_non_vide) then lsubtract_avg = ((nbr_cell == 1).and.labs) - chi(:) = 1d-300 - Snu(:) = 0.0 + chi(:) = 1d-300; Snu(:) = 0.0_dp ! opacities in m^-1, l_contrib in au if (icompute_atomRT(icell) > 0) then @@ -1170,9 +1170,11 @@ subroutine integ_ray_atom(id,icell_in,x,y,z,u,v,w,iray,labs,N,lambda) call opacity_atom_bb_loc(id,icell,iray,x0,y0,z0,x1,y1,z1,u,v,w,& l_void_before,l_contrib,lsubtract_avg,N,lambda,chi,Snu) endif - if (maxval(densite_pouss(:,icell))>0) then - chi(:) = chi(:) + kappa(p_icell,:) * kappa_factor(icell) * m_to_AU ! [m^-1] - Snu(:) = Snu(:) + kappa_abs_LTE(p_icell,:) * kappa_factor(icell) * m_to_AU * Bpnu(N,lambda,T(icell)) ! [W m^-3 Hz^-1 sr^-1] + !TO DO: move to the total contopac & + ! do not initialize chi, Snu in background but update them instead. + if (ldust_atom) then + chi = chi + kappa(p_icell,:) * kappa_factor(icell) * m_to_AU ! [m^-1] + Snu = Snu + kappa_abs_LTE(p_icell,:) * kappa_factor(icell) * m_to_AU * Bpnu(N,lambda,T(icell)) ! [W m^-3 Hz^-1 sr^-1] endif dtau(:) = l_contrib * chi(:) * AU_to_m !au * m^-1 * au_to_m @@ -1188,7 +1190,7 @@ subroutine integ_ray_atom(id,icell_in,x,y,z,u,v,w,iray,labs,N,lambda) Snu = Snu / chi - Itot(:,iray,id) = Itot(:,iray,id) + Snu!exp(-tau) * (1.0_dp - exp(-dtau)) * Snu + Itot(:,iray,id) = Itot(:,iray,id) + exp(-tau) * (1.0_dp - exp(-dtau)) * Snu tau(:) = tau(:) + dtau(:) !for next cell end if ! lcellule_non_vide diff --git a/src/parameters.f90 b/src/parameters.f90 index 8305898d2..c2ae788f3 100644 --- a/src/parameters.f90 +++ b/src/parameters.f90 @@ -63,7 +63,7 @@ module parametres ! Atomic line radiative transfer logical :: lexit_after_nonlte_loop, lstop_after_jnu logical :: lemission_atom, lelectron_scattering, lforce_lte, & - ldissolve, loutput_rates, lzeeman_polarisation + ldissolve, loutput_rates, lzeeman_polarisation, ldust_atom integer :: N_rayons_mc, istep_start, istep_end !HEALpix diff --git a/src/read_spherical_grid.f90 b/src/read_spherical_grid.f90 index 87025a995..e3a30f992 100644 --- a/src/read_spherical_grid.f90 +++ b/src/read_spherical_grid.f90 @@ -216,6 +216,8 @@ subroutine read_spherical_model(filename) if (disk_dust_mass > 0.0_dp) then dust_pop(:)%masse = disk_dust_mass call normalize_dust_density(disk_dust_mass) + ldust_atom = .false. !tmp here, to move once opacity are added to contopac (adding 0 if no dust) + if (lemission_atom) ldust_atom = .true. endif ! ********************************** ! From 2482be899698ff2f34dbb0acccb995060ccb7801 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 31 Oct 2023 22:43:31 +0100 Subject: [PATCH 21/46] storing dust emissivity on memory --- src/gas/atom_transfer.f90 | 12 +++++++++--- src/mem.f90 | 10 ++++++++-- src/optical_depth.f90 | 6 +++--- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index 1a70b0072..c92c99605 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -39,9 +39,11 @@ module atom_transfer use messages, only : error, warning use voigts, only : Voigt use broad, only : line_damping + use density, only : densite_pouss use temperature, only : Tdust - use mem, only : clean_mem_dust_mol, realloc_dust_atom, deallocate_em_th_mol + use mem, only : clean_mem_dust_mol, realloc_dust_atom, deallocate_em_th_mol,emissivite_dust use dust_prop, only : prop_grains, opacite, init_indices_optiques, kappa_abs_lte, kappa, kappa_factor + use scattering use healpix_mod !$ use omp_lib @@ -1211,7 +1213,6 @@ subroutine atom_line_transfer() end subroutine atom_line_transfer subroutine init_dust_temperature() - use density, only : densite_pouss !lowering too much the treshold might create some convergence issues in the non-LTE pops or in ! the electronic density calculations (0 division mainly for low values). real(kind=dp), parameter :: T_formation = 1500.0 ! [K] @@ -1232,7 +1233,6 @@ subroutine init_dust_temperature() end subroutine init_dust_temperature subroutine init_dust_atom() - use scattering !see mol_transfer.f90 / init_dust_mol() for TO DOs. integer :: la, p_lambda integer, target :: icell @@ -1273,6 +1273,12 @@ subroutine init_dust_atom() call opacite(la, la, no_scatt=.true.) enddo + do icell=1, n_cells + if (sum(densite_pouss(:,icell)) <= 0.0_dp) cycle + emissivite_dust(:,icell) = kappa_abs_LTE(p_icell,:) * kappa_factor(icell) * & + m_to_AU * Bpnu(n_lambda,tab_lambda_nm,T(icell)) ! [W m^-3 Hz^-1 sr^-1] + enddo + call clean_mem_dust_mol() write(*,*) " *** done." return diff --git a/src/mem.f90 b/src/mem.f90 index 12e61c9da..b886fd1eb 100644 --- a/src/mem.f90 +++ b/src/mem.f90 @@ -483,8 +483,14 @@ subroutine realloc_dust_atom() allocate(kappa(p_n_cells,n_lambda),kappa_abs_LTE(p_n_cells,n_lambda), kappa_factor(n_cells), stat=alloc_status) if (alloc_status > 0) call error('Allocation error emissivite_dust (realloc atom)') kappa = 0.0 ; kappa_abs_LTE = 0.0 - !emissivite_dust(n_cells,n_lambda),emissivite_dust = 0.0 - !I don't store the dust emissivity in a separate array. + !mind the shape of the array compared to the others. + if (allocated(emissivite_dust)) deallocate(emissivite_dust) + allocate(emissivite_dust(n_lambda,n_cells),stat=alloc_status) + if (alloc_status > 0) call error('Allocation error emissivite_dust (realloc atom)') + if (sizeof(emissivite_dust)/1024.**3 > 5) then + write(*,*) " WARNING: using ", sizeof(emissivite_dust)/1024.**3, " GB for emissivite_dust" + endif + emissivite_dust = 0.0 if (lRE_nLTE) then if (allocated(kappa_abs_nlte)) deallocate(kappa_abs_nlte) diff --git a/src/optical_depth.f90 b/src/optical_depth.f90 index 8c42ca1ca..7b16717be 100644 --- a/src/optical_depth.f90 +++ b/src/optical_depth.f90 @@ -1087,11 +1087,10 @@ end subroutine optical_length_tot_mol !******************************************************************** subroutine integ_ray_atom(id,icell_in,x,y,z,u,v,w,iray,labs,N,lambda) ! ------------------------------------------------------------------------------- ! - ! TO DO: merge integ_ray_atom + integ_ray_line + ! TO DO: merge integ_ray_atom + integ_ray_mol ! Zeeman ! scattering ! level dissolution - ! dust ! ------------------------------------------------------------------------------- ! integer, intent(in) :: id, icell_in, iray real(kind=dp), intent(in) :: u,v,w @@ -1174,7 +1173,8 @@ subroutine integ_ray_atom(id,icell_in,x,y,z,u,v,w,iray,labs,N,lambda) ! do not initialize chi, Snu in background but update them instead. if (ldust_atom) then chi = chi + kappa(p_icell,:) * kappa_factor(icell) * m_to_AU ! [m^-1] - Snu = Snu + kappa_abs_LTE(p_icell,:) * kappa_factor(icell) * m_to_AU * Bpnu(N,lambda,T(icell)) ! [W m^-3 Hz^-1 sr^-1] + ! Snu = Snu + kappa_abs_LTE(p_icell,:) * kappa_factor(icell) * m_to_AU * Bpnu(N,lambda,T(icell)) ! [W m^-3 Hz^-1 sr^-1] + Snu = Snu + emissivite_dust(:,icell) ! [W m^-3 Hz^-1 sr^-1] endif dtau(:) = l_contrib * chi(:) * AU_to_m !au * m^-1 * au_to_m From 8c5267f1fd660acf884b2d494eb6921b6c5dca11 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Wed, 1 Nov 2023 15:03:19 +0100 Subject: [PATCH 22/46] cleaning --- src/stars.f90 | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/stars.f90 b/src/stars.f90 index 1879e4282..54842788a 100644 --- a/src/stars.f90 +++ b/src/stars.f90 @@ -6,7 +6,6 @@ module stars use messages use wavelengths use grid - use elements_type, only : wght_per_H implicit none @@ -949,10 +948,12 @@ function is_inshock(id, iray, i_star, icell0, x, y, z, Thp, Tshock, Facc) ! use grid, only : voronoi use constantes, only : sigma, kb + use elements_type, only : wght_per_H + ! use density, only : densite_gaz logical :: is_inshock integer :: i_star, icell0, id, iray real(kind=dp), intent(out) :: Thp, Tshock, Facc - real(kind=dp) :: x, y, z + real(kind=dp) :: x, y, z, rho real(kind=dp) :: Tloc, vaccr, vmod2, rr, sign_z real :: alpha_1 = 0.75 real :: alpha_2 = 0.25 @@ -961,10 +962,11 @@ function is_inshock(id, iray, i_star, icell0, x, y, z, Thp, Tshock, Facc) if (.not.laccretion_shock) return if (icell0<=n_cells) then - if (nHtot(icell0) > 0.0) then - ! if (icompute_atomRT(icell0) > 0) then + !TO DO: densite_gaz(icell0) instead of nHtot + rho = nHtot(icell0) * wght_per_H + if (rho > 0.0) then ! even if icompute_atomRT(icell0) /= 0 rr = sqrt( x*x + y*y + z*z) - !vaccr is vr, the spherical r velocity component + ! Get vaccr : the accretion velocity above the shock. if (lvoronoi) then !always 3d vaccr = Voronoi(icell0)%vxyz(1)*x/rr + Voronoi(icell0)%vxyz(2)*y/rr + Voronoi(icell0)%vxyz(3) * z/rr vmod2 = sum( Voronoi(icell0)%vxyz(:)**2 ) @@ -992,13 +994,14 @@ function is_inshock(id, iray, i_star, icell0, x, y, z, Thp, Tshock, Facc) if (vaccr < 0.0_dp) then !Facc = 1/2 rho vs^3 - Facc = 0.5 * (1d-3 * masseH * wght_per_H * nHtot(icell0)) * abs(vaccr)**3 + Facc = 0.5 * (1d-3 * masseH * rho) * abs(vaccr)**3 Tloc = ( alpha_1 * Facc / sigma )**0.25 ! is_inshock = (Tloc > 0.5 * etoile(i_star)%T) is_inshock = (T_hp > 1.0_dp * etoile(i_star)%T) Thp = T_hp if (T_hp<=0.0) then - is_inshock = (abs(T_hp) * Tloc > 1.0_dp*etoile(i_star)%T) !depends on the local value + !depends on the local value + is_inshock = (abs(T_hp) * Tloc > 1.0_dp*etoile(i_star)%T) Thp = abs(T_hp) * Tloc endif !assuming mu is 0.5 From 213c1b5ee386c6d94694e56a23ec35b0a8be6002 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Thu, 2 Nov 2023 14:36:26 +0100 Subject: [PATCH 23/46] using kappa_abs_LTE for dust absorption --- src/optical_depth.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/optical_depth.f90 b/src/optical_depth.f90 index 7b16717be..d7091df2d 100644 --- a/src/optical_depth.f90 +++ b/src/optical_depth.f90 @@ -1172,7 +1172,7 @@ subroutine integ_ray_atom(id,icell_in,x,y,z,u,v,w,iray,labs,N,lambda) !TO DO: move to the total contopac & ! do not initialize chi, Snu in background but update them instead. if (ldust_atom) then - chi = chi + kappa(p_icell,:) * kappa_factor(icell) * m_to_AU ! [m^-1] + chi = chi + kappa_abs_LTE(p_icell,:) * kappa_factor(icell) * m_to_AU ! [m^-1] ! Snu = Snu + kappa_abs_LTE(p_icell,:) * kappa_factor(icell) * m_to_AU * Bpnu(N,lambda,T(icell)) ! [W m^-3 Hz^-1 sr^-1] Snu = Snu + emissivite_dust(:,icell) ! [W m^-3 Hz^-1 sr^-1] endif From c5efb0f134dead26b7db181496f594f0fd3fe23d Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Thu, 2 Nov 2023 20:24:06 +0100 Subject: [PATCH 24/46] correct density normalisation for dust/atom transfer --- src/init_mcfost.f90 | 1 + src/read_spherical_grid.f90 | 58 ++++++++++++++++++++++++------------- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/init_mcfost.f90 b/src/init_mcfost.f90 index 338e5ddb8..f5f2c7b00 100644 --- a/src/init_mcfost.f90 +++ b/src/init_mcfost.f90 @@ -82,6 +82,7 @@ subroutine set_default_variables() lsafe_stop = .false. safe_stop_time = 155520.0!1.8days in seconds, default lemission_atom = .false. + ldust_atom = .false. !coupling dust and atomic RT lelectron_scattering = .false. lstop_after_jnu = .false. lsolve_for_ne = .false. diff --git a/src/read_spherical_grid.f90 b/src/read_spherical_grid.f90 index e3a30f992..35c5d987f 100644 --- a/src/read_spherical_grid.f90 +++ b/src/read_spherical_grid.f90 @@ -129,15 +129,16 @@ subroutine read_spherical_model(filename) ! ----------------------------------------------------- ! ! read spherical grid data defined at cell centres. ! ----------------------------------------------------- ! + ! use grains, only : M_Grain character(len=*), intent(in) :: filename integer :: ios, i, Nsize - integer :: j, k, jj, icell, read_dust + integer :: j, k, jj, icell integer, allocatable :: dz(:,:,:) real, allocatable :: vtmp(:,:,:,:) real(kind=dp), allocatable :: rho(:,:,:), rho_dust(:,:,:) real(kind=dp), allocatable :: T_tmp(:,:,:), ne_tmp(:,:,:), vt_tmp(:,:,:) - real(kind=dp) :: mass, disk_dust_mass + real(kind=dp) :: mass call alloc_atomrt_grid call read_abundance !can be move in atom_transfer, but then rho must be changed in nHtot @@ -170,15 +171,16 @@ subroutine read_spherical_model(filename) read(1, iostat=ios) vtmp(:,:,:,:) read(1, iostat=ios) vt_tmp(:,:,:) read(1, iostat=ios) dz(:,:,:) - read(1, iostat=ios) read_dust + read(1, iostat=ios) disk_zone(1)%gas_to_dust + write(*,*) "Gas/Dust from model:", real(disk_zone(1)%gas_to_dust) !read total dust density - if (read_dust > 0) then - allocate(rho_dust(pluto%nx1,pluto%nx2,pluto%nx3)) - read(1, iostat=ios) rho_dust(:,:,:) - endif + allocate(rho_dust(pluto%nx1,pluto%nx2,pluto%nx3)) + read(1, iostat=ios) rho_dust(:,:,:) close(unit=1) densite_pouss = 0.0_dp ! init just in case. + masse_gaz = 0.0_dp + disk_zone(1)%diskmass = 0.0 do i=1, n_rad j = 0 bz : do jj=j_start+1,nz-1 ! 1 extra empty cell in theta on each side @@ -192,38 +194,54 @@ subroutine read_spherical_model(filename) vfield3d(icell,:) = vtmp(i,j,k,:) !-> wrapper for dust RT. - densite_gaz(icell) = nHtot(icell) * wght_per_H - if (read_dust > 0) densite_pouss(:,icell) = rho_dust(i,j,k) * 1d3 / masseH ! [m^-3] + !-> taking into account proper weights assuming only molecular gas in dusty regions + if (rho_dust(i,j,k) > 0.0) then ! dusty region + densite_gaz(icell) = rho(i,j,k) * 1d3 / masse_mol_gaz !total molecular gas density in H2/m^3 + densite_pouss(:,icell) = rho_dust(i,j,k) * 1d3 / masse_mol_gaz ! [m^-3] + disk_zone(1)%diskmass = disk_zone(1)%diskmass + rho_dust(i,j,k) * volume(icell) + else !No dust. + densite_gaz(icell) = nHtot(icell) * wght_per_H !total atomic gas density in H/m^3 + endif + masse_gaz(icell) = rho(i,j,k) * volume(icell) enddo enddo bz enddo + masse_gaz = masse_gaz * AU3_to_m3 * 1d3 ! [g] deallocate(rho,ne_tmp,T_tmp,vt_tmp,dz,vtmp) + !total dust mass + disk_zone(1)%diskmass = disk_zone(1)%diskmass * AU3_to_m3 * kg_to_Msun if (allocated(rho_dust)) deallocate(rho_dust) !dust part see read_pluto.f90 ! ********************************** ! - !technically is it masseH or masse_mol_gaz for H2 ? - mass = sum(densite_gaz * volume) * AU3_to_m3 * masseH * g_to_Msun + mass = sum(masse_gaz) * g_to_Msun + ! mass = sum(densite_gaz * volume) * AU3_to_m3 * masseH * g_to_Msun if (mass <= 0.0) call error('Gas mass is 0') - masse_gaz(:) = masseH * densite_gaz(:) * volume(:) * AU3_to_m3 ! [g] - - disk_dust_mass = sum(densite_pouss(1,:)*volume) * AU3_to_m3 * masseH * g_to_Msun + ! masse_gaz(:) = masseH * densite_gaz(:) * volume(:) * AU3_to_m3 ! [g] !--> no normalisation of density. The dust and gas densities are provided in the model. write(*,*) 'Total gas mass in model:', real(sum(masse_gaz) * g_to_Msun),' Msun' - ! write(*,*) 'Total dust mass in model:', real(disk_dust_mass),' Msun' - if (disk_dust_mass > 0.0_dp) then - dust_pop(:)%masse = disk_dust_mass - call normalize_dust_density(disk_dust_mass) - ldust_atom = .false. !tmp here, to move once opacity are added to contopac (adding 0 if no dust) + ! write(*,*) 'Total dust mass in model:', real(disk_zone(1)%diskmass),' Msun' + if (disk_zone(1)%diskmass > 0.0_dp) then + dust_pop(:)%masse = disk_zone(1)%diskmass + !here the densite_pouss gets normalise such that sum(densite_pouss) = 1 [units less] + call normalize_dust_density() + !the units of densite_pouss comes from M_grain in g/cm^3, normalize to give the dust mass if summed. + !the density of grains is M_grain x densite_pouss if (lemission_atom) ldust_atom = .true. endif ! ********************************** ! call check_for_zero_electronic_density() call print_info_model() - +! mass = 0 +! do icell=1, n_cells +! mass = mass + sum(M_grain(:) * densite_pouss(:,icell)) * volume(icell) +! enddo +! write(*,*) sum(masse) * g_to_Msun +! write(*,*) mass* AU3_to_cm3 * g_to_Msun +! stop return endsubroutine read_spherical_model From 8d3df5a6b593355d6e01e502e2957d6c8fc7e24c Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Fri, 3 Nov 2023 10:30:00 +0100 Subject: [PATCH 25/46] added a warning for dust mem allocation in atom RT --- src/mem.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mem.f90 b/src/mem.f90 index b886fd1eb..a113fd46d 100644 --- a/src/mem.f90 +++ b/src/mem.f90 @@ -487,7 +487,7 @@ subroutine realloc_dust_atom() if (allocated(emissivite_dust)) deallocate(emissivite_dust) allocate(emissivite_dust(n_lambda,n_cells),stat=alloc_status) if (alloc_status > 0) call error('Allocation error emissivite_dust (realloc atom)') - if (sizeof(emissivite_dust)/1024.**3 > 5) then + if (lvariable_dust.or.(sizeof(emissivite_dust)/1024.**3 > 5)) then write(*,*) " WARNING: using ", sizeof(emissivite_dust)/1024.**3, " GB for emissivite_dust" endif emissivite_dust = 0.0 From f54daaf4a3c9bf814d8a8d02964f79450d93bd2c Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Sat, 4 Nov 2023 22:24:49 +0100 Subject: [PATCH 26/46] fix issue --- src/dust_transfer.f90 | 2 -- src/input.f90 | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/dust_transfer.f90 b/src/dust_transfer.f90 index 038c3d6eb..ceb09cc12 100644 --- a/src/dust_transfer.f90 +++ b/src/dust_transfer.f90 @@ -246,8 +246,6 @@ subroutine transfert_poussiere() else etape_i=2 letape_th=.false. -!B. Tessore: !i ltemp == False (don't compute T) but we don't have dust so we don't want to read dust T -!or dust T is in the model, we need to leave here if (.not.(ldust_prop.and.lstop_after_init)) then ! we do not need the temperature if we only compute the dust prop call lect_Temperature() endif diff --git a/src/input.f90 b/src/input.f90 index 8ac85fe55..693240d23 100644 --- a/src/input.f90 +++ b/src/input.f90 @@ -185,9 +185,8 @@ subroutine lect_Temperature() !future: lgas_transfer. Dust could not always be present in the gas RT. if (lemission_atom) then - !note sure the test on ltemp is necessary here there_is_dust = (maxval(densite_pouss) > 0_dp) - if ( (.not.ltemp).and.(.not.there_is_dust) ) then + if ( .not.there_is_dust ) then call warning("(lect_Temperature) Do not attempt to read Tdust file when there is not dust!") return endif From 6d480fb9cdfa282c3c0d991977810303a55ead84 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Sat, 4 Nov 2023 23:01:24 +0100 Subject: [PATCH 27/46] do not print dark region --- src/read1d_models.f90 | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/read1d_models.f90 b/src/read1d_models.f90 index 455a6e0d1..b2821987f 100644 --- a/src/read1d_models.f90 +++ b/src/read1d_models.f90 @@ -14,6 +14,8 @@ module read1d_models use elements_type use grid, only : cell_map, vfield3d, alloc_atomrt_grid, nHtot, ne, v_char, lmagnetized, vturb, T, icompute_atomRT, & lcalc_ne, check_for_zero_electronic_density + use density, only : densite_pouss + use grains, only : M_grain implicit none @@ -226,10 +228,12 @@ end subroutine setup_model1d_to_mcfost subroutine print_info_model real(kind=dp) :: v_char + real(kind=dp) :: dust_dens_max, dust_dens_min, rho_d + integer :: icell v_char = sqrt( maxval(sum(vfield3d**2,dim=2)) ) - write(*,*) "Maximum/minimum velocities in the model (km/s):" + write(*,*) "Maximum/minimum velocities in the model [km s^-1]:" write(*,*) " Vfield(1) = ", & 1e-3 * maxval(abs(vfield3d(:,1))), 1d-3*minval(abs(vfield3d(:,1)),mask=icompute_atomRT>0) write(*,*) " Vfield(2) = ", & @@ -238,18 +242,32 @@ subroutine print_info_model 1d-3 * maxval(abs(vfield3d(:,3))), 1d-3*minval(abs(vfield3d(:,3)),mask=icompute_atomRT>0) - write(*,*) "Typical line extent due to V fields (km/s):" + write(*,*) "Typical line extent due to V fields [km s^-1]:" write(*,*) v_char/1d3 - write(*,*) "Maximum/minimum turbulent velocity (km/s):" + write(*,*) "Maximum/minimum turbulent velocity [km s^-1]:" write(*,*) maxval(vturb)/1d3, minval(vturb, mask=icompute_atomRT>0)/1d3 - write(*,*) "Maximum/minimum Temperature in the model (K):" + write(*,*) "Maximum/minimum Temperature in the model [K]:" write(*,*) real(maxval(T)), real(minval(T,mask=icompute_atomRT>0)) - write(*,*) "Maximum/minimum Hydrogen total density in the model (m^-3):" + ! write(*,*) " --> Density average of the Temperature [K]:" + ! write(*,*) real(sum(T*nHtot,(sum(densite_pouss,dim=1)==0.0).and.(icompute_atomRT>0)) / & + ! sum(nHtot,(sum(densite_pouss,dim=1)==0.0).and.(icompute_atomRT>0))) + write(*,*) "Maximum/minimum Hydrogen total density in the model [m^-3]:" write(*,*) real(maxval(nHtot)), real(minval(nHtot,mask=icompute_atomRT>0)) + if (ldust_atom) then + dust_dens_max = 0d0; dust_dens_min = 1d30 + do icell=1, n_cells + rho_d = sum(densite_pouss(:,icell) * M_grain(:)) + if (rho_d<=0.0) cycle + dust_dens_min = min(dust_dens_min,rho_d) + dust_dens_max = max(dust_dens_max,rho_d) + enddo + write(*,*) "Maximum/minimum dust total density in the model [kg m^-3]:" + write(*,*) 1d3*dust_dens_max, 1d3*dust_dens_min + endif if (.not.lcalc_ne) then - write(*,*) "Maximum/minimum ne density in the model (m^-3):" + write(*,*) "Maximum/minimum ne density in the model [m^-3]:" write(*,*) real(maxval(ne)), real(minval(ne,mask=icompute_atomRT>0)) endif @@ -259,7 +277,7 @@ subroutine print_info_model endif write(*,*) "Read ", size(pack(icompute_atomRT,mask=icompute_atomRT>0)), " density zones" write(*,*) "Read ", size(pack(icompute_atomRT,mask=icompute_atomRT==0)), " transparent zones" - write(*,*) "Read ", size(pack(icompute_atomRT,mask=icompute_atomRT<0)), " dark zones" + ! write(*,*) "Read ", size(pack(icompute_atomRT,mask=icompute_atomRT<0)), " dark zones" write(*,'("-- Solving RTE for "(1F6.2)" % of cells")') & 100.0*real(size(pack(icompute_atomRT,mask=icompute_atomRT>0))) / real(n_cells) From d268c6730fe9b92b707622256773150588894132 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Sat, 4 Nov 2023 23:23:31 +0100 Subject: [PATCH 28/46] added some comments. Todo: fix cell mapping --- src/read_spherical_grid.f90 | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/src/read_spherical_grid.f90 b/src/read_spherical_grid.f90 index 35c5d987f..7d152b9e3 100644 --- a/src/read_spherical_grid.f90 +++ b/src/read_spherical_grid.f90 @@ -149,17 +149,6 @@ subroutine read_spherical_model(filename) Nsize = pluto%nx1*pluto%nx2*pluto%nx3 write(*,*) "n_cells=", n_cells, Nsize - ! --> implicit cell mapping (does not work if the data is not well ordered) - ! read(1, iostat=ios) T(:) - ! read(1, iostat=ios) nHtot(:) - ! read(1, iostat=ios) ne(:) - ! read(1, iostat=ios) vfield3d(:,:) - ! read(1, iostat=ios) vturb(:) - ! read(1, iostat=ios) icompute_atomRT(:) - ! close(unit=1) - ! ! stop - ! !rho -> nH - ! nHtot = nHtot * 1d3 / masseH / wght_per_H ! --> explicit cell mapping of the 3d arrays allocate(rho(pluto%nx1,pluto%nx2,pluto%nx3), ne_tmp(pluto%nx1,pluto%nx2,pluto%nx3), & @@ -189,7 +178,7 @@ subroutine read_spherical_model(filename) do k=1, n_az icell = cell_map(i,jj,k) T(icell) = T_tmp(i,j,k) - nHtot(icell) = rho(i,j,k) * 1d3 / masseH / wght_per_H ! [m^-3] + nHtot(icell) = rho(i,j,k) * 1d3 / masseH / wght_per_H ! [H/m^3] icompute_atomRT(icell) = dz(i,j,k) vfield3d(icell,:) = vtmp(i,j,k,:) @@ -200,12 +189,12 @@ subroutine read_spherical_model(filename) densite_pouss(:,icell) = rho_dust(i,j,k) * 1d3 / masse_mol_gaz ! [m^-3] disk_zone(1)%diskmass = disk_zone(1)%diskmass + rho_dust(i,j,k) * volume(icell) else !No dust. - densite_gaz(icell) = nHtot(icell) * wght_per_H !total atomic gas density in H/m^3 + densite_gaz(icell) = nHtot(icell) * wght_per_H !total atomic gas density in [m^-3] endif masse_gaz(icell) = rho(i,j,k) * volume(icell) - enddo - enddo bz - enddo + enddo ! phi + enddo bz ! theta + enddo ! r masse_gaz = masse_gaz * AU3_to_m3 * 1d3 ! [g] deallocate(rho,ne_tmp,T_tmp,vt_tmp,dz,vtmp) !total dust mass @@ -225,7 +214,7 @@ subroutine read_spherical_model(filename) ! write(*,*) 'Total dust mass in model:', real(disk_zone(1)%diskmass),' Msun' if (disk_zone(1)%diskmass > 0.0_dp) then dust_pop(:)%masse = disk_zone(1)%diskmass - !here the densite_pouss gets normalise such that sum(densite_pouss) = 1 [units less] + !here the densite_pouss gets normalised such that sum(densite_pouss) = 1 [units less] call normalize_dust_density() !the units of densite_pouss comes from M_grain in g/cm^3, normalize to give the dust mass if summed. !the density of grains is M_grain x densite_pouss @@ -235,13 +224,7 @@ subroutine read_spherical_model(filename) call check_for_zero_electronic_density() call print_info_model() -! mass = 0 -! do icell=1, n_cells -! mass = mass + sum(M_grain(:) * densite_pouss(:,icell)) * volume(icell) -! enddo -! write(*,*) sum(masse) * g_to_Msun -! write(*,*) mass* AU3_to_cm3 * g_to_Msun -! stop + return endsubroutine read_spherical_model From 1ad1c1eecd1866b2217c009436c78cb47e6a1068 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Sat, 4 Nov 2023 23:51:48 +0100 Subject: [PATCH 29/46] improved warning in realloc_dust_atom --- src/mem.f90 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/mem.f90 b/src/mem.f90 index a113fd46d..2b68c2e24 100644 --- a/src/mem.f90 +++ b/src/mem.f90 @@ -456,6 +456,10 @@ subroutine realloc_dust_atom() integer :: alloc_status real :: mem_size + if (lvariable_dust) then + write(*,*) " WARNING: sizes of dust transfer could be very big !" + !TO DO: better storing of quantities / recuction of n_lambda + endif !Note: tab_lambda(n_lambda) is already allocated in atomic_transfer ! the tab_lambda_* or tab_delta_lambda should be de-allocated when tab_lambda is allocated in atom_rt. @@ -488,7 +492,7 @@ subroutine realloc_dust_atom() allocate(emissivite_dust(n_lambda,n_cells),stat=alloc_status) if (alloc_status > 0) call error('Allocation error emissivite_dust (realloc atom)') if (lvariable_dust.or.(sizeof(emissivite_dust)/1024.**3 > 5)) then - write(*,*) " WARNING: using ", sizeof(emissivite_dust)/1024.**3, " GB for emissivite_dust" + write(*,*) " *** WARNING: using ", sizeof(emissivite_dust)/1024.**3, " GB for emissivite_dust" endif emissivite_dust = 0.0 From b6d1d3ff8ab44316489928e3d5bd43231ab86d3a Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Sat, 4 Nov 2023 23:54:45 +0100 Subject: [PATCH 30/46] minor fix --- src/gas/atom_transfer.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index c92c99605..15f59216c 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -1224,7 +1224,7 @@ subroutine init_dust_temperature() if (any(T < T_formation)) call warning('(atom_transfer) Setting the gas transparent where T < 1500 K.') where (T < T_formation) icompute_atomRT = 0 if (any(icompute_atomRT>0)) then - write(*,*) "T:", maxval(T,icompute_atomRT>0), minval(T,icompute_atomRT>0) + write(*,*) "T:", real(maxval(T,icompute_atomRT>0)), real(minval(T,icompute_atomRT>0)) else call warning("(init_dust_temperature) The (atomic) gas is all transparent in dusty regions !") endif From b49a123f2eb4d356048bff87b7f29218ad0cf284 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Mon, 6 Nov 2023 09:37:34 +0100 Subject: [PATCH 31/46] clean --- src/gas/atom_transfer.f90 | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index 15f59216c..508f2a9ef 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -1216,19 +1216,27 @@ subroutine init_dust_temperature() !lowering too much the treshold might create some convergence issues in the non-LTE pops or in ! the electronic density calculations (0 division mainly for low values). real(kind=dp), parameter :: T_formation = 1500.0 ! [K] + logical, dimension(:), allocatable :: ldust + allocate(ldust(n_cells)); ldust = (sum(densite_pouss,dim=1)>0.0_dp) write(*,*) " *** Associating the dust temperature in the model..." + !force dust_sublimation + ! TO DO: + ! call sublimate_dust() + write(*,*) "Tdust:", maxval(Tdust), minval(Tdust) + write(*,*) "Tdust (rho_dust >0 ):", maxval(Tdust,ldust), minval(Tdust,ldust) !If the dust temperature is above T_formation the gas will follow that temperature !and atomic opacities will be considered. - write(*,*) "Tdust:", maxval(Tdust), minval(Tdust) - where(sum(densite_pouss,dim=1) > 0.0_dp) T(:) = Tdust(:) + where(ldust) T(:) = Tdust(:) if (any(T < T_formation)) call warning('(atom_transfer) Setting the gas transparent where T < 1500 K.') where (T < T_formation) icompute_atomRT = 0 if (any(icompute_atomRT>0)) then write(*,*) "T:", real(maxval(T,icompute_atomRT>0)), real(minval(T,icompute_atomRT>0)) + write(*,*) "T (rho_dust = 0):", real(maxval(T,(icompute_atomRT>0).and..not.ldust)), real(minval(T,(icompute_atomRT>0).and..not.ldust)) else - call warning("(init_dust_temperature) The (atomic) gas is all transparent in dusty regions !") + call warning("(init_dust_temperature) The (atomic) gas is all transparent !") endif write(*,*) " *** done." + deallocate(ldust) return end subroutine init_dust_temperature From ff0774d89f5c2d7095be41099a81e6fdb224bd65 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Mon, 6 Nov 2023 10:04:09 +0100 Subject: [PATCH 32/46] fix allocation error + cleaning --- src/gas/io_atom.f90 | 126 ++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 70 deletions(-) diff --git a/src/gas/io_atom.f90 b/src/gas/io_atom.f90 index 54cd03c85..26975f034 100644 --- a/src/gas/io_atom.f90 +++ b/src/gas/io_atom.f90 @@ -107,8 +107,9 @@ subroutine read_model_atom(atomunit, atom) allocate(parse_labs(atom%Nlevel)) !atomic level's population at LTE (n^*) allocate(atom%nstar(atom%Nlevel,n_cells)) + !ratio of continuum lower level to upper level allocate(atom%ni_on_nj_star(atom%Nlevel-1,n_cells)); atom%ni_on_nj_star = 0.0_dp - write(*,*) "size ni*/nj*=", sizeof(atom%ni_on_nj_star)/1024.**3, " GB" + ! write(*,*) "size ni*/nj*=", sizeof(atom%ni_on_nj_star)/1024.**3, " GB" !total number of transitions for this model atom%Ntr = atom%Nline + atom%Ncont !-> to remove tab_trans ?? @@ -153,7 +154,6 @@ subroutine read_model_atom(atomunit, atom) !it cannot be used as a loop index :-) !read bounb-bound (line) transitions - write(*,*) "MAGNETIC POLARIZATION REMOVED AT THE MOMENT" allocate(atom%lines(atom%Nline)) do kr=1,atom%Nline @@ -260,7 +260,7 @@ subroutine read_model_atom(atomunit, atom) endif - !Van der Waaks collision method + !Van der Waals collision method !line%a allocated in opacity_atom.f90 atom%lines(kr)%cvdWaals(4) = 0. atom%lines(kr)%cvdWaals(2) = 0. @@ -283,8 +283,6 @@ subroutine read_model_atom(atomunit, atom) case default atom%lines(kr)%vdWaals = "UNSOLD" end select - !-> move to make_wavelengths_nlte in wavlengths_gas - ! call compute_line_bound(atom%lines(kr),.false.) end do !end loop over bound-bound transitions ! ----------------------------------------- ! @@ -363,7 +361,7 @@ subroutine read_model_atom(atomunit, atom) call search_cont_lambdamax (atom%continua(kr), atom%Rydberg, atom%stage(i)+1,atom%E(j),atom%E(i)) endif endif - !the Nlambda from file is not used except if not hydrogenic + !Not used except if not hydrogenic atom%continua(kr)%Nlambda = 0 case default @@ -374,12 +372,15 @@ subroutine read_model_atom(atomunit, atom) atom%set_ltepops = .true. !by default compute lte populations !non-LTE pops in electronic density ? write non-LTE pops to file ? - atom%NLTEpops = .false. !set to true during non-LTE loop if initial /= 0 + atom%NLTEpops = .false. ! set to true during non-LTE loop (initial /= 1). + ! true if read from file (initial==1). ! allocate some space - if (atom%initial==2) then + if (atom%initial>1) then if (.not.atom%active) then - write(*,*) atom%ID, " is passive! cannot use ZERO_RADIATION solution, set to LTE." + write(*,*) atom%ID, " is passive!" + write(*,*) " *** Only LTE_POPS or OLD_POPS are possible as initial conditions" + write(*,*) " *** setting to LTE" atom%initial=0 endif endif @@ -390,81 +391,66 @@ subroutine read_model_atom(atomunit, atom) ! reading collision rates of RH, even for H even if it is not used. if (atom%ID /= "X") then - write(*,*) " -> Reading collision data from RH for atom ", atom%ID + write(*,*) " *** Reading collision data from RH for atom ", atom%ID call read_collisions(atomunit, atom) call warning(" ** the data for each transition must be consistent with transitions in the file") write(*,*) "a value of -99 is given to missing transitions and are skipped **" endif + !if the atom is active, we must allocate the non-LTE populations arrays. allocate(atom%n(atom%Nlevel,n_cells)) atom%n = 0.0_dp - if (atom%initial == 0) then!(initial==0 .or. initial==3) - atom%n = atom%nstar !still need to be computed - atom%set_ltepops = .true. - !if (initial==0) then - write(*,*) " -> Setting initial solution to LTE " - !else - ! cswitch - !endif - - - else if (atom%initial == 1) then - - write(*,*) " -> Reading (non-LTE AND LTE) populations from file..." - call read_pops_atom(atom) - atom%NLTEpops = .true. - atom%set_ltepops = .false. !read and USE also LTE populations from file!! - - else if (atom%initial == 2) then - - call error("initial solution == 2 (opt thin) not implemented yet!") - atom%n = atom%nstar - atom%set_ltepops = .true. - !nlte pops is false and are set after first electron density and lte pops. - - else if (atom%initial == 3) then - atom%n = atom%nstar !still need to be computed - !like initial==0 - atom%set_ltepops = .true. - if (.not. lforce_lte) then !otherwise cswitch is not LTE - write(*,*) " -> Setting initial solution to LTE with CSWITCH " - atom%cswitch = cswitch_val - if (.not. lcswitch_enabled) lcswitch_enabled = .true.!we need at least one - endif - - else if (atom%initial == 4) then - - call error("initial solution == 4 (Sobolev) not implemented yet!") - atom%n = atom%nstar - atom%set_ltepops = .true. - !nlte pops is false and are set after first electron density and lte pops. - - end if + select case (atom%initial) + case (0) + write(*,*) " -> Setting initial solution to LTE " + case (1) + write(*,*) " -> Setting initial solution to OLD_POPS " ! non-LTE + LTE + call read_pops_atom(atom) + atom%NLTEpops = .true. !read from file. + atom%set_ltepops = .false. !read from file, no need to compute. + case (2) + call error("initial solution == 2 (opt thin) not implemented yet!") + atom%set_ltepops = .true. + case (3) + atom%set_ltepops = .true. + if (.not. lforce_lte) then !otherwise cswitch is not LTE + write(*,*) " -> Setting initial solution to LTE with CSWITCH " + atom%cswitch = cswitch_val + if (.not. lcswitch_enabled) lcswitch_enabled = .true. !we need at least one + endif + case (4) + call error("initial solution == 4 (ESCAPE/LVG/Sobolev) not implemented yet!") + atom%set_ltepops = .true. + case default + write(*,*) "Active atom: initial = ", atom%initial + call error("Initial solution unknown!") + end select else !not active = PASSIVE - !other initials do not matter, always LTE ! (except if read) - if (atom%initial == 1) then - - allocate(atom%n(atom%Nlevel,n_cells)) !not allocated if passive, n->nstar - write(*,*) " -> Reading (non-LTE AND LTE) populations from file for passive atom..." - call read_pops_atom(atom) - !by default. Need a case with only LTE ? - atom%NLTEpops = .true. - atom%set_ltepops = .false. !read and USE also LTE populations from file!! - - !atom%NLTEpops = .false. still false at this point as we need pops to do electron densities - else !pure passive without nlte pops from previous run - ! atom%NLTEpops=.false. !-> default values - ! atom%set_ltepops = .true. - atom%n => atom%nstar !initialised to zero - !atom%n is an alias for nstar in this case - end if + ! Only intial = 0 (LTE) or 1 (from file) ! + select case (atom%initial) + case (0) !pure passive without nlte pops from previous run. + ! atom%NLTEpops = .false. !-> default values + ! atom%set_ltepops = .true. !-> default values + !%n is an alias for %nstar in that case. No need to allocate. + atom%n => atom%nstar ! initialised to nstar values + case (1) !non-LTE mode using previous populations. + ! Compute images and so on without updating non-LTE pops. + allocate(atom%n(atom%Nlevel,n_cells)) + write(*,*) " -> Reading (non-LTE AND LTE) populations from file." + call read_pops_atom(atom) + atom%NLTEpops = .true. !read from file. + atom%set_ltepops = .false. !read from file, no need to compute. + case default + write(*,*) "Passive atom: initial = ", atom%initial + call error("Initial solution unknown!") + end select end if !end is active deallocate(levelNumber) deallocate(determined) deallocate(parse_labs) !close atomic file - close(unit=atomunit) !later it will be open again for + close(unit=atomunit) return end subroutine read_Model_Atom From eefa5cf96d6124902dc20449fca479737a787dd3 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Mon, 6 Nov 2023 12:11:55 +0100 Subject: [PATCH 33/46] reducing stdout info --- src/read_spherical_grid.f90 | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/read_spherical_grid.f90 b/src/read_spherical_grid.f90 index 7d152b9e3..59c2a5e3e 100644 --- a/src/read_spherical_grid.f90 +++ b/src/read_spherical_grid.f90 @@ -1,7 +1,5 @@ ! -! Read model generated on a structured spherical mesh (e.g. with numpy.meshgrid). -! The model is in binary format generated with scipy.io.FortranFile.write_record() -! +! Read model generated on a structured spherical mesh (e.g. with numpy.meshgrid).! ! module read_spherical_grid @@ -35,7 +33,7 @@ subroutine read_spherical_grid_parameters(filename) ! ----------------------------------------------------- ! character(len=*), intent(in) :: filename integer :: ios, Nsize, acc, i, ipos - real :: dphi + real :: dphi,theta_0, theta_1 lvelocity_file = .true. vfield_coord = 3 ! spherical @@ -49,26 +47,31 @@ subroutine read_spherical_grid_parameters(filename) allocate(pluto%x1(pluto%nx1+1)) read(1,iostat=ios) pluto%x1(:) pluto%x1_min = minval(pluto%x1); pluto%x1_max = maxval(pluto%x1) - write(*,*) "r_limits (read)=",pluto%x1(:)! / etoile(1)%r + ! write(*,*) "r_limits [Rstar(1)] (read)=", pluto%x1(:) / etoile(1)%r + write(*,*) "r_limits [Rstar(1)] (read)=", pluto%x1(1) / etoile(1)%r, pluto%x1(pluto%nx1+1) / etoile(1)%r read(1,iostat=ios) pluto%nx2 allocate(pluto%x2(pluto%nx2+1)) read(1,iostat=ios) pluto%x2(:) pluto%x2_min = minval(pluto%x2); pluto%x2_max = maxval(pluto%x2) - write(*,*) "sin(theta)_limits (read)=", pluto%x2(:) + ! write(*,*) "sin(theta)_limits (read)=", pluto%x2(:) + write(*,*) "sin(theta)_limits (read)=", pluto%x2(1), pluto%x2(pluto%nx2+1) !correct prec error ? ! if (pluto%x2(1)-0.5*pi < 1e-6) pluto%x2(1) = 0.5*pi - write(*,*) "theta_limits (read)=",180.0 * real(asin(real(pluto%x2(:),kind=dp))) / pi + theta_0 = 180.0 * real(asin(real(pluto%x2(1),kind=dp))) / pi + theta_1 = 180.0 * real(asin(real(pluto%x2(pluto%nx2+1),kind=dp))) / pi + ! write(*,*) "theta_limits [°] (read)=",180.0 * real(asin(real(pluto%x2(:),kind=dp))) / pi + write(*,*) "theta_limits [°] (read)=", theta_0, theta_1 read(1,iostat=ios) pluto%nx3 !special, only 1 azimuth if not 3D (' no limits ') Nsize = pluto%nx3 if (pluto%nx3 > 1) then - ! l3D = .true. Nsize = Nsize + 1 endif allocate(pluto%x3(Nsize)) read(1,iostat=ios) pluto%x3(:) pluto%x3_min = minval(pluto%x3); pluto%x3_max = maxval(pluto%x3) - write(*,*) "phi_limits (read)=",180.0 * pluto%x3(:) / pi + ! write(*,*) "phi_limits [rad] (read)=", pluto%x3(:) + write(*,*) "phi_limits [°] (read)=", 180.0 * pluto%x3(1) / pi, 180.0 * pluto%x3(size(pluto%x3)) / pi read(1, iostat=ios) acc read(1, iostat=ios) T_hp @@ -94,7 +97,7 @@ subroutine read_spherical_grid_parameters(filename) theta_max = pluto%x2_max disk_zone(1)%rin = pluto%x1_min - disk_zone(1)%edge=0.0 + disk_zone(1)%edge = 0.0 disk_zone(1)%rmin = disk_zone(1)%rin disk_zone(1)%rout = pluto%x1_max @@ -120,7 +123,7 @@ subroutine read_spherical_grid_parameters(filename) Nsize = pluto%nx2 * pluto%nx3 * pluto%nx1 write(*,*) "Nsize=", Nsize, " nx1=", pluto%nx1, " nx2=", pluto%nx2," nx3=", pluto%nx3 write(*,*) "n_rad=", n_rad, "nz=", nz, "n_az=", n_az - write(*,*) "rin=", real(disk_zone(1)%rin), "rout=", real(disk_zone(1)%rout) + write(*,*) "rin=", real(disk_zone(1)%rin), "[au]; ", "rout=", real(disk_zone(1)%rout), "[au]" return endsubroutine read_spherical_grid_parameters From b47b1995eff7ba283b3ce4e1105b6050b210ff1c Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Mon, 6 Nov 2023 12:15:21 +0100 Subject: [PATCH 34/46] reducing stdout info --- src/read_spherical_grid.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/read_spherical_grid.f90 b/src/read_spherical_grid.f90 index 59c2a5e3e..ce7c47209 100644 --- a/src/read_spherical_grid.f90 +++ b/src/read_spherical_grid.f90 @@ -85,7 +85,7 @@ subroutine read_spherical_grid_parameters(filename) !either 2.5d (min(sin(theta))=-1) or 3d (Nphi > 1) l3d = (minval(pluto%x2) < 0.0).or.(pluto%nx3 > 1) - write(*,*) "3d mode ? ", l3d + ! write(*,*) "3d mode ? ", l3d laccretion_shock = (acc == 1) if (T_hp == 0.0_dp) T_hp = -1.0_dp From 5a9c2aefd1e4f4b9ad70e468bb1100263761ce0f Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Mon, 6 Nov 2023 15:03:51 +0100 Subject: [PATCH 35/46] cleaning --- src/gas/atom_transfer.f90 | 1 - src/gas/electron_density.f90 | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index 508f2a9ef..9736fb435 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -836,7 +836,6 @@ subroutine nlte_loop_mali() if (n_iterate_ne > 0) then write(*,'("ne(min)="(1ES17.8E3)" m^-3 ;ne(max)="(1ES17.8E3)" m^-3")') minval(ne,mask=icompute_atomRT>0), maxval(ne) - write(*,'("nH/ne "(1ES13.5E3, 1ES13.5E3))') maxval(nHtot/ne,mask=nhtot*ne>0), minval(nHtot/ne,mask=nHtot*ne>0) call write_electron endif diff --git a/src/gas/electron_density.f90 b/src/gas/electron_density.f90 index f1274ef84..9e5b45871 100644 --- a/src/gas/electron_density.f90 +++ b/src/gas/electron_density.f90 @@ -561,9 +561,8 @@ subroutine solve_ne(initial, verbose, epsilon) write(*,*) " T = ", T(ik_max)," nH = ", nHtot(ik_max) write(*,*) " " write(*,'("Ionisation fraction of HII "(1ES13.5E3, 1ES13.5E3))') max_f_HII, min_f_HII - ! write(*,*) nHtot(locate(ne/(1d-50+nHtot),maxval(ne/(1d-50+nHtot)))) - write(*,'("nH/ne "(1ES13.5E3, 1ES13.5E3))') maxval(nHtot/ne,mask=ne>0), minval(nHtot/ne,mask=ne>0) - ! call show_electron_given_per_elem(0, 0, max_fjk) + ! write(*,'("nH/ne "(1ES13.5E3, 1ES13.5E3))') maxval(nHtot/ne,mask=ne>0), minval(nHtot/ne,mask=ne>0) + ! call show_electron_given_per_elem(0, 0, max_fjk) write(*,*) " ---------------------------------------------------- " endif ! where (ne < ne_small) ne = 0.0 From 089d99a1bbd7702bd8036fd30cdbcdc720d70c1c Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Mon, 13 Nov 2023 12:52:36 +0100 Subject: [PATCH 36/46] corrected spherical input grid + read theta limits directly --- src/cylindrical_grid.f90 | 31 ++++++++----------------------- src/read_spherical_grid.f90 | 37 ++++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 40 deletions(-) diff --git a/src/cylindrical_grid.f90 b/src/cylindrical_grid.f90 index 74af4cd8b..07c022809 100644 --- a/src/cylindrical_grid.f90 +++ b/src/cylindrical_grid.f90 @@ -385,7 +385,6 @@ subroutine define_cylindrical_grid() !redifine and use the r grid read if (lsphere_model) then - !tab_r = r_lim ? tab_r(:) = pluto%x1(1:n_rad+1) !1 -> n_rad + 1 r_lim(:) = pluto%x1(:) !from Rmin to Rmax, 0 to n_rad r_lim_2(:) = r_lim(:) * r_lim(:) @@ -537,27 +536,18 @@ subroutine define_cylindrical_grid() ! test theta grid endif -! write(*,*) "wlim1=", w_lim -! write(*,*) "tlim1=", theta_lim -! write(*,*) "dc1=", dcos_theta -! write(*,*) "tantlim1=", tan_theta_lim - !redifine and use the theta grid read, still spherical if (lsphere_model) then - w_lim(:) = pluto%x2(nz+1:1:-1) !one more cell - theta_lim(:) = asin(w_lim) - ! write(*,*) size(pluto%x2), nz, size(w_lim), size(theta_lim) + !pluto%x2 goes from the max value of theta (pi/2 or pi if 3D) to 0. + !It has been re-ordered such that it goes from 0 to pi/2 (or pi): + ! %x2(1) = 0; %x2(nz+1) = pi/2 even in 3d (%x2(2*nz+1)=pi). + theta_lim(:) = pluto%x2(1:nz+1) + w_lim(:) = sin(theta_lim) tan_theta_lim(0) = 1.0e-10_dp tan_theta_lim(nz) = 1.e30_dp tan_theta_lim(1:nz-1) = tan(theta_lim(1:nz-1)) dcos_theta(1:nz) = w_lim(1:nz) - w_lim(0:nz-1) - - ! write(*,*) "w=",w_lim - ! write(*,*) "t=",theta_lim - ! write(*,*) dcos_theta - ! write(*,*) tan_theta_lim - endif do i=1, n_rad @@ -597,11 +587,9 @@ subroutine define_cylindrical_grid() endif enddo !k - !redifine and use the phi grid from file - ! write(*,*) "phi1=", phi_grid_tmp - ! write(*,*) "tan_phi1=", tan_phi_lim - ! write(*,*) size(tan_phi_lim), n_az, size(pluto%x3), size(phi_grid_tmp) - if (lsphere_model) then + !handle 2.5d (l3d but n_az==1) and pure 3d (n_az > 1). + if ((lsphere_model).and.(n_az>1)) then + !redifine and use the phi grid from file phi_grid_tmp(:) = 0.5*(pluto%x3(2:n_az+1) + pluto%x3(1:n_az)) ! do k=1, n_az ! phi = pluto%x3(k+1) @@ -616,9 +604,6 @@ subroutine define_cylindrical_grid() elsewhere tan_phi_lim = tan(pluto%x3(2:n_az+1)) endwhere - ! write(*,*) "phi=", phi_grid_tmp - ! write(*,*) "tan_phi=", tan_phi_lim - ! stop endif V(:,:) = V(:,:) * 0.5 / real(n_az) diff --git a/src/read_spherical_grid.f90 b/src/read_spherical_grid.f90 index ce7c47209..27c474717 100644 --- a/src/read_spherical_grid.f90 +++ b/src/read_spherical_grid.f90 @@ -33,7 +33,7 @@ subroutine read_spherical_grid_parameters(filename) ! ----------------------------------------------------- ! character(len=*), intent(in) :: filename integer :: ios, Nsize, acc, i, ipos - real :: dphi,theta_0, theta_1 + real :: dphi lvelocity_file = .true. vfield_coord = 3 ! spherical @@ -46,21 +46,17 @@ subroutine read_spherical_grid_parameters(filename) read(1,iostat=ios) pluto%nx1 allocate(pluto%x1(pluto%nx1+1)) read(1,iostat=ios) pluto%x1(:) + !Rmin to Rmax pluto%x1_min = minval(pluto%x1); pluto%x1_max = maxval(pluto%x1) ! write(*,*) "r_limits [Rstar(1)] (read)=", pluto%x1(:) / etoile(1)%r write(*,*) "r_limits [Rstar(1)] (read)=", pluto%x1(1) / etoile(1)%r, pluto%x1(pluto%nx1+1) / etoile(1)%r read(1,iostat=ios) pluto%nx2 allocate(pluto%x2(pluto%nx2+1)) read(1,iostat=ios) pluto%x2(:) + !pi to 0 or pi/2 to 0 if 2d. pluto%x2_min = minval(pluto%x2); pluto%x2_max = maxval(pluto%x2) - ! write(*,*) "sin(theta)_limits (read)=", pluto%x2(:) - write(*,*) "sin(theta)_limits (read)=", pluto%x2(1), pluto%x2(pluto%nx2+1) - !correct prec error ? - ! if (pluto%x2(1)-0.5*pi < 1e-6) pluto%x2(1) = 0.5*pi - theta_0 = 180.0 * real(asin(real(pluto%x2(1),kind=dp))) / pi - theta_1 = 180.0 * real(asin(real(pluto%x2(pluto%nx2+1),kind=dp))) / pi - ! write(*,*) "theta_limits [°] (read)=",180.0 * real(asin(real(pluto%x2(:),kind=dp))) / pi - write(*,*) "theta_limits [°] (read)=", theta_0, theta_1 + ! write(*,*) "theta_limits [°] (read)=", pluto%x2(:) + write(*,*) "theta_limits [°] (read)=", pluto%x2(1), pluto%x2(pluto%nx2+1) read(1,iostat=ios) pluto%nx3 !special, only 1 azimuth if not 3D (' no limits ') Nsize = pluto%nx3 @@ -69,6 +65,7 @@ subroutine read_spherical_grid_parameters(filename) endif allocate(pluto%x3(Nsize)) read(1,iostat=ios) pluto%x3(:) + !0 to 2pi pluto%x3_min = minval(pluto%x3); pluto%x3_max = maxval(pluto%x3) ! write(*,*) "phi_limits [rad] (read)=", pluto%x3(:) write(*,*) "phi_limits [°] (read)=", 180.0 * pluto%x3(1) / pi, 180.0 * pluto%x3(size(pluto%x3)) / pi @@ -82,10 +79,11 @@ subroutine read_spherical_grid_parameters(filename) if (pluto%x2(1) < pluto%x2(pluto%nx2)) then call error("(spherical input grid) theta(1) must be the largest value (pi or pi/2)") endif + !re-order pluto%x2 such that it goes from 0 to pi/2 from 1 to nz+1 + pluto%x2(:) = pluto%x2(pluto%nx2+1:1:-1) - !either 2.5d (min(sin(theta))=-1) or 3d (Nphi > 1) - l3d = (minval(pluto%x2) < 0.0).or.(pluto%nx3 > 1) - ! write(*,*) "3d mode ? ", l3d + ! 3d 2.5d + l3d = (pluto%nx3 > 1).or.(abs(maxval(pluto%x2) - 0.5 * pi) > 1e-6) laccretion_shock = (acc == 1) if (T_hp == 0.0_dp) T_hp = -1.0_dp @@ -94,22 +92,27 @@ subroutine read_spherical_grid_parameters(filename) n_rad = pluto%nx1 n_az = pluto%nx3 nz = pluto%nx2 - theta_max = pluto%x2_max + !but not used anyway + theta_max = 0.5_dp * pi ! should always be pi/2 (?) ! pluto%x2_max + !beware pluto%x1_min must not overlap with the core (star, planet etc). disk_zone(1)%rin = pluto%x1_min disk_zone(1)%edge = 0.0 disk_zone(1)%rmin = disk_zone(1)%rin disk_zone(1)%rout = pluto%x1_max - ! if (maxval(pluto%x1) == pluto%x1_max) then - ! pluto%x1_max = pluto%x1_max + pluto%x1(pluto%nx1) - pluto%x1(pluto%nx1-1) - ! endif disk_zone(1)%rmax = disk_zone(1)%rout - !change nz to two hemispheres and check that the grid of phi is linear. if (l3d) then + !handle the case 2.5d where Np=1 but %x2 goes to pi to 0. + !In those cases we have to give half the points in nz. nz = pluto%nx2/2 if (mod(pluto%nx2,2)>0) call warning("odd nx2") + endif + + !test on nx3 in the envtuallity of 2.5d + if (pluto%nx3 > 1) then + !check phi grid is pluto%nx3 > 1 dphi = pluto%x3(2) - pluto%x3(1) do i=2, size(pluto%x3) if ( abs((pluto%x3(i) - pluto%x3(i-1)) - dphi) > 1e-6 ) then From c5da33c3364e95fb7eb52ac10f27c9cc6e448c90 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 14 Nov 2023 12:16:22 +0100 Subject: [PATCH 37/46] correct cell mapping --- src/read_spherical_grid.f90 | 47 +++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/read_spherical_grid.f90 b/src/read_spherical_grid.f90 index 27c474717..da98494d2 100644 --- a/src/read_spherical_grid.f90 +++ b/src/read_spherical_grid.f90 @@ -176,13 +176,48 @@ subroutine read_spherical_model(filename) densite_pouss = 0.0_dp ! init just in case. masse_gaz = 0.0_dp disk_zone(1)%diskmass = 0.0 + ! do i=1, n_rad + ! j = 0 + ! bz : do jj=j_start+1,nz-1 ! 1 extra empty cell in theta on each side + ! if (jj==0) cycle bz + ! j = j + 1 + ! do k=1, n_az + ! icell = cell_map(i,jj,k) + ! T(icell) = T_tmp(i,j,k) + ! nHtot(icell) = rho(i,j,k) * 1d3 / masseH / wght_per_H ! [H/m^3] + ! icompute_atomRT(icell) = dz(i,j,k) + ! vfield3d(icell,:) = vtmp(i,j,k,:) + + ! !-> wrapper for dust RT. + ! !-> taking into account proper weights assuming only molecular gas in dusty regions + ! if (rho_dust(i,j,k) > 0.0) then ! dusty region + ! densite_gaz(icell) = rho(i,j,k) * 1d3 / masse_mol_gaz !total molecular gas density in H2/m^3 + ! densite_pouss(:,icell) = rho_dust(i,j,k) * 1d3 / masse_mol_gaz ! [m^-3] + ! disk_zone(1)%diskmass = disk_zone(1)%diskmass + rho_dust(i,j,k) * volume(icell) + ! else !No dust. + ! densite_gaz(icell) = nHtot(icell) * wght_per_H !total atomic gas density in [m^-3] + ! endif + ! masse_gaz(icell) = rho(i,j,k) * volume(icell) + ! enddo ! phi + ! enddo bz ! theta + ! enddo ! r do i=1, n_rad - j = 0 - bz : do jj=j_start+1,nz-1 ! 1 extra empty cell in theta on each side - if (jj==0) cycle bz - j = j + 1 + bz : do jj=min(0,j_start),nz do k=1, n_az - icell = cell_map(i,jj,k) + if (jj==0) then + icell = cell_map(i,1,k) + j = 1 + else + j = jj + if (l3d) then + if (jj > 0) then + j = jj + nz + else + j = nz + 1 + jj + endif + endif + icell = cell_map(i,jj,k) + endif T(icell) = T_tmp(i,j,k) nHtot(icell) = rho(i,j,k) * 1d3 / masseH / wght_per_H ! [H/m^3] icompute_atomRT(icell) = dz(i,j,k) @@ -227,6 +262,8 @@ subroutine read_spherical_model(filename) if (lemission_atom) ldust_atom = .true. endif ! ********************************** ! + ! write(*,*) "icell_not_empty:", icell_not_empty + ! write(*,*) "rho(icell_not_empty)", maxval(densite_pouss(:,icell_not_empty)), densite_gaz(icell_not_empty) call check_for_zero_electronic_density() call print_info_model() From 6c47b7c728a1da7b578cc991f33a29ce754350a9 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 14 Nov 2023 14:54:01 +0100 Subject: [PATCH 38/46] fix flux units back to standard --- src/gas/atom_transfer.f90 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index 9736fb435..234a6eb4a 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -1382,16 +1382,17 @@ subroutine intensite_pixel_atom(id,ibin,iaz,n_iter_min,n_iter_max,ipix,jpix,pixe ! Prise en compte de la surface du pixel (en sr) ! Flux out of a pixel in W/m2/Hz/pix - normF = c_light / nm_to_m * ( pixelsize / (distance*pc_to_AU) )**2 + normF = ( pixelsize / (distance*pc_to_AU) )**2 + !to nu.Fnu -> normF * c_light / nm_to_m; flux -> flux / tab_lambda_nm if (RT_line_method==1) then - Flux_total(:,ibin,iaz,id) = Flux_total(:,ibin,iaz,id) + I0(:) * normF / tab_lambda_nm + Flux_total(:,ibin,iaz,id) = Flux_total(:,ibin,iaz,id) + I0(:) * normF else do nat=1,N_atoms atom => atoms(nat)%p do kr=1,atom%nTrans_rayTracing krr = atom%ij_to_trans(atom%i_Trans_rayTracing(kr),atom%j_Trans_rayTracing(kr)) - atom%lines(krr)%map(ipix,jpix,:,ibin,iaz) = I0(atom%lines(krr)%nb:atom%lines(krr)%nr)*normF/ tab_lambda_nm(atom%lines(krr)%nb:atom%lines(krr)%nr) + atom%lines(krr)%map(ipix,jpix,:,ibin,iaz) = I0(atom%lines(krr)%nb:atom%lines(krr)%nr)*normF enddo atom => NULL() enddo From a9890afb3f913768a6230682cca6d713decefeb0 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Tue, 14 Nov 2023 15:43:13 +0100 Subject: [PATCH 39/46] increasing a bit the threshold in Tgas=Tdust for atomic transfer to prevent convergence issues --- src/gas/atom_transfer.f90 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index 234a6eb4a..852a79c1f 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -1214,7 +1214,7 @@ end subroutine atom_line_transfer subroutine init_dust_temperature() !lowering too much the treshold might create some convergence issues in the non-LTE pops or in ! the electronic density calculations (0 division mainly for low values). - real(kind=dp), parameter :: T_formation = 1500.0 ! [K] + real(kind=dp), parameter :: T_formation = 2000.0 ! [K] logical, dimension(:), allocatable :: ldust allocate(ldust(n_cells)); ldust = (sum(densite_pouss,dim=1)>0.0_dp) write(*,*) " *** Associating the dust temperature in the model..." @@ -1226,8 +1226,9 @@ subroutine init_dust_temperature() !If the dust temperature is above T_formation the gas will follow that temperature !and atomic opacities will be considered. where(ldust) T(:) = Tdust(:) - if (any(T < T_formation)) call warning('(atom_transfer) Setting the gas transparent where T < 1500 K.') + if (any(T < T_formation)) call warning('(atom_transfer) Setting the gas transparent where T < 2000 K.') where (T < T_formation) icompute_atomRT = 0 + !or set the atomic gas temperature to 0 in dust regions ? if (any(icompute_atomRT>0)) then write(*,*) "T:", real(maxval(T,icompute_atomRT>0)), real(minval(T,icompute_atomRT>0)) write(*,*) "T (rho_dust = 0):", real(maxval(T,(icompute_atomRT>0).and..not.ldust)), real(minval(T,(icompute_atomRT>0).and..not.ldust)) From 2e3fe2876286376f2b6e550314a6bf2f88b6630f Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Thu, 16 Nov 2023 09:32:44 +0100 Subject: [PATCH 40/46] fix alloc issue --- src/gas/wavelengths_gas.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gas/wavelengths_gas.f90 b/src/gas/wavelengths_gas.f90 index 0ae9c86d8..18075eea5 100644 --- a/src/gas/wavelengths_gas.f90 +++ b/src/gas/wavelengths_gas.f90 @@ -261,8 +261,8 @@ end function line_lambda_grid_dv subroutine deallocate_wavelengths_gasrt()!(lambda) use wavelengths, only : n_lambda, tab_lambda, tab_lambda_inf, tab_lambda_sup, tab_delta_lambda, n_lambda2, tab_lambda2 ! real(kind=dp), intent(inout), allocatable, dimension(:) :: lambda - if (allocated(tab_lambda)) then !lambda - deallocate(tab_lambda) !lambda + if (allocated(tab_lambda)) deallocate(tab_lambda) !lambda + if (allocated(tab_lambda_inf)) then deallocate(tab_lambda_inf, tab_lambda_sup, tab_delta_lambda) endif if (allocated(tab_lambda_nm)) deallocate(tab_lambda_cont, tab_lambda_nm) From f65d061fb6f8634c6752e22588d7f0151d046459 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Thu, 16 Nov 2023 14:41:55 +0100 Subject: [PATCH 41/46] prevent negative Ieff --- src/gas/see.f90 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gas/see.f90 b/src/gas/see.f90 index fac2f7ce4..bcfdb8990 100644 --- a/src/gas/see.f90 +++ b/src/gas/see.f90 @@ -571,7 +571,8 @@ subroutine accumulate_radrates_mali(id, icell, iray, domega) wphi = 0.0 !(Psi - Psi^\ast) eta - Ieff(1:Nl) = Itot(Nb:Nr,iray,id) - Psi(Nb:Nr,1,id) * eta_atoms(Nb:Nr,nact,id) + !-> cannot be negative. At worst, it is 0 if the emission is entirely local + Ieff(1:Nl) = max(Itot(Nb:Nr,iray,id) - Psi(Nb:Nr,1,id) * eta_atoms(Nb:Nr,nact,id),0.0_dp) ! do l=2, nl ! wl = c_light * (tab_lambda_nm(i0+l) - tab_lambda_nm(i0+l-1))/atom%lines(kr)%lambda0 @@ -651,7 +652,7 @@ subroutine accumulate_radrates_mali(id, icell, iray, domega) Jbar_up = 0.0 xcc_down = 0.0 - Ieff(1:Nl) = Itot(Nb:Nr,iray,id) - Psi(Nb:Nr,1,id) * eta_atoms(Nb:Nr,nact,id) + Ieff(1:Nl) = max(Itot(Nb:Nr,iray,id) - Psi(Nb:Nr,1,id) * eta_atoms(Nb:Nr,nact,id),0.0_dp) ! write(*,*) Itot(Nb:Nr,iray,id) ! write(*,*) Psi(Nb:Nr,1,id)*eta_atoms(Nb:Nr,nact,id) ! write(*,*) Psi(Nb:Nr,1,id) From c0dac4a731a3d0b1fe07670e455aef210a15a641 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Thu, 16 Nov 2023 16:34:53 +0100 Subject: [PATCH 42/46] used step 2 after step 1 just as a smoother for the angular averages. Otherwise, starts at step 2 --- src/gas/atom_transfer.f90 | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index 852a79c1f..269d827be 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -253,12 +253,7 @@ subroutine nlte_loop_mali() write(*,'(" ****-> Using "(1I8)" pixels for healpix, resolution of "(1F12.3)" degrees")') n_rayons, & healpix_angular_resolution(healpix_lorder) call healpix_sphere(healpix_lorder,xmu,xmux,xmuy) - if (etape_end > 1) then - !use that etape as an initial solution for step 2 - precision = 1d-1 - else - precision = dpops_max_error - endif + precision = dpops_max_error conv_speed_limit = conv_speed_limit_healpix else if (etape==2) then precision = dpops_max_error @@ -268,6 +263,12 @@ subroutine nlte_loop_mali() allocate(wmu(n_rayons)) wmu(:) = 1.0_dp / real(n_rayons,kind=dp) conv_speed_limit = conv_speed_limit_mc + if (etape_start == 1) then + !use that etape to increase the angular sampling, at lower convergence ? + precision = 1d-1 + else + precision = dpops_max_error + endif ! else if (etape==3) then ! !or solution with fixed rays that increase after each iteration?? ! lfixed_rays = .false. From 6a2022077d9fd860e32c958963b353e16854926b Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Thu, 16 Nov 2023 19:25:22 +0100 Subject: [PATCH 43/46] bug fix --- src/gas/io_atom.f90 | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/gas/io_atom.f90 b/src/gas/io_atom.f90 index 26975f034..37d091493 100644 --- a/src/gas/io_atom.f90 +++ b/src/gas/io_atom.f90 @@ -795,6 +795,8 @@ subroutine read_pops_atom(atom) logical :: extend, simple, anynull, show_warning = .true. integer :: nelements, naxis2(4), Nl, naxis_found, hdutype, l, icell character(len=256) :: some_comments, popsF + integer :: i, k + real(kind=dp) :: ntotal status = 0 call ftgiou(unit,status) @@ -969,6 +971,21 @@ subroutine read_pops_atom(atom) endif + !Set ni/nj ratio for continuum transitions in case ne-> 0 and nj ->0 + !should be ok for lines (the ratio for lines is used only in the collision) + !TO DO: para + do k=1, n_cells + ntotal = sum(atom%nstar(:,k)) ! nHtot(k) * atom%Abund + do i=1, atom%Ncont + if (atom%nstar(atom%continua(i)%j,k)>1d-15*ntotal) then + atom%ni_on_nj_star(atom%continua(i)%i,k) = atom%nstar(atom%continua(i)%i,k)/atom%nstar(atom%continua(i)%j,k) + else + atom%ni_on_nj_star(atom%continua(i)%i,k) = 0.0 + endif + enddo + enddo + + do l=1,atom%Nlevel write(*,"('Level #'(1I3))") l write(*,'(" -- min(n)="(1ES20.7E3)" m^-3; max(n)="(1ES20.7E3)" m^-3")') , & From 526aba74fc77712ab53b87a2d1f21b54e9c425b0 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Mon, 20 Nov 2023 14:47:05 +0100 Subject: [PATCH 44/46] clean --- src/gas/atom_transfer.f90 | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index 269d827be..13ffb986b 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -240,7 +240,7 @@ subroutine nlte_loop_mali() call alloc_nlte_var(one_ray,mem=mem_alloc_local) ! --------------------------- OUTER LOOP ON STEP --------------------------- ! - + precision = dpops_max_error step_loop : do etape=etape_start, etape_end write(*,*) "" @@ -253,22 +253,14 @@ subroutine nlte_loop_mali() write(*,'(" ****-> Using "(1I8)" pixels for healpix, resolution of "(1F12.3)" degrees")') n_rayons, & healpix_angular_resolution(healpix_lorder) call healpix_sphere(healpix_lorder,xmu,xmux,xmuy) - precision = dpops_max_error conv_speed_limit = conv_speed_limit_healpix else if (etape==2) then - precision = dpops_max_error n_rayons = N_rayons_mc write(*,'(" ****-> Using "(1I4)" rays for Monte-Carlo step, ~resolution of "(1F12.3)" degrees")') n_rayons, & 360.0 * sqrt(pi/real(n_rayons))/pi allocate(wmu(n_rayons)) wmu(:) = 1.0_dp / real(n_rayons,kind=dp) conv_speed_limit = conv_speed_limit_mc - if (etape_start == 1) then - !use that etape to increase the angular sampling, at lower convergence ? - precision = 1d-1 - else - precision = dpops_max_error - endif ! else if (etape==3) then ! !or solution with fixed rays that increase after each iteration?? ! lfixed_rays = .false. From 961b1a7602a7059f2d1fc0252a16ee5e80abc8ce Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Mon, 20 Nov 2023 15:05:31 +0100 Subject: [PATCH 45/46] fix long lines gfortran --- src/dust_transfer.f90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dust_transfer.f90 b/src/dust_transfer.f90 index ceb09cc12..2821b1b84 100644 --- a/src/dust_transfer.f90 +++ b/src/dust_transfer.f90 @@ -761,7 +761,8 @@ subroutine transfert_poussiere() call ecriture_temperature(1) call ecriture_sed(1) - if (lapprox_diffusion.and.l_is_dark_zone.and.(lemission_mol.or.lprodimo.or.lML.or.lforce_diff_approx.or.lemission_atom)) then + if (lapprox_diffusion.and.l_is_dark_zone.and.& + (lemission_mol.or.lprodimo.or.lML.or.lforce_diff_approx.or.lemission_atom)) then call Temp_approx_diffusion_vertical() ! call Temp_approx_diffusion() call diffusion_approx_nLTE_nRE() From 9dab2954354e54e8a2f1f0a434e5f940d688a7c0 Mon Sep 17 00:00:00 2001 From: Benjamin Tessore Date: Mon, 20 Nov 2023 15:20:28 +0100 Subject: [PATCH 46/46] fix long lines gfortran --- src/gas/atom_transfer.f90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gas/atom_transfer.f90 b/src/gas/atom_transfer.f90 index 13ffb986b..c4ae653e5 100644 --- a/src/gas/atom_transfer.f90 +++ b/src/gas/atom_transfer.f90 @@ -1224,7 +1224,8 @@ subroutine init_dust_temperature() !or set the atomic gas temperature to 0 in dust regions ? if (any(icompute_atomRT>0)) then write(*,*) "T:", real(maxval(T,icompute_atomRT>0)), real(minval(T,icompute_atomRT>0)) - write(*,*) "T (rho_dust = 0):", real(maxval(T,(icompute_atomRT>0).and..not.ldust)), real(minval(T,(icompute_atomRT>0).and..not.ldust)) + write(*,*) "T (rho_dust = 0):", real(maxval(T,(icompute_atomRT>0).and..not.ldust)), & + real(minval(T,(icompute_atomRT>0).and..not.ldust)) else call warning("(init_dust_temperature) The (atomic) gas is all transparent !") endif