Skip to content

Commit

Permalink
Merge pull request #54 from nichollsh/chemfix
Browse files Browse the repository at this point in the history
Fixes to chemistry following thermo changes
  • Loading branch information
nichollsh authored Jul 1, 2024
2 parents 3587461 + 19a1725 commit 2bd00d2
Show file tree
Hide file tree
Showing 13 changed files with 282 additions and 97 deletions.
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ authors:
given-names: "Harrison"
orcid: "https://orcid.org/0000-0002-8368-4641"
title: "AGNI"
version: 0.5.1
version: 0.5.2
doi: 10.xx/xx.xx
date-released: 2024-06-25
url: "https://github.com/nichollsh/AGNI"
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "AGNI"
uuid = "ede838c1-9ec3-4ebe-8ae8-da4091b3f21c"
authors = ["Harrison Nicholls <[email protected]>"]
version = "0.5.1"
version = "0.5.2"

[deps]
ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63"
Expand Down
86 changes: 43 additions & 43 deletions res/config/chemistry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,58 @@
title = "Equilibrium chemistry demo" # Name for this configuration file

[planet]
tmp_surf = 2200.0 # Surface temperature [kelvin]
instellation = 44000.0 # Stellar flux at planet's orbital distance [W m-2]
albedo_b = 0.18 # Pseudo bond-albedo which downscales the stellar flux by 1-this_value
s0_fact = 0.375 # Stellar flux scale factor which accounts for planetary rotation (c.f. Cronin+13)
zenith_angle = 48.19 # Characteristic zenith angle for incoming stellar radiation [degrees]
albedo_s = 0.0 # Surface albedo
radius = 6.37e6 # Planet radius at the surface [m]
gravity = 9.81 # Gravitational acceleration at the surface [m s-2]
p_surf = 270.0 # Total surface pressure [bar]
p_top = 1e-5 # Total top-of-atmosphere pressure [bar]
vmr = { H2O = 0.6, CO2=0.1, N2=0.1, SO2=0.1, O2=0.05, Fe=0.05} # Volatile volume mixing ratios
tmp_surf = 2200.0
instellation = 10000.0
albedo_b = 0.0
s0_fact = 0.375
zenith_angle = 48.19
albedo_s = 0.0
radius = 6.37e6
gravity = 9.81
p_surf = 270.0
p_top = 1e-5
vmr = { H2O = 0.3, CO2=0.1, N2=0.1, SO2=0.05, O2=0.05, FeO2=0.05, OH=0.0, H=0.0, CH4=0.1, CO=0.5, H2=0.5, SO=0.0, NH3=0.0, NH2=0.0, H2S=0.0, H2SO4=0.0} # Volatile volume mixing ratios
condensates = []
tmp_int = 0.0 # Effective temperature

tmp_int = 0.0
[files]
clean_output = true
input_sf = "res/spectral_files/Dayspring/48/Dayspring.sf" # Path to SOCRATES spectral file.
input_sf = "res/spectral_files/nogit/Dayspring/48/Dayspring.sf" # Path to SOCRATES spectral file.
input_star = "res/stellar_spectra/sun.txt" # Path to stellar spectrum.
output_dir = "out/" # Path to output directory.
fastchem_path = "/Users/nichollsh/Projects/fastchem/"

[execution]
verbosity = 1 # Log level (0: none, 1: normal, 2: debug)
max_steps = 200 # Maximum number of solver steps.
max_runtime = 400 # Maximum wall-clock solver runtime [s].
num_levels = 40 # Number of model levels.
continua = true # Include absorption from continua?
rayleigh = false # Include rayleigh scattering?
cloud = false # Include water cloud radiative properties?
aerosol = false # Include aerosol radiative properties?
overlap_method = 4 # Method for treating line overlap.
thermo_funct = false # Use temperature-dependent thermodynamic properties?
sensible_heat = false # Include sensible heat transport at the surface?
latent_heat = false
convection_type = "mlt" # Convection type ("" = no convection, "mlt" = use mixing length theory).
chemistry = 1 # Chemistry type (see wiki)
solution_type = 3 # Solution type (see wiki).
solvers = ["newton"] # Ordered list of solvers to apply (see wiki).
dx_max = 200.0 # Maximum step size [Kelvin], when using nonlinear solvers
initial_state = ["iso","2000"] # Ordered list of requests describing the initial state of the atmosphere (see wiki).
linesearch = false # Use linesearch?
converge_atol = 1.0e-2 # Convergence criterion on absolute flux lost [W m-2].
converge_rtol = 1.0e-4 # Convergence criterion on relative flux lost [dimensionless].
verbosity = 1
max_steps = 200
max_runtime = 400
num_levels = 45
continua = true
rayleigh = true
cloud = false
aerosol = false
overlap_method = 4
thermo_funct = true
sensible_heat = false
latent_heat = false
convection_type = "mlt"
chemistry = 1
solution_type = 3
solvers = ["newton"]
dx_max = 200.0
initial_state = ["iso","2000"]
linesearch = false
converge_atol = 1.0e-2
converge_rtol = 1.0e-4


