|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "code", |
| 5 | + "execution_count": null, |
| 6 | + "id": "4f297f36", |
| 7 | + "metadata": {}, |
| 8 | + "outputs": [], |
| 9 | + "source": [ |
| 10 | + "# Setup environment\n", |
| 11 | + "using Pkg\n", |
| 12 | + "Pkg.activate(\"..\")\n", |
| 13 | + "\n", |
| 14 | + "ENV[\"RAD_DIR\"] = abspath(\"..\", \"socrates\")\n", |
| 15 | + "\n", |
| 16 | + "using Revise\n", |
| 17 | + "include(\"../src/AGNI.jl\")\n", |
| 18 | + "\n", |
| 19 | + "using Printf\n", |
| 20 | + "using Plots" |
| 21 | + ] |
| 22 | + }, |
| 23 | + { |
| 24 | + "cell_type": "code", |
| 25 | + "execution_count": null, |
| 26 | + "id": "0b394f17", |
| 27 | + "metadata": {}, |
| 28 | + "outputs": [], |
| 29 | + "source": [ |
| 30 | + "# Common parameters\n", |
| 31 | + "ROOT_DIR = abspath(\"..\")\n", |
| 32 | + "OUT_DIR_BASE = abspath(\"..\", \"out\", \"test_deep_heating\")\n", |
| 33 | + "spectral_file = \"res/spectral_files/Dayspring/48/Dayspring.sf\"\n", |
| 34 | + "star_file = \"res/stellar_spectra/sun.txt\"\n", |
| 35 | + "\n", |
| 36 | + "# Planet parameters (hot Jupiter-like)\n", |
| 37 | + "instellation = 5000.0 # W/m² (moderate stellar flux)\n", |
| 38 | + "tmp_surf = 1500.0 # K\n", |
| 39 | + "gravity = 10.0 # m/s²\n", |
| 40 | + "radius = 7.0e7 # m (roughly Jupiter radius)\n", |
| 41 | + "p_surf = 100.0 # bar\n", |
| 42 | + "p_top = 1e-5 # bar\n", |
| 43 | + "nlev = 100 # number of levels\n", |
| 44 | + "\n", |
| 45 | + "# Deep heating parameters\n", |
| 46 | + "deep_P_dep = 1.0e6 # 10 bar deposition pressure\n", |
| 47 | + "deep_sigma_P = 1.0 # Width in log-pressure\n", |
| 48 | + "deep_efficiency = 0.02 # 2% of stellar flux\n", |
| 49 | + "\n", |
| 50 | + "# Expected additional flux\n", |
| 51 | + "F_deep_expected = deep_efficiency * instellation\n", |
| 52 | + "@printf(\"Expected deep heating flux: %.2f W/m²\\n\", F_deep_expected)" |
| 53 | + ] |
| 54 | + }, |
| 55 | + { |
| 56 | + "cell_type": "code", |
| 57 | + "execution_count": null, |
| 58 | + "id": "7cac6882", |
| 59 | + "metadata": {}, |
| 60 | + "outputs": [], |
| 61 | + "source": [ |
| 62 | + "# Function to create and run an atmosphere model\n", |
| 63 | + "function run_model(out_dir::String, deep_active::Bool)\n", |
| 64 | + " # Clean output directory\n", |
| 65 | + " rm(out_dir, force=true, recursive=true)\n", |
| 66 | + " mkpath(out_dir)\n", |
| 67 | + "\n", |
| 68 | + " # Create atmosphere\n", |
| 69 | + " atmos = AGNI.atmosphere.Atmos_t()\n", |
| 70 | + "\n", |
| 71 | + " # Composition: H2-dominated with some H2O\n", |
| 72 | + " mf_dict = Dict(\"H2\" => 0.85, \"He\" => 0.14, \"H2O\" => 0.01)\n", |
| 73 | + "\n", |
| 74 | + " # Setup atmosphere\n", |
| 75 | + " AGNI.atmosphere.setup!(atmos, ROOT_DIR, out_dir,\n", |
| 76 | + " spectral_file,\n", |
| 77 | + " instellation, 1.0, 0.0, 48.19, # instellation, s0_fact, albedo_b, zenith\n", |
| 78 | + " tmp_surf, gravity, radius,\n", |
| 79 | + " nlev, p_surf, p_top,\n", |
| 80 | + " mf_dict, \"\"; # mf_dict, mf_path\n", |
| 81 | + " flag_rayleigh=false,\n", |
| 82 | + " flag_gcontinuum=true,\n", |
| 83 | + " real_gas=false,\n", |
| 84 | + " thermo_functions=true)\n", |
| 85 | + "\n", |
| 86 | + " # Allocate\n", |
| 87 | + " AGNI.atmosphere.allocate!(atmos, joinpath(ROOT_DIR, star_file))\n", |
| 88 | + "\n", |
| 89 | + " # Set deep heating if requested\n", |
| 90 | + " if deep_active\n", |
| 91 | + " AGNI.atmosphere.set_deep_heating!(atmos,\n", |
| 92 | + " active=true,\n", |
| 93 | + " P_dep=deep_P_dep,\n", |
| 94 | + " sigma_P=deep_sigma_P,\n", |
| 95 | + " efficiency=deep_efficiency)\n", |
| 96 | + " end\n", |
| 97 | + "\n", |
| 98 | + " # Set initial temperature profile (isothermal + adiabatic)\n", |
| 99 | + " AGNI.setpt.isothermal!(atmos, tmp_surf)\n", |
| 100 | + "\n", |
| 101 | + " # Calculate layer properties\n", |
| 102 | + " AGNI.atmosphere.calc_layer_props!(atmos)\n", |
| 103 | + "\n", |
| 104 | + " # Calculate fluxes (no solve, just single evaluation)\n", |
| 105 | + " AGNI.energy.calc_fluxes!(atmos, true, false, true, false, true)\n", |
| 106 | + "\n", |
| 107 | + " return atmos\n", |
| 108 | + "end" |
| 109 | + ] |
| 110 | + }, |
| 111 | + { |
| 112 | + "cell_type": "code", |
| 113 | + "execution_count": null, |
| 114 | + "id": "cfb5b969", |
| 115 | + "metadata": { |
| 116 | + "vscode": { |
| 117 | + "languageId": "ruby" |
| 118 | + } |
| 119 | + }, |
| 120 | + "outputs": [], |
| 121 | + "source": [ |
| 122 | + "# Run model WITHOUT deep heating\n", |
| 123 | + "@info \"Running model without deep heating...\"\n", |
| 124 | + "out_dir_off = joinpath(OUT_DIR_BASE, \"no_deep_heating\")\n", |
| 125 | + "atmos_off = run_model(out_dir_off, false)\n", |
| 126 | + "@info \"Done\"" |
| 127 | + ] |
| 128 | + }, |
| 129 | + { |
| 130 | + "cell_type": "code", |
| 131 | + "execution_count": null, |
| 132 | + "id": "6c6e6f80", |
| 133 | + "metadata": {}, |
| 134 | + "outputs": [], |
| 135 | + "source": [ |
| 136 | + "# Run model WITH deep heating\n", |
| 137 | + "@info \"Running model with deep heating...\"\n", |
| 138 | + "out_dir_on = joinpath(OUT_DIR_BASE, \"with_deep_heating\")\n", |
| 139 | + "atmos_on = run_model(out_dir_on, true)\n", |
| 140 | + "@info \"Done\"" |
| 141 | + ] |
| 142 | + }, |
| 143 | + { |
| 144 | + "cell_type": "code", |
| 145 | + "execution_count": null, |
| 146 | + "id": "1ca11aba", |
| 147 | + "metadata": {}, |
| 148 | + "outputs": [], |
| 149 | + "source": [ |
| 150 | + "# Compare results\n", |
| 151 | + "println(\"=\"^60)\n", |
| 152 | + "println(\"COMPARISON OF RESULTS\")\n", |
| 153 | + "println(\"=\"^60)\n", |
| 154 | + "\n", |
| 155 | + "# TOA fluxes\n", |
| 156 | + "OLR_off = atmos_off.flux_u_lw[1]\n", |
| 157 | + "OLR_on = atmos_on.flux_u_lw[1]\n", |
| 158 | + "\n", |
| 159 | + "flux_tot_toa_off = atmos_off.flux_tot[1]\n", |
| 160 | + "flux_tot_toa_on = atmos_on.flux_tot[1]\n", |
| 161 | + "\n", |
| 162 | + "flux_tot_boa_off = atmos_off.flux_tot[end]\n", |
| 163 | + "flux_tot_boa_on = atmos_on.flux_tot[end]\n", |
| 164 | + "\n", |
| 165 | + "# Deep heating flux at BOA (should equal F_deep_expected)\n", |
| 166 | + "flux_deep_boa = atmos_on.flux_deep[end]\n", |
| 167 | + "\n", |
| 168 | + "@printf(\"\\nWithout Deep Heating:\\n\")\n", |
| 169 | + "@printf(\" OLR (LW up at TOA): %.2f W/m²\\n\", OLR_off)\n", |
| 170 | + "@printf(\" Total flux at TOA: %.2f W/m²\\n\", flux_tot_toa_off)\n", |
| 171 | + "@printf(\" Total flux at BOA: %.2f W/m²\\n\", flux_tot_boa_off)\n", |
| 172 | + "\n", |
| 173 | + "@printf(\"\\nWith Deep Heating (ε=%.2f):\\n\", deep_efficiency)\n", |
| 174 | + "@printf(\" OLR (LW up at TOA): %.2f W/m²\\n\", OLR_on)\n", |
| 175 | + "@printf(\" Total flux at TOA: %.2f W/m²\\n\", flux_tot_toa_on)\n", |
| 176 | + "@printf(\" Total flux at BOA: %.2f W/m²\\n\", flux_tot_boa_on)\n", |
| 177 | + "@printf(\" Deep heating flux (BOA): %.2f W/m²\\n\", flux_deep_boa)\n", |
| 178 | + "\n", |
| 179 | + "@printf(\"\\nDifferences:\\n\")\n", |
| 180 | + "@printf(\" ΔOLR: %.2f W/m²\\n\", OLR_on - OLR_off)\n", |
| 181 | + "@printf(\" ΔTotal flux (TOA): %.2f W/m²\\n\", flux_tot_toa_on - flux_tot_toa_off)\n", |
| 182 | + "@printf(\" ΔTotal flux (BOA): %.2f W/m²\\n\", flux_tot_boa_on - flux_tot_boa_off)\n", |
| 183 | + "\n", |
| 184 | + "@printf(\"\\nExpected deep heating flux: %.2f W/m²\\n\", F_deep_expected)\n", |
| 185 | + "@printf(\"Actual deep heating flux: %.2f W/m²\\n\", flux_deep_boa)\n", |
| 186 | + "@printf(\"Difference: %.4f W/m² (%.2f%%)\\n\",\n", |
| 187 | + " abs(flux_deep_boa - F_deep_expected),\n", |
| 188 | + " 100*abs(flux_deep_boa - F_deep_expected)/F_deep_expected)" |
| 189 | + ] |
| 190 | + }, |
| 191 | + { |
| 192 | + "cell_type": "code", |
| 193 | + "execution_count": null, |
| 194 | + "id": "f963a493", |
| 195 | + "metadata": {}, |
| 196 | + "outputs": [], |
| 197 | + "source": [ |
| 198 | + "# Plot temperature profiles\n", |
| 199 | + "p1 = plot(xlabel=\"Temperature [K]\", ylabel=\"Pressure [bar]\",\n", |
| 200 | + " yflip=true, yscale=:log10, legend=:topright,\n", |
| 201 | + " title=\"Temperature Profile\", size=(500, 400))\n", |
| 202 | + "\n", |
| 203 | + "plot!(p1, atmos_off.tmp, atmos_off.p .* 1e-5,\n", |
| 204 | + " label=\"No Deep Heating\", lw=2, color=:blue)\n", |
| 205 | + "plot!(p1, atmos_on.tmp, atmos_on.p .* 1e-5,\n", |
| 206 | + " label=\"With Deep Heating\", lw=2, color=:red, ls=:dash)\n", |
| 207 | + "\n", |
| 208 | + "display(p1)" |
| 209 | + ] |
| 210 | + }, |
| 211 | + { |
| 212 | + "cell_type": "code", |
| 213 | + "execution_count": null, |
| 214 | + "id": "1aa3bee6", |
| 215 | + "metadata": {}, |
| 216 | + "outputs": [], |
| 217 | + "source": [ |
| 218 | + "# Plot flux profiles\n", |
| 219 | + "p2 = plot(xlabel=\"Flux [W m⁻²]\", ylabel=\"Pressure [bar]\",\n", |
| 220 | + " yflip=true, yscale=:log10, legend=:topright,\n", |
| 221 | + " title=\"Total Flux Profile\", size=(500, 400))\n", |
| 222 | + "\n", |
| 223 | + "plot!(p2, atmos_off.flux_tot, atmos_off.pl .* 1e-5,\n", |
| 224 | + " label=\"Total (no deep)\", lw=2, color=:blue)\n", |
| 225 | + "plot!(p2, atmos_on.flux_tot, atmos_on.pl .* 1e-5,\n", |
| 226 | + " label=\"Total (with deep)\", lw=2, color=:red)\n", |
| 227 | + "plot!(p2, atmos_on.flux_deep, atmos_on.pl .* 1e-5,\n", |
| 228 | + " label=\"Deep Heating\", lw=2, color=:magenta, ls=:dash)\n", |
| 229 | + "\n", |
| 230 | + "# Mark deposition pressure\n", |
| 231 | + "hline!(p2, [deep_P_dep * 1e-5], ls=:dot, color=:gray, label=\"P_dep\")\n", |
| 232 | + "\n", |
| 233 | + "display(p2)" |
| 234 | + ] |
| 235 | + }, |
| 236 | + { |
| 237 | + "cell_type": "code", |
| 238 | + "execution_count": null, |
| 239 | + "id": "05050f1a", |
| 240 | + "metadata": {}, |
| 241 | + "outputs": [], |
| 242 | + "source": [ |
| 243 | + "# Plot deep heating flux gradient (dF/dP profile)\n", |
| 244 | + "# Calculate the flux gradient from the cumulative flux\n", |
| 245 | + "dF_deep = diff(atmos_on.flux_deep)\n", |
| 246 | + "dp = diff(atmos_on.pl)\n", |
| 247 | + "dF_dP = dF_deep ./ dp\n", |
| 248 | + "\n", |
| 249 | + "p3 = plot(xlabel=\"dF/dP [W m⁻² Pa⁻¹]\", ylabel=\"Pressure [bar]\",\n", |
| 250 | + " yflip=true, yscale=:log10, legend=:topright,\n", |
| 251 | + " title=\"Deep Heating Rate (dF/dP)\", size=(500, 400))\n", |
| 252 | + "\n", |
| 253 | + "plot!(p3, dF_dP, atmos_on.p .* 1e-5,\n", |
| 254 | + " label=\"dF_deep/dP\", lw=2, color=:magenta)\n", |
| 255 | + "\n", |
| 256 | + "# Mark deposition pressure\n", |
| 257 | + "hline!(p3, [deep_P_dep * 1e-5], ls=:dot, color=:gray, label=\"P_dep\")\n", |
| 258 | + "\n", |
| 259 | + "display(p3)" |
| 260 | + ] |
| 261 | + }, |
| 262 | + { |
| 263 | + "cell_type": "code", |
| 264 | + "execution_count": null, |
| 265 | + "id": "30699ab1", |
| 266 | + "metadata": {}, |
| 267 | + "outputs": [], |
| 268 | + "source": [ |
| 269 | + "# Combined plot with all flux components\n", |
| 270 | + "p4 = plot(xlabel=\"Flux [W m⁻²]\", ylabel=\"Pressure [bar]\",\n", |
| 271 | + " yflip=true, yscale=:log10, legend=:outerright,\n", |
| 272 | + " title=\"Flux Components (With Deep Heating)\", size=(700, 450))\n", |
| 273 | + "\n", |
| 274 | + "# Radiative fluxes\n", |
| 275 | + "plot!(p4, atmos_on.flux_u_lw, atmos_on.pl .* 1e-5,\n", |
| 276 | + " label=\"LW Up\", lw=2, color=:red)\n", |
| 277 | + "plot!(p4, -atmos_on.flux_d_lw, atmos_on.pl .* 1e-5,\n", |
| 278 | + " label=\"LW Down\", lw=2, color=:red, ls=:dash)\n", |
| 279 | + "plot!(p4, atmos_on.flux_u_sw, atmos_on.pl .* 1e-5,\n", |
| 280 | + " label=\"SW Up\", lw=2, color=:orange)\n", |
| 281 | + "plot!(p4, -atmos_on.flux_d_sw, atmos_on.pl .* 1e-5,\n", |
| 282 | + " label=\"SW Down\", lw=2, color=:orange, ls=:dash)\n", |
| 283 | + "\n", |
| 284 | + "# Convective flux\n", |
| 285 | + "plot!(p4, atmos_on.flux_cdry, atmos_on.pl .* 1e-5,\n", |
| 286 | + " label=\"Convection\", lw=2, color=:blue)\n", |
| 287 | + "\n", |
| 288 | + "# Deep heating flux\n", |
| 289 | + "plot!(p4, atmos_on.flux_deep, atmos_on.pl .* 1e-5,\n", |
| 290 | + " label=\"Deep Heating\", lw=3, color=:magenta)\n", |
| 291 | + "\n", |
| 292 | + "# Total flux\n", |
| 293 | + "plot!(p4, atmos_on.flux_tot, atmos_on.pl .* 1e-5,\n", |
| 294 | + " label=\"Total\", lw=2, color=:black)\n", |
| 295 | + "\n", |
| 296 | + "# Mark deposition pressure\n", |
| 297 | + "hline!(p4, [deep_P_dep * 1e-5], ls=:dot, color=:gray, lw=1, label=\"P_dep\")\n", |
| 298 | + "\n", |
| 299 | + "display(p4)" |
| 300 | + ] |
| 301 | + }, |
| 302 | + { |
| 303 | + "cell_type": "code", |
| 304 | + "execution_count": null, |
| 305 | + "id": "3cfe29c1", |
| 306 | + "metadata": {}, |
| 307 | + "outputs": [], |
| 308 | + "source": [ |
| 309 | + "# Save combined comparison plot\n", |
| 310 | + "p_combined = plot(p1, p2, p3, p4, layout=(2, 2), size=(1000, 800))\n", |
| 311 | + "savefig(p_combined, joinpath(OUT_DIR_BASE, \"deep_heating_comparison.png\"))\n", |
| 312 | + "@info \"Saved comparison plot to $(joinpath(OUT_DIR_BASE, \"deep_heating_comparison.png\"))\"\n", |
| 313 | + "display(p_combined)" |
| 314 | + ] |
| 315 | + }, |
| 316 | + { |
| 317 | + "cell_type": "code", |
| 318 | + "execution_count": null, |
| 319 | + "id": "62b1b230", |
| 320 | + "metadata": {}, |
| 321 | + "outputs": [], |
| 322 | + "source": [ |
| 323 | + "# Clean up\n", |
| 324 | + "AGNI.atmosphere.deallocate!(atmos_off)\n", |
| 325 | + "AGNI.atmosphere.deallocate!(atmos_on)\n", |
| 326 | + "@info \"Test complete!\"" |
| 327 | + ] |
| 328 | + } |
| 329 | + ], |
| 330 | + "metadata": { |
| 331 | + "kernelspec": { |
| 332 | + "display_name": "venus", |
| 333 | + "language": "python", |
| 334 | + "name": "python3" |
| 335 | + }, |
| 336 | + "language_info": { |
| 337 | + "name": "python", |
| 338 | + "version": "3.10.18" |
| 339 | + } |
| 340 | + }, |
| 341 | + "nbformat": 4, |
| 342 | + "nbformat_minor": 5 |
| 343 | +} |
0 commit comments