[plots]
at_runtime = true # Make some plots at runtime?
temperature = true # Plot temperature profile?
fluxes = true # Plot fluxes?
contribution = true # Plot spectral contribution function?
emission = true # Plot emission spectrum?
albedo = true # Plot spectral albedo?
mixing_ratios = true # Plot mixing ratios?
animate = true # Make animation from runtime plots?
at_runtime = true
temperature = true
fluxes = true
contribution = true
emission = true
albedo = true
mixing_ratios = true
animate = true

Binary file added res/thermo/C2H4.nc
Binary file not shown.
Binary file added res/thermo/FeS.nc
Binary file not shown.
Binary file added res/thermo/OCS.nc
Binary file not shown.
Binary file added res/thermo/S2.nc
Binary file not shown.
Binary file added res/thermo/SO.nc
Binary file not shown.
115 changes: 92 additions & 23 deletions src/atmosphere.jl
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,9 @@ module atmosphere
gas_sat::Dict{String, Array{Bool, 1}} # Layer is saturated or cold-trapped
gas_dat::Dict{String, phys.Gas_t} # struct variables containing thermodynamic data
gas_yield::Dict{String, Array{Float64,1}} # condensate yield [kg/m^2] at each level (can be negative, representing evaporation)
condensates::Array{String, 1} # List of condensing gases (strings)
single_component::Bool # Does a single gas make up 100% of layer at any point in the column?
condensates::Array{String, 1} # List of condensing gases (strings)
condense_any::Bool # length(condensates)>0 ?
single_component::Bool # Does a single gas make up 100% of layer at any point in the column?

# Gases (only those in spectralfile)
gas_soc_num::Int
Expand Down Expand Up @@ -301,7 +302,7 @@ module atmosphere
end

# Code versions
atmos.AGNI_VERSION = "0.5.1"
atmos.AGNI_VERSION = "0.5.2"
atmos.SOCRATES_VERSION = readchomp(joinpath(ENV["RAD_DIR"],"version"))
@debug "AGNI VERSION = $(atmos.AGNI_VERSION)"
@debug "Using SOCRATES at $(ENV["RAD_DIR"])"
Expand Down Expand Up @@ -523,7 +524,9 @@ module atmosphere
end

# Validate condensate names
atmos.condense_any = false
if length(condensates) > 0
atmos.condense_any = true
for c in condensates
if !(c in atmos.gas_names)
@error "Invalid condensate '$c'"
Expand Down Expand Up @@ -1081,7 +1084,7 @@ module atmosphere
if !isempty(gas_flags)
gas_flags = "($(gas_flags[1:end-1]))"
end
@info @sprintf(" %6.2e %-5s %s", atmos.gas_vmr[g][end], g, gas_flags)
@info @sprintf(" %6.2e %-6s %s", atmos.gas_vmr[g][end], g, gas_flags)
end


Expand Down Expand Up @@ -1211,12 +1214,14 @@ module atmosphere
- `atmos::Atmos_t` the atmosphere struct instance to be used.
- `chem_type::Int` chemistry type (see wiki)
- `write_cfg::Bool` write config and elements
- `tmp_floor::Float64=500.0` temperature floor for T(p) provided to FastChem
- `tmp_floor::Float64` temperature floor for T(p) provided to FastChem
Returns:
- `state::Int` fastchem state (0: success, 1: critical_fail, 2: elem_fail, 3: conv_fail, 4: both_fail)
"""
function chemistry_eq!(atmos::atmosphere.Atmos_t, chem_type::Int, write_cfg::Bool; tmp_floor::Float64=500.0)::Int
function chemistry_eq!(atmos::atmosphere.Atmos_t, chem_type::Int, write_cfg::Bool; tmp_floor::Float64=700.0)::Int

@debug "Running equilibrium chemistry"

# Return code
state::Int = 0
Expand All @@ -1227,6 +1232,14 @@ module atmosphere
return 1
end

# Check minimum temperature
if maximum(atmos.tmpl) < tmp_floor
@warn "Temperature profile is entirely too cold for FastChem. Not doing chemistry."
return 1
end

count_elem_nonzero::Int = 0

# Paths
execpath::String = joinpath(atmos.fastchem_path,"fastchem") # Executable file
confpath::String = joinpath(atmos.fastchem_work,"config.input") # Configuration by AGNI
Expand Down Expand Up @@ -1263,16 +1276,16 @@ module atmosphere
write(f,joinpath(logK,"logK.dat")*" "*joinpath(logK,"logK_condensates.dat")*" \n\n")

write(f,"#Accuracy of chemistry iteration \n")
write(f,"1.0e-5 \n\n")
write(f,"1.0e-4 \n\n")

write(f,"#Accuracy of element conservation \n")
write(f,"1.0e-4 \n\n")

write(f,"#Max number of chemistry iterations \n")
write(f,"50000 \n\n")
write(f,"60000 \n\n")

write(f,"#Max number internal solver iterations \n")
write(f,"10000 \n\n")
write(f,"30000 \n\n")
end

# Calculate elemental abundances
Expand All @@ -1289,16 +1302,19 @@ module atmosphere
N_g[i] += d[e]
end
end
# will be normalised in later code
N_g *= get_x(atmos, gas, atmos.nlev_c) * atmos.p[end] / (phys.k_B * atmos.tmp[end]) # gas contribution
N_t += N_g # number/m^3
N_t += N_g
end

# Write elemental abundances
open(joinpath(atmos.fastchem_work,"elements.dat"),"w") do f
write(f,"# Elemental abundances derived from AGNI volatiles \n")
for (i,e) in enumerate(phys.elements_list)
if N_t[i] > 1.0e-30
# normalise relative to hydrogen
write(f, @sprintf("%s %.3f \n",e,log10(N_t[i]/N_t[1]) + 12.0))
count_elem_nonzero += 1
end
end
end
Expand All @@ -1309,7 +1325,7 @@ module atmosphere
write(f,"# AGNI temperature structure \n")
write(f,"# bar, kelvin \n")
for i in 1:atmos.nlev_c
write(f,@sprintf("%.6e %.6e \n", atmos.p[i], max(tmp_floor,atmos.tmp[i]) ))
write(f,@sprintf("%.6e %.6e \n", atmos.p[i]*1e-5, max(tmp_floor,atmos.tmp[i]) ))
end
end

Expand Down Expand Up @@ -1350,24 +1366,77 @@ module atmosphere
(data,head) = readdlm(chempath, '\t', Float64, header=true)
data = transpose(data) # convert to: gas, level

# Clear VMRs
for g in atmos.gas_names
fill!(atmos.gas_vmr[g], 0.0)
end

# Parse gas chemistry
g::String = ""
g_fc::String = "_unset"
d_fc::Dict = Dict{String, Int}()
g_in::String = "_unset"
match::Bool = false
N_t = data[4,:] # at each level: sum of gas number densities

for (i,h) in enumerate(head) # for each column (gas)
g = rstrip(lstrip(h))

# check if gas is included in the model
if g in keys(phys.map_fastchem_name)
g = phys.map_fastchem_name[g] # convert name
if g in atmos.gas_names
N_g = data[i,:] # number densities for this gas
atmos.gas_vmr[g][:] .= N_g[:] ./ N_t[:] # mole fraction (VMR) for this gas
end
end # not included => skip

# skip T and P
if i <= 5+count_elem_nonzero
continue
end

# parse name
g_fc = rstrip(lstrip(h))
if occursin("_", g_fc)
g_fc = split(g_fc, "_")[1]
end
g_fc = replace(g_fc, "cis"=>"", "trans"=>"")

match = false

# firstly, check if we have the FC name already stored
for g in atmos.gas_names
if atmos.gas_dat[g].fastchem_name == g_fc
match = true
g_in = g
break
end
end

# not stored => search based on atoms
if !match
d_fc = phys.count_atoms(g_fc) # get atoms dict from FC name

for g in atmos.gas_names
if phys.same_atoms(d_fc, atmos.gas_dat[g].atoms)
match = true
g_in = g
break
end
end
end

# matched?
if match
N_g = data[i,:] # number densities for this gas
atmos.gas_vmr[g_in][:] .+= N_g[:] ./ N_t[:] # mole fraction (VMR) for this gas
end
end

# Do not renormalise mixing ratios
# Do not renormalise mixing ratios, since this is done by fastchem
# If we are missing gases then that's okay.

# Find where we truncated the temperature profile, and make sure that regions above that use the same x_gas values
for i in range(start=atmos.nlev_c, stop=1, step=-1)
if atmos.tmp[i] < tmp_floor
for g in atmos.gas_names
atmos.gas_vmr[g][1:i] .= atmos.gas_vmr[g][i+1]
end
break
end
end

# See docstring for return codes
return state
end

Expand Down
6 changes: 3 additions & 3 deletions src/energy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ module energy
function condense_relax!(atmos::atmosphere.Atmos_t)

# Check if empty
if length(atmos.condensates) == 0
if !atmos.condense_any
return nothing
end

Expand Down Expand Up @@ -542,7 +542,7 @@ module energy
fill!(atmos.mask_l, 0)

# Check if empty
if length(atmos.condensates) == 0
if !atmos.condense_any
return nothing
end

Expand Down Expand Up @@ -600,7 +600,7 @@ module energy
fill!(atmos.flux_dif, 0.0)

# +Condensation energy flux
if latent
if latent || atmos.condense_any
if atmos.single_component
# does NOT modify VMRs
energy.condense_relax!(atmos)
Expand Down
Loading

0 comments on commit 2bd00d2

Please sign in to comment.