From 3ed79e3efae348608ca4bd9475054c1d226b935a Mon Sep 17 00:00:00 2001 From: zdaq12 Date: Sun, 13 Sep 2026 13:34:23 -0500 Subject: [PATCH 01/19] add dry deposition support to the sectional model --- CMakeLists.txt | 2 +- scenarios/7_drydep/1_run_sect.sh | 12 ++ scenarios/7_drydep/2_process_modal.sh | 2 +- scenarios/7_drydep/2_process_sect.sh | 12 ++ scenarios/7_drydep/README | 75 +++++++++++ scenarios/7_drydep/drydep_modal.spec | 10 +- scenarios/7_drydep/drydep_sect.spec | 45 +++++++ src/output.F90 | 22 +++- src/partmc.F90 | 6 + src/run_exact.F90 | 4 +- src/run_sect.F90 | 100 +++++++++++--- src/scenario.F90 | 123 ++++++++++++++++-- test/brownian/run_sect.spec | 9 ++ test/loss/loss_drydep_sect_aero_time_ref.txt | 9 ++ test/loss/loss_modal_drydep_aero_time_ref.txt | 4 +- ...ss_modal_drydep_quadpack_aero_time_ref.txt | 4 +- test/loss/run_drydep_sect.spec | 44 +++++++ test/loss/run_drydep_sect_dil.spec | 44 +++++++ test/loss/test_loss_16.sh | 13 ++ test/loss/test_loss_17.sh | 18 +++ test/parallel/run_sect.spec | 9 ++ test/sedi/run_sect.spec | 9 ++ 22 files changed, 530 insertions(+), 46 deletions(-) create mode 100755 scenarios/7_drydep/1_run_sect.sh create mode 100755 scenarios/7_drydep/2_process_sect.sh create mode 100644 scenarios/7_drydep/README create mode 100644 scenarios/7_drydep/drydep_sect.spec create mode 100644 test/loss/loss_drydep_sect_aero_time_ref.txt create mode 100644 test/loss/run_drydep_sect.spec create mode 100644 test/loss/run_drydep_sect_dil.spec create mode 100755 test/loss/test_loss_16.sh create mode 100755 test/loss/test_loss_17.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index e07fb70a5..d8dbfdf4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -438,7 +438,7 @@ target_link_libraries(numeric_diff partmclib) add_executable(numeric_average src/numeric_average.F90) ###################################################################### -# scenarios/1_urban_plume/urban_plum_process +# scenarios/1_urban_plume/urban_plume_process add_executable(urban_plume_process scenarios/1_urban_plume/urban_plume_process.F90) diff --git a/scenarios/7_drydep/1_run_sect.sh b/scenarios/7_drydep/1_run_sect.sh new file mode 100755 index 000000000..6f19d17b2 --- /dev/null +++ b/scenarios/7_drydep/1_run_sect.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# exit on error +set -e +# turn on command echoing +set -v + +mkdir -p out + +../../build/partmc drydep_sect.spec + +# Now run ./2_process_sect.sh to process the data diff --git a/scenarios/7_drydep/2_process_modal.sh b/scenarios/7_drydep/2_process_modal.sh index 2e2aceb6c..6bc4a247b 100755 --- a/scenarios/7_drydep/2_process_modal.sh +++ b/scenarios/7_drydep/2_process_modal.sh @@ -7,4 +7,4 @@ set -v # The data should have already been generated by ./1_run_modal.sh -../../build/drydep_modal_process out/modal_dpg_00001000000000000000_sig_2_5_emerson_grass +../../build/drydep_modal_process out/drydep_modal diff --git a/scenarios/7_drydep/2_process_sect.sh b/scenarios/7_drydep/2_process_sect.sh new file mode 100755 index 000000000..1cc619937 --- /dev/null +++ b/scenarios/7_drydep/2_process_sect.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# exit on error +set -e +# turn on command echoing +set -v + +# The data should have already been generated by ./1_run_sect.sh + +../../build/extract_sectional_aero_time out/drydep_sect +../../build/extract_sectional_aero_size --num out/drydep_sect +../../build/extract_sectional_aero_size --mass out/drydep_sect diff --git a/scenarios/7_drydep/README b/scenarios/7_drydep/README new file mode 100644 index 000000000..b156ba22f --- /dev/null +++ b/scenarios/7_drydep/README @@ -0,0 +1,75 @@ +Dry deposition scenario +======================= + +Demonstrates dry deposition of aerosol particles using both of the +representations that support it: the modal representation and the +sectional (binned) representation. Both are run with identical +inputs -- same initial distribution, meteorology, and deposition +parameters -- so their results can be compared directly. + +Running +------- + +Modal: + + ./1_run_modal.sh + ./2_process_modal.sh + +Sectional: + + ./1_run_sect.sh + ./2_process_sect.sh + +Each simulates 8 hours with hourly output. The modal case is +post-processed by drydep_modal_process, which writes total number and +mass concentration time series to out/drydep_modal_process.nc. The +sectional case uses the standard extract_sectional_* tools, which +write plain-text time series and size distributions. + +Configuration +------------- + +Both runs share: + + aero_init_dist.dat single log-normal mode, 3.2e9 m^-3, geometric + mean diameter 10 nm, narrow (sigma = 1.1) + aero_data.dat single species (SO4) + drydep_params.dat deposition parameters (see below) + temp.dat, pres.dat, height.dat, gas_*.dat, aero_back*.dat, + aero_emit*.dat meteorology, emissions and background + +Emissions and background rates are zero, and condensation and the +other microphysical processes are disabled, so dry deposition is the +only active process. The sectional case runs with the zero +coagulation kernel, which leaves the size distribution unchanged. It +also sets do_aero_dilution to no; the modal representation has no +dilution treatment, so this is what makes the two comparable. + +Deposition parameters +--------------------- + +drydep_params.dat holds the coefficients of the size-resolved +deposition scheme (Zhang et al. 2001; Emerson et al. 2020). The +combining equation is + + V_d = V_s + 1 / (R_a + R_s) + +following Slinn (1982), as used by both parameterizations. The +land-use-dependent quantities (z_rough, A, alpha, gamma) and the +scheme coefficients (C_B, C_IN, C_IM, nu, beta) are all read from +this file, so switching land-use category or parameterization needs +no source changes or rebuild -- copy the file, edit the values, and +point drydep_params at it. + +Comparing the two representations +--------------------------------- + +The modal and sectional results differ substantially for this case +(tens of percent in total number by the end of the run). This is not +a numerical artifact: the sectional solution is converged with +respect to bin count, and is independently validated against the +particle-resolved representation in test/loss/test_loss_17.sh. The +difference reflects the modal representation holding a fixed +log-normal shape while deposition removes particles at strongly +size-dependent rates, which is largest for narrow distributions +undergoing rapid deposition, as here. diff --git a/scenarios/7_drydep/drydep_modal.spec b/scenarios/7_drydep/drydep_modal.spec index 7a4bdb5f5..5bafdd44b 100644 --- a/scenarios/7_drydep/drydep_modal.spec +++ b/scenarios/7_drydep/drydep_modal.spec @@ -1,5 +1,5 @@ run_type modal # modal run -output_prefix out/modal_dpg_10_0_sig_2_5_emerson_broad +output_prefix out/drydep_modal # prefix of output files t_max 28800 # total simulation time (s) del_t 60 # timestep (s) @@ -7,8 +7,8 @@ t_output 3600 # output interval (0 disables) (s) t_progress 0 # progress printing interval (0 disables) (s) n_bin 1000 # number of bins (for processing purposes) -d_min 4e-8 # minimum diameter (m) -d_max 2.5e-3 # maximum diameter (m) +d_min 1e-10 # minimum diameter (m) +d_max 1e-3 # maximum diameter (m) do_camp_chem no # whether to use CAMP for chemistry (yes/no) do_tchem no # whether to use TChem for chemistry (yes/no) @@ -16,7 +16,7 @@ do_tchem no # whether to use TChem for chemistry (yes gas_data gas_data.dat # file containing gas data aerosol_data aero_data.dat # file containing aerosol data do_fractal no # whether to do fractal treatment (yes/no) -aerosol_init aero_init_run.dat +aerosol_init aero_init_dist.dat # aerosol initial condition file temp_profile temp.dat # temperature profile file pressure_profile pres.dat # pressure profile file @@ -26,7 +26,7 @@ gas_background gas_back.dat # background gas concentrations file aero_emissions aero_emit.dat # aerosol emissions file aero_background aero_back.dat # aerosol background file loss_function drydep # loss function specification -drydep_params drydep_broad_emerson.dat +drydep_params drydep_params.dat # dry deposition parameters rel_humidity 0.95 # initial relative humidity (1) latitude 0 # latitude (degrees, -90 to 90) diff --git a/scenarios/7_drydep/drydep_sect.spec b/scenarios/7_drydep/drydep_sect.spec new file mode 100644 index 000000000..c4dfc7e79 --- /dev/null +++ b/scenarios/7_drydep/drydep_sect.spec @@ -0,0 +1,45 @@ +run_type sectional # sectional (binned) run +output_prefix out/drydep_sect # prefix of output files + +t_max 28800 # total simulation time (s) +del_t 60 # timestep (s) +t_output 3600 # output interval (0 disables) (s) +t_progress 0 # progress printing interval (0 disables) (s) + +n_bin 1000 # number of bins +d_min 1e-10 # minimum diameter (m) +d_max 1e-3 # maximum diameter (m) + +do_camp_chem no # whether to use CAMP for chemistry (yes/no) +do_tchem no # whether to use TChem for chemistry (yes/no) + +gas_data gas_data.dat # file containing gas data +aerosol_data aero_data.dat # file containing aerosol data +do_fractal no # whether to do fractal treatment (yes/no) +aerosol_init aero_init_dist.dat # aerosol initial condition file + +temp_profile temp.dat # temperature profile file +pressure_profile pres.dat # pressure profile file +height_profile height.dat # height profile file +gas_emissions gas_emit.dat # gas emissions file +gas_background gas_back.dat # background gas concentrations file +aero_emissions aero_emit.dat # aerosol emissions file +aero_background aero_back.dat # aerosol background file +loss_function drydep # loss function specification +drydep_params drydep_params.dat # dry deposition parameters + +rel_humidity 0.95 # initial relative humidity (1) +latitude 0 # latitude (degrees, -90 to 90) +longitude 0 # longitude (degrees, -180 to 180) +altitude 0 # altitude (m) +start_time 21600 # start time (s since 00:00 UTC) +start_day 200 # start day of year (UTC) + +do_aero_dilution no # whether to do aerosol dilution (yes/no) +do_coagulation yes # whether to do coagulation (yes/no) +coag_kernel zero # coagulation kernel (zero = no coagulation) +do_condensation no # whether to do condensation (yes/no) +do_mosaic no # whether to do MOSAIC (yes/no) +do_optical no # whether to compute optical props (yes/no) +do_nucleation no # whether to do nucleation (yes/no) +do_immersion_freezing no # whether to do freezing (yes/no) diff --git a/src/output.F90 b/src/output.F90 index 91272b525..e204144a5 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -78,6 +78,7 @@ module pmc_output use pmc_gas_data use pmc_scenario use pmc_mpi + use pmc_scenario #ifdef PMC_USE_MPI use mpi #endif @@ -662,7 +663,7 @@ end subroutine input_n_files !> Write the current sectional data. subroutine output_sectional(prefix, bin_grid, aero_data, aero_binned, & - gas_data, gas_state, env_state, index, time, del_t, uuid) + gas_data, gas_state, env_state, scenario, index, time, del_t, uuid) !> Prefix of filename to write character(len=*), intent(in) :: prefix @@ -678,6 +679,8 @@ subroutine output_sectional(prefix, bin_grid, aero_data, aero_binned, & type(gas_state_t), intent(in) :: gas_state !> Environment state. type(env_state_t), intent(in) :: env_state + !> Scenario data. + type(scenario_t), intent(in) :: scenario !> Filename index. integer, intent(in) :: index !> Current time (s). @@ -705,6 +708,10 @@ subroutine output_sectional(prefix, bin_grid, aero_data, aero_binned, & call aero_binned_output_netcdf(aero_binned, ncid, bin_grid, & aero_data) + if (scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_DRYDEP) then + call drydep_params_output_netcdf(scenario%drydep, ncid) + end if + call pmc_nc_check(nf90_close(ncid)) end subroutine output_sectional @@ -713,7 +720,7 @@ end subroutine output_sectional !> Input sectional data. subroutine input_sectional(filename, index, time, del_t, uuid, bin_grid, & - aero_data, aero_binned, gas_data, gas_state, env_state) + aero_data, aero_binned, gas_data, gas_state, env_state, scenario) !> Filename to read. character(len=*), intent(in) :: filename @@ -737,6 +744,8 @@ subroutine input_sectional(filename, index, time, del_t, uuid, bin_grid, & type(gas_state_t), optional, intent(inout) :: gas_state !> Environment state. type(env_state_t), optional, intent(inout) :: env_state + !> Scenario data. + type(scenario_t), optional, intent(inout) :: scenario integer :: ncid @@ -779,6 +788,10 @@ subroutine input_sectional(filename, index, time, del_t, uuid, bin_grid, & call env_state_input_netcdf(env_state, ncid) end if + if (present(scenario)) then + call drydep_params_input_netcdf(scenario%drydep, ncid) + end if + call pmc_nc_close(ncid) end subroutine input_sectional @@ -834,7 +847,10 @@ subroutine output_modal(prefix, aero_binned, aero_dist, aero_data, & call gas_state_output_netcdf(gas_state, ncid, gas_data) call aero_data_output_netcdf(aero_data, ncid) call bin_grid_output_netcdf(bin_grid, ncid, "diam", unit="m") - call drydep_params_output_netcdf(scenario%drydep, ncid) + + if (scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_DRYDEP) then + call drydep_params_output_netcdf(scenario%drydep, ncid) + end if call pmc_nc_check(nf90_close(ncid)) diff --git a/src/partmc.F90 b/src/partmc.F90 index 7a17c9222..3407abe96 100644 --- a/src/partmc.F90 +++ b/src/partmc.F90 @@ -732,6 +732,11 @@ subroutine partmc_sect(file) !! format should be \subpage input_format_aero_dist !! - \subpage input_format_scenario !! - \subpage input_format_env_state + !! - \b do_aero_dilution (logical): whether to apply aerosol + !! dilution. If \c no, both the background-exchange dilution and + !! the mixing-layer-growth correction are skipped, which allows + !! other processes (for example dry deposition) to be studied in + !! isolation. !! - \b do_coagulation (logical): whether to perform particle !! coagulation. If \c do_coagulation is \c yes, then the !! following parameters must also be provided: @@ -771,6 +776,7 @@ subroutine partmc_sect(file) !! start_time 0 # start time (s since 00:00 UTC) !! start_day 1 # start day of year (UTC) !! + !! do_aero_dilution yes # whether to do dilution (yes/no) !! do_coagulation yes # whether to do coagulation (yes/no) !! kernel brown # coagulation kernel !! diff --git a/src/run_exact.F90 b/src/run_exact.F90 index c873ed252..493f846ff 100644 --- a/src/run_exact.F90 +++ b/src/run_exact.F90 @@ -78,8 +78,8 @@ subroutine run_exact(bin_grid, scenario, env_state, aero_data, & run_exact_opt%coag_kernel_type, aero_dist_init, scenario, & env_state, time, aero_binned) call output_sectional(run_exact_opt%prefix, bin_grid, aero_data, & - aero_binned, gas_data, gas_state, env_state, i_time + 1, & - time, run_exact_opt%t_output, run_exact_opt%uuid) + aero_binned, gas_data, gas_state, env_state, scenario, & + i_time + 1, time, run_exact_opt%t_output, run_exact_opt%uuid) end do end subroutine run_exact diff --git a/src/run_sect.F90 b/src/run_sect.F90 index a1bfb9b71..18d0e0faf 100644 --- a/src/run_sect.F90 +++ b/src/run_sect.F90 @@ -31,19 +31,35 @@ module pmc_run_sect !> Options controlling the operation of run_sect(). type run_sect_opt_t !> Final time (s). - real(kind=dp) :: t_max - !> Timestep for coagulation (s). - real(kind=dp) :: del_t - !> Output interval (0 disables) (s). - real(kind=dp) :: t_output - !> Progress interval (0 disables) (s). - real(kind=dp) :: t_progress - !> Whether to do coagulation. - logical :: do_coagulation - !> Output prefix. + real(kind=dp) :: t_max + !> Timestep for coagulation (s). + real(kind=dp) :: del_t + !> Output interval (0 disables) (s). + real(kind=dp) :: t_output + !> Progress interval (0 disables) (s). + real(kind=dp) :: t_progress + !> Whether to do aerosol background dilution. + logical :: do_aero_dilution + !> Type of coagulation kernel. + integer :: coag_kernel_type + !> Whether to do coagulation. + logical :: do_coagulation + !> Whether to run CAMP. + logical :: do_camp_chem + !> Whether to run TChem. + logical :: do_tchem + !> Whether to do condensation. + logical :: do_condensation + !> Whether to run MOSAIC. + logical :: do_mosaic + !> Whether to compute optical properties. + logical :: do_optical + !> Whether to do nucleation. + logical :: do_nucleation + !> Whether to do immersion freezing. + logical :: do_immersion_freezing + !> Output prefix. character(len=300) :: prefix - !> Type of coagulation kernel. - integer :: coag_kernel_type !> UUID of the simulation. character(len=PMC_UUID_LEN) :: uuid end type run_sect_opt_t @@ -88,6 +104,7 @@ subroutine run_sect(bin_grid, gas_data, aero_data, aero_dist, & integer i, j, i_time, num_t, i_summary logical do_output, do_progress + real(kind=dp) removed call check_time_multiple("t_max", run_sect_opt%t_max, & "del_t", run_sect_opt%del_t) @@ -126,6 +143,7 @@ subroutine run_sect(bin_grid, gas_data, aero_data, aero_dist, & last_progress_time = 0d0 time = 0d0 i_summary = 1 + removed = 0d0 ! precompute kernel values for all pairs of bins call bin_kernel(bin_grid_size(bin_grid), bin_grid%centers, aero_data, & @@ -149,7 +167,7 @@ subroutine run_sect(bin_grid, gas_data, aero_data, aero_dist, & last_output_time, do_output) if (do_output) then call output_sectional(run_sect_opt%prefix, bin_grid, aero_data, & - aero_binned, gas_data, gas_state, env_state, i_summary, & + aero_binned, gas_data, gas_state, env_state, scenario, i_summary, & time, run_sect_opt%t_output, run_sect_opt%uuid) end if @@ -174,7 +192,8 @@ subroutine run_sect(bin_grid, gas_data, aero_data, aero_dist, & call scenario_update_gas_state(scenario, run_sect_opt%del_t, & env_state, old_env_state, gas_data, gas_state) call scenario_update_aero_binned(scenario, run_sect_opt%del_t, & - env_state, old_env_state, bin_grid, aero_data, aero_binned) + env_state, old_env_state, bin_grid, aero_data, & + run_sect_opt%do_aero_dilution, aero_binned) ! print output call check_event(time, run_sect_opt%del_t, run_sect_opt%t_output, & @@ -182,8 +201,8 @@ subroutine run_sect(bin_grid, gas_data, aero_data, aero_dist, & if (do_output) then i_summary = i_summary + 1 call output_sectional(run_sect_opt%prefix, bin_grid, aero_data, & - aero_binned, gas_data, gas_state, env_state, i_summary, & - time, run_sect_opt%t_output, run_sect_opt%uuid) + aero_binned, gas_data, gas_state, env_state, scenario, & + i_summary, time, run_sect_opt%t_output, run_sect_opt%uuid) end if ! print progress to stdout @@ -232,6 +251,19 @@ subroutine spec_file_read_run_sect(file, run_sect_opt, aero_data, & call spec_file_read_radius_bin_grid(file, bin_grid) + call spec_file_read_logical(file, 'do_camp_chem', & + run_sect_opt%do_camp_chem) + if (run_sect_opt%do_camp_chem) then + call spec_file_die_msg(263948175, file, & + "sectional run does not support CAMP chemistry") + end if + + call spec_file_read_logical(file, 'do_tchem', run_sect_opt%do_tchem) + if (run_sect_opt%do_tchem) then + call spec_file_die_msg(195837264, file, & + "sectional run does not support TChem chemistry") + end if + call spec_file_read_string(file, 'gas_data', sub_filename) call spec_file_open(sub_filename, sub_file) call spec_file_read_gas_data(sub_file, gas_data) @@ -252,6 +284,9 @@ subroutine spec_file_read_run_sect(file, run_sect_opt, aero_data, & call spec_file_read_scenario(file, gas_data, aero_data, .false., scenario) call spec_file_read_env_state(file, env_state) + call spec_file_read_logical(file, 'do_aero_dilution', & + run_sect_opt%do_aero_dilution) + call spec_file_read_logical(file, 'do_coagulation', & run_sect_opt%do_coagulation) if (run_sect_opt%do_coagulation) then @@ -265,6 +300,39 @@ subroutine spec_file_read_run_sect(file, run_sect_opt, aero_data, & run_sect_opt%coag_kernel_type = COAG_KERNEL_TYPE_INVALID end if + call spec_file_read_logical(file, 'do_condensation', & + run_sect_opt%do_condensation) + if (run_sect_opt%do_condensation) then + call spec_file_die_msg(612938475, file, & + "sectional run does not support condensation") + end if + + call spec_file_read_logical(file, 'do_mosaic', run_sect_opt%do_mosaic) + if (run_sect_opt%do_mosaic) then + call spec_file_die_msg(584729163, file, & + "sectional run does not support MOSAIC chemistry") + end if + + call spec_file_read_logical(file, 'do_optical', run_sect_opt%do_optical) + if (run_sect_opt%do_optical) then + call spec_file_die_msg(527436819, file, & + "sectional run does not support optical properties calculation") + end if + + call spec_file_read_logical(file, 'do_nucleation', & + run_sect_opt%do_nucleation) + if (run_sect_opt%do_nucleation) then + call spec_file_die_msg(391847265, file, & + "sectional run does not support nucleation") + end if + + call spec_file_read_logical(file, 'do_immersion_freezing', & + run_sect_opt%do_immersion_freezing) + if (run_sect_opt%do_immersion_freezing) then + call spec_file_die_msg(748291635, file, & + "sectional run does not support immersion freezing") + end if + call spec_file_close(file) ! finished reading .spec data, now do the run diff --git a/src/scenario.F90 b/src/scenario.F90 index 07927a77b..c16fcf269 100644 --- a/src/scenario.F90 +++ b/src/scenario.F90 @@ -18,6 +18,7 @@ module pmc_scenario use pmc_gas_data use pmc_chamber use pmc_mpi + use pmc_netcdf #ifdef PMC_USE_MPI use mpi #endif @@ -381,7 +382,7 @@ end subroutine scenario_update_aero_state !! !! See scenario_update_gas_state() for a description of the model. subroutine scenario_update_aero_binned(scenario, delta_t, env_state, & - old_env_state, bin_grid, aero_data, aero_binned) + old_env_state, bin_grid, aero_data, do_aero_dilution, aero_binned) !> Scenario data. type(scenario_t), intent(in) :: scenario @@ -395,6 +396,8 @@ subroutine scenario_update_aero_binned(scenario, delta_t, env_state, & type(bin_grid_t), intent(in) :: bin_grid !> Aero data values. type(aero_data_t), intent(in) :: aero_data + !> Whether to do dilution. + logical, intent(in) :: do_aero_dilution !> Aero binned to update. type(aero_binned_t), intent(inout) :: aero_binned @@ -412,17 +415,23 @@ subroutine scenario_update_aero_binned(scenario, delta_t, env_state, & call aero_binned_add_scaled(aero_binned, emissions_binned, p) ! dilution - call aero_dist_interp_1d(scenario%aero_background, & - scenario%aero_dilution_time, scenario%aero_dilution_rate, & - env_state%elapsed_time, background, dilution_rate) - call aero_binned_add_aero_dist(background_binned, bin_grid, aero_data, & - background) - p = exp(- dilution_rate * delta_t) - if (env_state%height > old_env_state%height) then - p = p * old_env_state%height / env_state%height + if (do_aero_dilution) then + call aero_dist_interp_1d(scenario%aero_background, & + scenario%aero_dilution_time, scenario%aero_dilution_rate, & + env_state%elapsed_time, background, dilution_rate) + call aero_binned_add_aero_dist(background_binned, bin_grid, aero_data, & + background) + p = exp(- dilution_rate * delta_t) + if (env_state%height > old_env_state%height) then + p = p * old_env_state%height / env_state%height + end if + call aero_binned_scale(aero_binned, p) + call aero_binned_add_scaled(aero_binned, background_binned, 1d0 - p) end if - call aero_binned_scale(aero_binned, p) - call aero_binned_add_scaled(aero_binned, background_binned, 1d0 - p) + + ! loss + call scenario_binned_loss(scenario, bin_grid, delta_t, aero_data, & + env_state, aero_binned) end subroutine scenario_update_aero_binned @@ -622,7 +631,7 @@ real(kind=dp) function scenario_loss_rate_drydep(vol, density, aero_data, & R_s = 1.0d0 / (drydep_params%eps_0 * u_star * (E_B + E_IN + E_IM) * R1) ! Dry deposition - V_d = V_s + (1.0d0 / (R_a + R_s + R_a * R_s * V_s)) + V_d = V_s + (1.0d0 / (R_a + R_s)) ! The loss rate scenario_loss_rate_drydep = V_d / env_state%height @@ -733,7 +742,7 @@ real(kind=dp) function scenario_integrated_loss_rate_drydep(scenario, & R_s = 1.0d0 / (drydep_params%eps_0 * u_star * (E_B + E_IN + E_IM) * R1) ! Integrated deposition velocity - V_d_hat = V_g_hat + (1.0d0 / (R_a + R_s + R_a * R_s * V_g_hat)) + V_d_hat = V_g_hat + (1.0d0 / (R_a + R_s)) ! Loss rate scenario_integrated_loss_rate_drydep = V_d_hat / env_state%height @@ -868,7 +877,7 @@ real(kind=dp) function dep_vel_integrand(d_p) R_s = 1.0d0 / (drydep_params%eps_0 * u_star * (E_B + E_IN + E_IM) * R1) ! Deposition velocity - V_d = V_s + (1.0d0 / (R_a + R_s + R_a * R_s * V_s)) + V_d = V_s + (1.0d0 / (R_a + R_s)) ! Log-normal size distribution ln_dp = log(d_p) @@ -1120,6 +1129,92 @@ subroutine scenario_try_single_particle_loss(scenario, delta_t, & call aero_state_remove_particle_with_info(aero_state, i_part, aero_info) end subroutine scenario_try_single_particle_loss +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + !> Performs loss for a binned aerosol distribution for one time step. + subroutine scenario_binned_loss(scenario, bin_grid, delta_t, aero_data, & + env_state, aero_binned) + + !> Scenario data. + type(scenario_t), intent(in) :: scenario + !> Bin grid. + type(bin_grid_t), intent(in) :: bin_grid + !> Time increment to update over. + real(kind=dp), intent(in) :: delta_t + !> Aerosol data. + type(aero_data_t), intent(in) :: aero_data + !> Environmental state. + type(env_state_t), intent(in) :: env_state + !> Binned aerosol data. + type(aero_binned_t), intent(inout) :: aero_binned + + integer :: i_bin + real(kind=dp) :: density, vol, loss_rate, p + + if (scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_NONE .or. & + scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_INVALID) then + return + else if (scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_DRYDEP) then + + density = aero_data%density(1) + + do i_bin = 1,bin_grid_size(bin_grid) + + if (aero_binned%num_conc(i_bin) <= 0d0) cycle + + vol = aero_data_rad2vol(aero_data, bin_grid%centers(i_bin)) + loss_rate = scenario_loss_rate(scenario, vol, density, & + aero_data, env_state) + p = exp(- loss_rate * delta_t) + aero_binned%vol_conc(i_bin,:) = aero_binned%vol_conc(i_bin,:) * p + aero_binned%num_conc(i_bin) = aero_binned%vol_conc(i_bin,1) / vol + + end do + else + return + end if + + end subroutine scenario_binned_loss + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + !> Updates an array (of size equal to the number of sections) containing + !> the dry deposition velocity for each bin in a sectional simulation. + !! + !! This is a diagnostic helper: it returns deposition velocities (m s^{-1}) + !! rather than loss rates, by multiplying the rate from + !! scenario_loss_rate_drydep() back by the mixing layer height. It is not + !! used by the sectional time-stepping itself, which calls + !! scenario_binned_loss(). + subroutine scenario_section_drydep_rates(scenario, bin_grid, aero_data, & + env_state, rates) + + !> Scenario data. + type(scenario_t), intent(in) :: scenario + !> Bin grid. + type(bin_grid_t), intent(in) :: bin_grid + !> Aerosol data. + type(aero_data_t), intent(in) :: aero_data + !> Environmental state. + type(env_state_t), intent(in) :: env_state + !> Deposition velocities for each section/bin (m s^{-1}). + real(kind=dp), intent(inout) :: rates(:) + + integer :: i_bin + real(kind=dp) :: density, vol + + call assert_msg(516274839, size(rates) == bin_grid_size(bin_grid), & + "rates array size must match the number of bins") + + density = aero_data%density(1) + + do i_bin = 1,bin_grid_size(bin_grid) + vol = aero_data_rad2vol(aero_data, bin_grid%centers(i_bin)) + rates(i_bin) = scenario_loss_rate_drydep(vol, density, & + aero_data, env_state, scenario) * env_state%height + end do + + end subroutine scenario_section_drydep_rates !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/test/brownian/run_sect.spec b/test/brownian/run_sect.spec index 42bca8014..1c2d8d78f 100644 --- a/test/brownian/run_sect.spec +++ b/test/brownian/run_sect.spec @@ -10,6 +10,9 @@ n_bin 220 # number of bins d_min 1e-10 # minimum diameter (m) d_max 1e-4 # maximum diameter (m) +do_camp_chem no # whether to use CAMP for chemistry (yes/no) +do_tchem no # whether to use TChem for chemistry (yes/no) + gas_data gas_data.dat # file containing gas data aerosol_data aero_data.dat # file containing aerosol data do_fractal no # whether to do fractal treatment @@ -31,5 +34,11 @@ altitude 0 # altitude (m) start_time 0 # start time (s since 00:00 UTC) start_day 1 # start day of year (UTC) +do_aero_dilution yes # whether to do aerosol dilution (yes/no) do_coagulation yes # whether to do coagulation (yes/no) coag_kernel brown # coagulation kernel +do_condensation no # whether to do condensation (yes/no) +do_mosaic no # whether to do MOSAIC (yes/no) +do_optical no # whether to compute optical props (yes/no) +do_nucleation no # whether to do nucleation (yes/no) +do_immersion_freezing no # whether to do freezing (yes/no) diff --git a/test/loss/loss_drydep_sect_aero_time_ref.txt b/test/loss/loss_drydep_sect_aero_time_ref.txt new file mode 100644 index 000000000..188c11782 --- /dev/null +++ b/test/loss/loss_drydep_sect_aero_time_ref.txt @@ -0,0 +1,9 @@ + 0.000000000000000E+000 0.999999999999441E+011 0.816871877909070E-003 0.816871877909070E-003 + 0.216000000000000E+005 0.959201656802061E+011 0.560485938369744E-003 0.560485938369744E-003 + 0.432000000000000E+005 0.921176166490367E+011 0.461610876969429E-003 0.461610876969429E-003 + 0.648000000000000E+005 0.885498978334148E+011 0.404755189414825E-003 0.404755189414825E-003 + 0.864000000000000E+005 0.851889372853975E+011 0.365719514353607E-003 0.365719514353607E-003 + 0.108000000000000E+006 0.820135529586750E+011 0.336170930733709E-003 0.336170930733709E-003 + 0.129600000000000E+006 0.790066637161495E+011 0.312443981572514E-003 0.312443981572514E-003 + 0.151200000000000E+006 0.761539664888974E+011 0.292641986522460E-003 0.292641986522460E-003 + 0.172800000000000E+006 0.734431974710473E+011 0.275665054596936E-003 0.275665054596936E-003 diff --git a/test/loss/loss_modal_drydep_aero_time_ref.txt b/test/loss/loss_modal_drydep_aero_time_ref.txt index 5a10669ab..0ca75772b 100644 --- a/test/loss/loss_modal_drydep_aero_time_ref.txt +++ b/test/loss/loss_modal_drydep_aero_time_ref.txt @@ -1,3 +1,3 @@ 0.000000000000000E+000 0.999999999999441E+011 0.816871877909070E-003 0.816871877909070E-003 - 0.180000000000000E+004 0.995999847146402E+011 0.746687557423342E-003 0.746687557423342E-003 - 0.360000000000000E+004 0.991934647238068E+011 0.684687037382628E-003 0.684687037382628E-003 + 0.180000000000000E+004 0.995993315271912E+011 0.742771143670393E-003 0.742771143670393E-003 + 0.360000000000000E+004 0.991916756145020E+011 0.677848857341900E-003 0.677848857341900E-003 diff --git a/test/loss/loss_modal_drydep_quadpack_aero_time_ref.txt b/test/loss/loss_modal_drydep_quadpack_aero_time_ref.txt index 090273568..a02fc0308 100644 --- a/test/loss/loss_modal_drydep_quadpack_aero_time_ref.txt +++ b/test/loss/loss_modal_drydep_quadpack_aero_time_ref.txt @@ -1,3 +1,3 @@ 0.000000000000000E+000 0.999999999999441E+011 0.816871877909070E-003 0.816871877909070E-003 - 0.180000000000000E+004 0.996500221922136E+011 0.778011861834278E-003 0.778011861834278E-003 - 0.360000000000000E+004 0.992987796737540E+011 0.741776762240038E-003 0.741776762240038E-003 + 0.180000000000000E+004 0.996494353546575E+011 0.775594027333591E-003 0.775594027333591E-003 + 0.360000000000000E+004 0.992974619476345E+011 0.737283873903109E-003 0.737283873903109E-003 diff --git a/test/loss/run_drydep_sect.spec b/test/loss/run_drydep_sect.spec new file mode 100644 index 000000000..c186ed18a --- /dev/null +++ b/test/loss/run_drydep_sect.spec @@ -0,0 +1,44 @@ +run_type sectional # sectional code run +output_prefix out/loss_drydep_sect # prefix of output files + +t_max 172800 # total simulation time (s) +del_t 60 # timestep (s) +t_output 21600 # output interval (0 disables) (s) +t_progress 0 # progress printing interval (0 disables) (s) + +n_bin 160 # number of bins +d_min 1e-9 # minimum diameter (m) +d_max 1e-3 # maximum diameter (m) + +do_camp_chem no # whether to use CAMP for chemistry (yes/no) +do_tchem no # whether to use TChem for chemistry (yes/no) + +gas_data gas_data.dat # file containing gas data +aerosol_data aero_data.dat # file containing aerosol data +do_fractal no # whether to do fractal treatment (yes/no) +aerosol_init aero_init_dist.dat # aerosol initial condition file + +temp_profile temp.dat # temperature profile file +pressure_profile pressure.dat # pressure profile file +height_profile height.dat # height profile file +gas_emissions gas_emit.dat # gas emissions file +gas_background gas_back.dat # background gas mixing ratios file +aero_emissions aero_emit.dat # aerosol emissions file +aero_background aero_back.dat # aerosol background file +loss_function drydep # loss function specification + +rel_humidity 0.999 # initial relative humidity (1) +latitude 40 # latitude (degrees, -90 to 90) +longitude 0 # longitude (degrees, -180 to 180) +altitude 0 # altitude (m) +start_time 0 # start time (s since 00:00 UTC) +start_day 1 # start day of year (UTC) + +do_aero_dilution no # whether to do aerosol dilution (yes/no) +do_coagulation yes # whether to do coagulation (yes/no) +coag_kernel zero # coagulation kernel +do_condensation no # whether to do condensation (yes/no) +do_mosaic no # whether to do MOSAIC (yes/no) +do_optical no # whether to compute optical props (yes/no) +do_nucleation no # whether to do nucleation (yes/no) +do_immersion_freezing no # whether to do freezing (yes/no) diff --git a/test/loss/run_drydep_sect_dil.spec b/test/loss/run_drydep_sect_dil.spec new file mode 100644 index 000000000..b4167e0a9 --- /dev/null +++ b/test/loss/run_drydep_sect_dil.spec @@ -0,0 +1,44 @@ +run_type sectional # sectional code run +output_prefix out/loss_drydep_sect_dil # prefix of output files + +t_max 172800 # total simulation time (s) +del_t 60 # timestep (s) +t_output 21600 # output interval (0 disables) (s) +t_progress 0 # progress printing interval (0 disables) (s) + +n_bin 160 # number of bins +d_min 1e-9 # minimum diameter (m) +d_max 1e-3 # maximum diameter (m) + +do_camp_chem no # whether to use CAMP for chemistry (yes/no) +do_tchem no # whether to use TChem for chemistry (yes/no) + +gas_data gas_data.dat # file containing gas data +aerosol_data aero_data.dat # file containing aerosol data +do_fractal no # whether to do fractal treatment (yes/no) +aerosol_init aero_init_dist.dat # aerosol initial condition file + +temp_profile temp.dat # temperature profile file +pressure_profile pressure.dat # pressure profile file +height_profile height.dat # height profile file +gas_emissions gas_emit.dat # gas emissions file +gas_background gas_back.dat # background gas mixing ratios file +aero_emissions aero_emit.dat # aerosol emissions file +aero_background aero_back.dat # aerosol background file +loss_function drydep # loss function specification + +rel_humidity 0.999 # initial relative humidity (1) +latitude 40 # latitude (degrees, -90 to 90) +longitude 0 # longitude (degrees, -180 to 180) +altitude 0 # altitude (m) +start_time 0 # start time (s since 00:00 UTC) +start_day 1 # start day of year (UTC) + +do_aero_dilution yes # whether to do aerosol dilution (yes/no) +do_coagulation yes # whether to do coagulation (yes/no) +coag_kernel zero # coagulation kernel +do_condensation no # whether to do condensation (yes/no) +do_mosaic no # whether to do MOSAIC (yes/no) +do_optical no # whether to compute optical props (yes/no) +do_nucleation no # whether to do nucleation (yes/no) +do_immersion_freezing no # whether to do freezing (yes/no) diff --git a/test/loss/test_loss_16.sh b/test/loss/test_loss_16.sh new file mode 100755 index 000000000..a5ea60fe3 --- /dev/null +++ b/test/loss/test_loss_16.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -e +set -v +cd ${0%/*} +mkdir -p out + +../../partmc run_drydep_sect.spec +../../extract_sectional_aero_time out/loss_drydep_sect + +../../numeric_diff --by col --rel-tol 1e-8 \ + loss_drydep_sect_aero_time_ref.txt \ + out/loss_drydep_sect_aero_time.txt diff --git a/test/loss/test_loss_17.sh b/test/loss/test_loss_17.sh new file mode 100755 index 000000000..1d40f14f3 --- /dev/null +++ b/test/loss/test_loss_17.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# exit on error +set -e +# turn on command echoing +set -v +# make sure that the current directory is the one where this script is +cd ${0%/*} +# make the output directory if it doesn't exist +mkdir -p out + +../../partmc run_drydep_sect_dil.spec +../../partmc run_drydep_part.spec + +../../extract_sectional_aero_time out/loss_drydep_sect_dil +../../extract_aero_time out/loss_part_drydep_0001 + +../../numeric_diff --by col --rel-tol 0.05 out/loss_drydep_sect_dil_aero_time.txt out/loss_part_drydep_0001_aero_time.txt diff --git a/test/parallel/run_sect.spec b/test/parallel/run_sect.spec index 00be7ca7e..855a8b7e0 100644 --- a/test/parallel/run_sect.spec +++ b/test/parallel/run_sect.spec @@ -10,6 +10,9 @@ n_bin 220 # number of bins d_min 1e-10 # minimum diameter (m) d_max 1e-4 # maximum diameter (m) +do_camp_chem no # whether to use CAMP for chemistry (yes/no) +do_tchem no # whether to use TChem for chemistry (yes/no) + gas_data gas_data.dat # file containing gas data aerosol_data aero_data.dat # file containing aerosol data do_fractal no # whether to do fractal treatment @@ -31,5 +34,11 @@ altitude 0 # altitude (m) start_time 0 # start time (s since 00:00 UTC) start_day 1 # start day of year (UTC) +do_aero_dilution yes # whether to do aerosol dilution (yes/no) do_coagulation yes # whether to do coagulation (yes/no) coag_kernel brown # coagulation kernel +do_condensation no # whether to do condensation (yes/no) +do_mosaic no # whether to do MOSAIC (yes/no) +do_optical no # whether to compute optical props (yes/no) +do_nucleation no # whether to do nucleation (yes/no) +do_immersion_freezing no # whether to do freezing (yes/no) diff --git a/test/sedi/run_sect.spec b/test/sedi/run_sect.spec index 2c83632ff..4b2981706 100644 --- a/test/sedi/run_sect.spec +++ b/test/sedi/run_sect.spec @@ -10,6 +10,9 @@ n_bin 100 # number of bins d_min 1e-7 # minimum diameter (m) d_max 1 # maximum diameter (m) +do_camp_chem no # whether to use CAMP for chemistry (yes/no) +do_tchem no # whether to use TChem for chemistry (yes/no) + gas_data gas_data.dat # file containing gas data aerosol_data aero_data.dat # file containing aerosol data do_fractal no # whether to do fractal treatment @@ -31,5 +34,11 @@ altitude 0 # altitude (m) start_time 0 # start time (s since 00:00 UTC) start_day 1 # start day of year (UTC) +do_aero_dilution yes # whether to do aerosol dilution (yes/no) do_coagulation yes # whether to do coagulation (yes/no) coag_kernel sedi # coagulation kernel +do_condensation no # whether to do condensation (yes/no) +do_mosaic no # whether to do MOSAIC (yes/no) +do_optical no # whether to compute optical props (yes/no) +do_nucleation no # whether to do nucleation (yes/no) +do_immersion_freezing no # whether to do freezing (yes/no) From 584d763e186e7bac4b484ce3dfc09239261a7c94 Mon Sep 17 00:00:00 2001 From: Zach D'Aquino <107204919+zdaq12@users.noreply.github.com> Date: Sun, 13 Sep 2026 15:02:31 -0400 Subject: [PATCH 02/19] Remove duplicate use pmc_scenario --- src/output.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/output.F90 b/src/output.F90 index e204144a5..dfe50a4f2 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -78,7 +78,6 @@ module pmc_output use pmc_gas_data use pmc_scenario use pmc_mpi - use pmc_scenario #ifdef PMC_USE_MPI use mpi #endif From ef0f5283fd9da5f859a33e1638bc30b118304a39 Mon Sep 17 00:00:00 2001 From: zdaq12 Date: Sun, 13 Sep 2026 14:36:29 -0500 Subject: [PATCH 03/19] update initial distribution for 7_drydep scenario --- scenarios/7_drydep/README | 39 +++++++-------------------- scenarios/7_drydep/aero_init_dist.dat | 4 +-- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/scenarios/7_drydep/README b/scenarios/7_drydep/README index b156ba22f..8289d8fe3 100644 --- a/scenarios/7_drydep/README +++ b/scenarios/7_drydep/README @@ -1,11 +1,9 @@ Dry deposition scenario ======================= -Demonstrates dry deposition of aerosol particles using both of the -representations that support it: the modal representation and the -sectional (binned) representation. Both are run with identical -inputs -- same initial distribution, meteorology, and deposition -parameters -- so their results can be compared directly. +Demonstrates dry deposition of aerosol particles using both the +modal and the sectional (binned) representations. Both are run +with identical inputs so that their results can be compared directly. Running ------- @@ -23,8 +21,7 @@ Sectional: Each simulates 8 hours with hourly output. The modal case is post-processed by drydep_modal_process, which writes total number and mass concentration time series to out/drydep_modal_process.nc. The -sectional case uses the standard extract_sectional_* tools, which -write plain-text time series and size distributions. +sectional case uses the standard extract_sectional_* tools. Configuration ------------- @@ -32,44 +29,28 @@ Configuration Both runs share: aero_init_dist.dat single log-normal mode, 3.2e9 m^-3, geometric - mean diameter 10 nm, narrow (sigma = 1.1) + mean diameter 100 nm, sigma (geom_std_dev)= 1.8 aero_data.dat single species (SO4) drydep_params.dat deposition parameters (see below) temp.dat, pres.dat, height.dat, gas_*.dat, aero_back*.dat, aero_emit*.dat meteorology, emissions and background -Emissions and background rates are zero, and condensation and the +Emissions and background rates are zero. Condensation and all other microphysical processes are disabled, so dry deposition is the only active process. The sectional case runs with the zero -coagulation kernel, which leaves the size distribution unchanged. It -also sets do_aero_dilution to no; the modal representation has no -dilution treatment, so this is what makes the two comparable. +coagulation kernel It also sets do_aero_dilution to no; the modal +representation has no dilution treatment. Deposition parameters --------------------- drydep_params.dat holds the coefficients of the size-resolved deposition scheme (Zhang et al. 2001; Emerson et al. 2020). The -combining equation is +dry deposition velocity equation is V_d = V_s + 1 / (R_a + R_s) following Slinn (1982), as used by both parameterizations. The land-use-dependent quantities (z_rough, A, alpha, gamma) and the scheme coefficients (C_B, C_IN, C_IM, nu, beta) are all read from -this file, so switching land-use category or parameterization needs -no source changes or rebuild -- copy the file, edit the values, and -point drydep_params at it. - -Comparing the two representations ---------------------------------- - -The modal and sectional results differ substantially for this case -(tens of percent in total number by the end of the run). This is not -a numerical artifact: the sectional solution is converged with -respect to bin count, and is independently validated against the -particle-resolved representation in test/loss/test_loss_17.sh. The -difference reflects the modal representation holding a fixed -log-normal shape while deposition removes particles at strongly -size-dependent rates, which is largest for narrow distributions -undergoing rapid deposition, as here. +this file. diff --git a/scenarios/7_drydep/aero_init_dist.dat b/scenarios/7_drydep/aero_init_dist.dat index 7f510934c..cf993588a 100644 --- a/scenarios/7_drydep/aero_init_dist.dat +++ b/scenarios/7_drydep/aero_init_dist.dat @@ -3,5 +3,5 @@ mass_frac aero_init_comp.dat # composition proportions of species diam_type geometric # type of diameter specified mode_type log_normal # type of distribution num_conc 3.2e9 # particle number concentration (#/m^3) -geom_mean_diam 1e-8 # geometric mean diameter (m) -log10_geom_std_dev 0.041 # log_10 of geometric std dev of diameter +geom_mean_diam 1e-7 # geometric mean diameter (m) +log10_geom_std_dev 0.255 # log_10 of geometric std dev of diameter From ff22072acb6cbeb6513055fdb13d08f20d6adea6 Mon Sep 17 00:00:00 2001 From: Zach D'Aquino <107204919+zdaq12@users.noreply.github.com> Date: Sun, 13 Sep 2026 16:50:54 -0400 Subject: [PATCH 04/19] Fix typo in dry deposition README Corrected typo in README regarding coagulation kernel. --- scenarios/7_drydep/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scenarios/7_drydep/README b/scenarios/7_drydep/README index 8289d8fe3..b6357257b 100644 --- a/scenarios/7_drydep/README +++ b/scenarios/7_drydep/README @@ -38,7 +38,7 @@ Both runs share: Emissions and background rates are zero. Condensation and all other microphysical processes are disabled, so dry deposition is the only active process. The sectional case runs with the zero -coagulation kernel It also sets do_aero_dilution to no; the modal +coagulation kernel. It also sets do_aero_dilution to no; the modal representation has no dilution treatment. Deposition parameters From 86892a021e0b844fac458ad4169c8d3822691612 Mon Sep 17 00:00:00 2001 From: Zach D'Aquino <107204919+zdaq12@users.noreply.github.com> Date: Wed, 16 Sep 2026 18:53:54 -0400 Subject: [PATCH 05/19] Update src/run_sect.F90 Co-authored-by: Jeffrey Curtis --- src/run_sect.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/run_sect.F90 b/src/run_sect.F90 index 18d0e0faf..8d8ee1895 100644 --- a/src/run_sect.F90 +++ b/src/run_sect.F90 @@ -104,7 +104,6 @@ subroutine run_sect(bin_grid, gas_data, aero_data, aero_dist, & integer i, j, i_time, num_t, i_summary logical do_output, do_progress - real(kind=dp) removed call check_time_multiple("t_max", run_sect_opt%t_max, & "del_t", run_sect_opt%del_t) From 75a7caeb55d2d9155f280f51c6eaade90f3b0c3d Mon Sep 17 00:00:00 2001 From: Zach D'Aquino <107204919+zdaq12@users.noreply.github.com> Date: Wed, 16 Sep 2026 18:54:52 -0400 Subject: [PATCH 06/19] Update src/run_sect.F90 Co-authored-by: Jeffrey Curtis --- src/run_sect.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/run_sect.F90 b/src/run_sect.F90 index 8d8ee1895..ca7912b1b 100644 --- a/src/run_sect.F90 +++ b/src/run_sect.F90 @@ -142,7 +142,6 @@ subroutine run_sect(bin_grid, gas_data, aero_data, aero_dist, & last_progress_time = 0d0 time = 0d0 i_summary = 1 - removed = 0d0 ! precompute kernel values for all pairs of bins call bin_kernel(bin_grid_size(bin_grid), bin_grid%centers, aero_data, & From 405090bb34117736c9c15d103d3d6417053fc079 Mon Sep 17 00:00:00 2001 From: zdaq12 Date: Sun, 27 Sep 2026 09:05:03 -0500 Subject: [PATCH 07/19] wrap coagulation calcs in conditional --- src/run_sect.F90 | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/run_sect.F90 b/src/run_sect.F90 index ca7912b1b..9d49ca599 100644 --- a/src/run_sect.F90 +++ b/src/run_sect.F90 @@ -144,21 +144,23 @@ subroutine run_sect(bin_grid, gas_data, aero_data, aero_dist, & i_summary = 1 ! precompute kernel values for all pairs of bins - call bin_kernel(bin_grid_size(bin_grid), bin_grid%centers, aero_data, & - run_sect_opt%coag_kernel_type, env_state, k_bin) - call smooth_bin_kernel(bin_grid_size(bin_grid), k_bin, ck) - do i = 1,bin_grid_size(bin_grid) - do j = 1,bin_grid_size(bin_grid) - ck(i,j) = ck(i,j) * 1d6 ! m^3/s to cm^3/s + if (run_sect_opt%do_coagulation) then + call bin_kernel(bin_grid_size(bin_grid), bin_grid%centers, aero_data, & + run_sect_opt%coag_kernel_type, env_state, k_bin) + call smooth_bin_kernel(bin_grid_size(bin_grid), k_bin, ck) + do i = 1,bin_grid_size(bin_grid) + do j = 1,bin_grid_size(bin_grid) + ck(i,j) = ck(i,j) * 1d6 ! m^3/s to cm^3/s + end do end do - end do - ! multiply kernel with constant timestep and logarithmic grid distance - do i = 1,bin_grid_size(bin_grid) - do j = 1,bin_grid_size(bin_grid) - ck(i,j) = ck(i,j) * run_sect_opt%del_t * bin_grid%widths(i) + ! multiply kernel with constant timestep and logarithmic grid distance + do i = 1,bin_grid_size(bin_grid) + do j = 1,bin_grid_size(bin_grid) + ck(i,j) = ck(i,j) * run_sect_opt%del_t * bin_grid%widths(i) + end do end do - end do + end if ! initial output call check_event(time, run_sect_opt%del_t, run_sect_opt%t_output, & From b396b14362977e2a0482869b45e7c1395f83170c Mon Sep 17 00:00:00 2001 From: zdaq12 Date: Sun, 27 Sep 2026 16:31:02 -0500 Subject: [PATCH 08/19] update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e0ec53304..f79a46200 100644 --- a/.gitignore +++ b/.gitignore @@ -17,5 +17,6 @@ scenarios/3_condense/spec/ scenarios/3_condense/temp/ scenarios/3_condense/out/ scenarios/4_chamber/out/ +scenarios/7_drydep/out/ *.o *.mod From 607fe02ea0b61bf0111573605aca48fda7bba0f8 Mon Sep 17 00:00:00 2001 From: zdaq12 Date: Sun, 27 Sep 2026 16:32:19 -0500 Subject: [PATCH 09/19] fix units in modal processing --- scenarios/7_drydep/drydep_modal_process.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scenarios/7_drydep/drydep_modal_process.F90 b/scenarios/7_drydep/drydep_modal_process.F90 index bcbd79250..609236e43 100644 --- a/scenarios/7_drydep/drydep_modal_process.F90 +++ b/scenarios/7_drydep/drydep_modal_process.F90 @@ -102,7 +102,7 @@ program process call stats_1d_output_netcdf(stats_tot_num_conc, ncid, "tot_num_conc", & dim_name="time", unit="m^{-3}") call stats_1d_output_netcdf(stats_tot_mass_conc, ncid, "tot_mass_conc", & - dim_name="time", unit="ug m^{-3}") + dim_name="time", unit="kg m^{-3}") call pmc_nc_close(ncid) call pmc_mpi_finalize() From b293a3f00555596f2792ff55130a12fde5203fa1 Mon Sep 17 00:00:00 2001 From: zdaq12 Date: Sun, 27 Sep 2026 16:33:23 -0500 Subject: [PATCH 10/19] add guards for reading/writing dry dep params --- src/output.F90 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/output.F90 b/src/output.F90 index dfe50a4f2..2e491d32f 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -788,7 +788,8 @@ subroutine input_sectional(filename, index, time, del_t, uuid, bin_grid, & end if if (present(scenario)) then - call drydep_params_input_netcdf(scenario%drydep, ncid) + call drydep_params_input_netcdf(scenario%drydep, ncid, & + must_be_present=.false.) end if call pmc_nc_close(ncid) @@ -935,7 +936,8 @@ subroutine input_modal(filename, index, time, del_t, uuid, aero_dist, & end if if (present(scenario)) then - call drydep_params_input_netcdf(scenario%drydep, ncid) + call drydep_params_input_netcdf(scenario%drydep, ncid, & + must_be_present=.false.) end if end subroutine input_modal From 221cddd6f85e7580dd3189a6dc9d98774aec4c7a Mon Sep 17 00:00:00 2001 From: zdaq12 Date: Sun, 27 Sep 2026 16:34:52 -0500 Subject: [PATCH 11/19] adjust handling of do_dilution; optional and only with dry dep --- src/partmc.F90 | 12 ++++++------ src/run_sect.F90 | 35 ++++++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/partmc.F90 b/src/partmc.F90 index 3407abe96..bbc3a8566 100644 --- a/src/partmc.F90 +++ b/src/partmc.F90 @@ -732,11 +732,12 @@ subroutine partmc_sect(file) !! format should be \subpage input_format_aero_dist !! - \subpage input_format_scenario !! - \subpage input_format_env_state - !! - \b do_aero_dilution (logical): whether to apply aerosol - !! dilution. If \c no, both the background-exchange dilution and - !! the mixing-layer-growth correction are skipped, which allows - !! other processes (for example dry deposition) to be studied in - !! isolation. + !! - \b do_aero_dilution (logical, optional): whether to apply aerosol + !! dilution (default \c yes). It may only be given when + !! \c loss_function is \c drydep. If \c no, both the + !! background-exchange dilution and the mixing-layer-growth dilution + !! are skipped, so dry deposition can be studied in isolation with a + !! time-varying mixing height. !! - \b do_coagulation (logical): whether to perform particle !! coagulation. If \c do_coagulation is \c yes, then the !! following parameters must also be provided: @@ -776,7 +777,6 @@ subroutine partmc_sect(file) !! start_time 0 # start time (s since 00:00 UTC) !! start_day 1 # start day of year (UTC) !! - !! do_aero_dilution yes # whether to do dilution (yes/no) !! do_coagulation yes # whether to do coagulation (yes/no) !! kernel brown # coagulation kernel !! diff --git a/src/run_sect.F90 b/src/run_sect.F90 index 9d49ca599..65717a04b 100644 --- a/src/run_sect.F90 +++ b/src/run_sect.F90 @@ -38,7 +38,8 @@ module pmc_run_sect real(kind=dp) :: t_output !> Progress interval (0 disables) (s). real(kind=dp) :: t_progress - !> Whether to do aerosol background dilution. + !> Whether to do aerosol background dilution (optional in spec file + !> and only allowed with loss_function = drydep; defaults to \c .true.). logical :: do_aero_dilution !> Type of coagulation kernel. integer :: coag_kernel_type @@ -241,6 +242,7 @@ subroutine spec_file_read_run_sect(file, run_sect_opt, aero_data, & character(len=PMC_MAX_FILENAME_LEN) :: sub_filename type(spec_file_t) :: sub_file + type(spec_line_t) :: line call spec_file_read_string(file, 'output_prefix', run_sect_opt%prefix) @@ -282,10 +284,24 @@ subroutine spec_file_read_run_sect(file, run_sect_opt, aero_data, & call spec_file_close(sub_file) call spec_file_read_scenario(file, gas_data, aero_data, .false., scenario) + call assert_msg(383939910, & + scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_NONE & + .or. scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_DRYDEP, & + "sectional run only supports loss_function none or drydep") call spec_file_read_env_state(file, env_state) - call spec_file_read_logical(file, 'do_aero_dilution', & - run_sect_opt%do_aero_dilution) + ! optional line, only allowed with dry deposition (default: dilute) + run_sect_opt%do_aero_dilution = .true. + call spec_file_read_line_no_eof(file, line) + call spec_file_unread_line(file) + if (line%name == 'do_aero_dilution') then + call spec_file_read_logical(file, 'do_aero_dilution', & + run_sect_opt%do_aero_dilution) + if (scenario%loss_function_type /= SCENARIO_LOSS_FUNCTION_DRYDEP) then + call spec_file_die_msg(363374529, file, & + "do_aero_dilution is only allowed with loss_function drydep") + end if + end if call spec_file_read_logical(file, 'do_coagulation', & run_sect_opt%do_coagulation) @@ -311,12 +327,13 @@ subroutine spec_file_read_run_sect(file, run_sect_opt, aero_data, & if (run_sect_opt%do_mosaic) then call spec_file_die_msg(584729163, file, & "sectional run does not support MOSAIC chemistry") - end if - - call spec_file_read_logical(file, 'do_optical', run_sect_opt%do_optical) - if (run_sect_opt%do_optical) then - call spec_file_die_msg(527436819, file, & - "sectional run does not support optical properties calculation") + call spec_file_read_logical(file, 'do_optical', run_sect_opt%do_optical) + if (run_sect_opt%do_optical) then + call spec_file_die_msg(527436819, file, & + "sectional run does not support optical properties calculation") + end if + else + run_sect_opt%do_optical = .false. end if call spec_file_read_logical(file, 'do_nucleation', & From be7b42da856748a78f42ab0e1bf7a0db640a95a4 Mon Sep 17 00:00:00 2001 From: zdaq12 Date: Sun, 27 Sep 2026 16:36:05 -0500 Subject: [PATCH 12/19] adjust loss handling --- src/scenario.F90 | 87 ++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 48 deletions(-) diff --git a/src/scenario.F90 b/src/scenario.F90 index c16fcf269..1f2b328f0 100644 --- a/src/scenario.F90 +++ b/src/scenario.F90 @@ -449,7 +449,7 @@ subroutine scenario_update_aero_modes(aero_dist, del_t, env_state, & type(env_state_t), intent(in) :: env_state !> Particle density (kg m^-3), assumed uniform across all modes. real(kind=dp), intent(in) :: density - !> Scenario + !> Scenario data. type(scenario_t), intent(in) :: scenario real(kind=dp) :: N, d_pg, ln_sigma_g @@ -462,9 +462,6 @@ subroutine scenario_update_aero_modes(aero_dist, del_t, env_state, & return else if (scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_NONE) then return - else if (scenario%loss_function_type == & - SCENARIO_LOSS_FUNCTION_CONSTANT) then - return else if (scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_DRYDEP) then do i_mode = 1,aero_dist_n_mode(aero_dist) N = aero_dist%mode(i_mode)%num_conc @@ -495,6 +492,10 @@ subroutine scenario_update_aero_modes(aero_dist, del_t, env_state, & * (ln_sigma_g**2.0d0)))**(1.0d0/3.0d0) aero_dist%mode(i_mode)%char_radius = new_d_pg / 2.0d0 end do + else + call die_msg(192500240, "loss_function must be none or drydep " & + // "for modal runs; unsupported loss function id: " & + // trim(integer_to_string(scenario%loss_function_type))) end if end subroutine scenario_update_aero_modes @@ -1153,9 +1154,14 @@ subroutine scenario_binned_loss(scenario, bin_grid, delta_t, aero_data, & if (scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_NONE .or. & scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_INVALID) then - return + return else if (scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_DRYDEP) then + ! Assumes a single aerosol species, as run_sect() requires. Both the + ! density and the number diagnosis below use species 1 only, and + ! must be generalized if more species are allowed. + call assert_msg(258732274, aero_data_n_spec(aero_data) == 1, & + "sectional loss assumes a single aerosol species") density = aero_data%density(1) do i_bin = 1,bin_grid_size(bin_grid) @@ -1171,51 +1177,13 @@ subroutine scenario_binned_loss(scenario, bin_grid, delta_t, aero_data, & end do else - return + call die_msg(769879198, "loss_function must be none or drydep " & + // "for sectional runs; unsupported loss function id: " & + // trim(integer_to_string(scenario%loss_function_type))) end if end subroutine scenario_binned_loss -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - !> Updates an array (of size equal to the number of sections) containing - !> the dry deposition velocity for each bin in a sectional simulation. - !! - !! This is a diagnostic helper: it returns deposition velocities (m s^{-1}) - !! rather than loss rates, by multiplying the rate from - !! scenario_loss_rate_drydep() back by the mixing layer height. It is not - !! used by the sectional time-stepping itself, which calls - !! scenario_binned_loss(). - subroutine scenario_section_drydep_rates(scenario, bin_grid, aero_data, & - env_state, rates) - - !> Scenario data. - type(scenario_t), intent(in) :: scenario - !> Bin grid. - type(bin_grid_t), intent(in) :: bin_grid - !> Aerosol data. - type(aero_data_t), intent(in) :: aero_data - !> Environmental state. - type(env_state_t), intent(in) :: env_state - !> Deposition velocities for each section/bin (m s^{-1}). - real(kind=dp), intent(inout) :: rates(:) - - integer :: i_bin - real(kind=dp) :: density, vol - - call assert_msg(516274839, size(rates) == bin_grid_size(bin_grid), & - "rates array size must match the number of bins") - - density = aero_data%density(1) - - do i_bin = 1,bin_grid_size(bin_grid) - vol = aero_data_rad2vol(aero_data, bin_grid%centers(i_bin)) - rates(i_bin) = scenario_loss_rate_drydep(vol, density, & - aero_data, env_state, scenario) * env_state%height - end do - - end subroutine scenario_section_drydep_rates - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !> Whether any of the contained aerosol modes are of the given type. @@ -1289,6 +1257,13 @@ subroutine spec_file_read_scenario(file, gas_data, aero_data, & !! for constant loss rate, \c volume for particle loss proportional !! to particle volume, \c drydep for particle loss proportional !! to dry deposition velocity, or \c chamber for a chamber model. + !! Sectional and modal runs support only \c none and \c drydep. + !! If \c loss_function is \c drydep, it may be followed by + !! \b drydep_params (string), the name of the file from which to + !! read the dry deposition parameters --- the file format should + !! be \subpage input_format_drydep_params. If \c drydep_params is + !! omitted, the default parameters are used and a warning is + !! printed. !! If \c loss_function is \c chamber, then the following !! parameters must also be provided: !! - \subpage input_format_chamber @@ -1493,7 +1468,7 @@ subroutine spec_file_read_drydep_params(file, drydep_params) !> \page input_format_drydep_params Input File Format: Dry Deposition Parameters !! - !! Dry deposition is simulatied using the specified parameters: + !! Dry deposition is simulated using the specified parameters: !! - \b z_ref (real, unit m): the reference height \f$z_{\rm ref}\f$ used !! in the calculation of aerodynamic resistance \f$R_a\f$ !! - \b u_mean (real, unit m s^{-1}): the wind speed at the reference @@ -1571,12 +1546,28 @@ end subroutine drydep_params_output_netcdf !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !> Read dry deposition parameters from a NetCDF file. - subroutine drydep_params_input_netcdf(drydep_params, ncid) + subroutine drydep_params_input_netcdf(drydep_params, ncid, must_be_present) !> Dry deposition parameters. type(drydep_params_t), intent(inout) :: drydep_params !> NetCDF file ID, in data mode. integer, intent(in) :: ncid + !> Whether the parameters must be present in the file (default + !> \c .true.). They are only written when the loss function is dry + !> deposition, so readers that may be given either kind of file + !> should pass \c .false., which leaves \c drydep_params unchanged. + logical, optional, intent(in) :: must_be_present + + integer :: varid, status + logical :: use_must_be_present + + use_must_be_present = .true. + if (present(must_be_present)) use_must_be_present = must_be_present + + if (.not. use_must_be_present) then + status = nf90_inq_varid(ncid, "drydep_z_ref", varid) + if (status == NF90_ENOTVAR) return + end if associate (d => drydep_params) call pmc_nc_read_real(ncid, d%z_ref, "drydep_z_ref") From c63d7fe23c9d82ca6c4ec6956a3781e5944331f3 Mon Sep 17 00:00:00 2001 From: zdaq12 Date: Sun, 27 Sep 2026 16:37:12 -0500 Subject: [PATCH 13/19] update scenario README and spec options --- scenarios/7_drydep/README | 7 ++++--- scenarios/7_drydep/drydep_sect.spec | 4 +--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/scenarios/7_drydep/README b/scenarios/7_drydep/README index b6357257b..0e647e43d 100644 --- a/scenarios/7_drydep/README +++ b/scenarios/7_drydep/README @@ -37,9 +37,10 @@ Both runs share: Emissions and background rates are zero. Condensation and all other microphysical processes are disabled, so dry deposition is the -only active process. The sectional case runs with the zero -coagulation kernel. It also sets do_aero_dilution to no; the modal -representation has no dilution treatment. +only active process. The sectional case sets do_aero_dilution to no +because the modal representation has no dilution treatment. +height.dat describes a growing boundary layer, which the deposition +rates depend on. Deposition parameters --------------------- diff --git a/scenarios/7_drydep/drydep_sect.spec b/scenarios/7_drydep/drydep_sect.spec index c4dfc7e79..77c6fcc7a 100644 --- a/scenarios/7_drydep/drydep_sect.spec +++ b/scenarios/7_drydep/drydep_sect.spec @@ -36,10 +36,8 @@ start_time 21600 # start time (s since 00:00 UTC) start_day 200 # start day of year (UTC) do_aero_dilution no # whether to do aerosol dilution (yes/no) -do_coagulation yes # whether to do coagulation (yes/no) -coag_kernel zero # coagulation kernel (zero = no coagulation) +do_coagulation no # whether to do coagulation (yes/no) do_condensation no # whether to do condensation (yes/no) do_mosaic no # whether to do MOSAIC (yes/no) -do_optical no # whether to compute optical props (yes/no) do_nucleation no # whether to do nucleation (yes/no) do_immersion_freezing no # whether to do freezing (yes/no) From a6c86f870dce748ffce12dfef752ebd1b75f20d7 Mon Sep 17 00:00:00 2001 From: zdaq12 Date: Sun, 27 Sep 2026 16:37:53 -0500 Subject: [PATCH 14/19] remove dilution spec file for sectional run --- test/loss/run_drydep_sect_dil.spec | 44 ------------------------------ 1 file changed, 44 deletions(-) delete mode 100644 test/loss/run_drydep_sect_dil.spec diff --git a/test/loss/run_drydep_sect_dil.spec b/test/loss/run_drydep_sect_dil.spec deleted file mode 100644 index b4167e0a9..000000000 --- a/test/loss/run_drydep_sect_dil.spec +++ /dev/null @@ -1,44 +0,0 @@ -run_type sectional # sectional code run -output_prefix out/loss_drydep_sect_dil # prefix of output files - -t_max 172800 # total simulation time (s) -del_t 60 # timestep (s) -t_output 21600 # output interval (0 disables) (s) -t_progress 0 # progress printing interval (0 disables) (s) - -n_bin 160 # number of bins -d_min 1e-9 # minimum diameter (m) -d_max 1e-3 # maximum diameter (m) - -do_camp_chem no # whether to use CAMP for chemistry (yes/no) -do_tchem no # whether to use TChem for chemistry (yes/no) - -gas_data gas_data.dat # file containing gas data -aerosol_data aero_data.dat # file containing aerosol data -do_fractal no # whether to do fractal treatment (yes/no) -aerosol_init aero_init_dist.dat # aerosol initial condition file - -temp_profile temp.dat # temperature profile file -pressure_profile pressure.dat # pressure profile file -height_profile height.dat # height profile file -gas_emissions gas_emit.dat # gas emissions file -gas_background gas_back.dat # background gas mixing ratios file -aero_emissions aero_emit.dat # aerosol emissions file -aero_background aero_back.dat # aerosol background file -loss_function drydep # loss function specification - -rel_humidity 0.999 # initial relative humidity (1) -latitude 40 # latitude (degrees, -90 to 90) -longitude 0 # longitude (degrees, -180 to 180) -altitude 0 # altitude (m) -start_time 0 # start time (s since 00:00 UTC) -start_day 1 # start day of year (UTC) - -do_aero_dilution yes # whether to do aerosol dilution (yes/no) -do_coagulation yes # whether to do coagulation (yes/no) -coag_kernel zero # coagulation kernel -do_condensation no # whether to do condensation (yes/no) -do_mosaic no # whether to do MOSAIC (yes/no) -do_optical no # whether to compute optical props (yes/no) -do_nucleation no # whether to do nucleation (yes/no) -do_immersion_freezing no # whether to do freezing (yes/no) From 2f2eb0a5110b019d4a38d1caca9b77e501dbc0de Mon Sep 17 00:00:00 2001 From: zdaq12 Date: Sun, 27 Sep 2026 16:39:13 -0500 Subject: [PATCH 15/19] update spec options for tests --- test/brownian/run_sect.spec | 2 -- test/loss/run_drydep_sect.spec | 4 +--- test/parallel/run_sect.spec | 2 -- test/sedi/run_sect.spec | 2 -- 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/test/brownian/run_sect.spec b/test/brownian/run_sect.spec index 1c2d8d78f..3981474d1 100644 --- a/test/brownian/run_sect.spec +++ b/test/brownian/run_sect.spec @@ -34,11 +34,9 @@ altitude 0 # altitude (m) start_time 0 # start time (s since 00:00 UTC) start_day 1 # start day of year (UTC) -do_aero_dilution yes # whether to do aerosol dilution (yes/no) do_coagulation yes # whether to do coagulation (yes/no) coag_kernel brown # coagulation kernel do_condensation no # whether to do condensation (yes/no) do_mosaic no # whether to do MOSAIC (yes/no) -do_optical no # whether to compute optical props (yes/no) do_nucleation no # whether to do nucleation (yes/no) do_immersion_freezing no # whether to do freezing (yes/no) diff --git a/test/loss/run_drydep_sect.spec b/test/loss/run_drydep_sect.spec index c186ed18a..85e2ee544 100644 --- a/test/loss/run_drydep_sect.spec +++ b/test/loss/run_drydep_sect.spec @@ -35,10 +35,8 @@ start_time 0 # start time (s since 00:00 UTC) start_day 1 # start day of year (UTC) do_aero_dilution no # whether to do aerosol dilution (yes/no) -do_coagulation yes # whether to do coagulation (yes/no) -coag_kernel zero # coagulation kernel +do_coagulation no # whether to do coagulation (yes/no) do_condensation no # whether to do condensation (yes/no) do_mosaic no # whether to do MOSAIC (yes/no) -do_optical no # whether to compute optical props (yes/no) do_nucleation no # whether to do nucleation (yes/no) do_immersion_freezing no # whether to do freezing (yes/no) diff --git a/test/parallel/run_sect.spec b/test/parallel/run_sect.spec index 855a8b7e0..25c6ee541 100644 --- a/test/parallel/run_sect.spec +++ b/test/parallel/run_sect.spec @@ -34,11 +34,9 @@ altitude 0 # altitude (m) start_time 0 # start time (s since 00:00 UTC) start_day 1 # start day of year (UTC) -do_aero_dilution yes # whether to do aerosol dilution (yes/no) do_coagulation yes # whether to do coagulation (yes/no) coag_kernel brown # coagulation kernel do_condensation no # whether to do condensation (yes/no) do_mosaic no # whether to do MOSAIC (yes/no) -do_optical no # whether to compute optical props (yes/no) do_nucleation no # whether to do nucleation (yes/no) do_immersion_freezing no # whether to do freezing (yes/no) diff --git a/test/sedi/run_sect.spec b/test/sedi/run_sect.spec index 4b2981706..eff7ef684 100644 --- a/test/sedi/run_sect.spec +++ b/test/sedi/run_sect.spec @@ -34,11 +34,9 @@ altitude 0 # altitude (m) start_time 0 # start time (s since 00:00 UTC) start_day 1 # start day of year (UTC) -do_aero_dilution yes # whether to do aerosol dilution (yes/no) do_coagulation yes # whether to do coagulation (yes/no) coag_kernel sedi # coagulation kernel do_condensation no # whether to do condensation (yes/no) do_mosaic no # whether to do MOSAIC (yes/no) -do_optical no # whether to compute optical props (yes/no) do_nucleation no # whether to do nucleation (yes/no) do_immersion_freezing no # whether to do freezing (yes/no) From 22fbde6144a15f01fdb17ea21df2c6ba1cc91f3d Mon Sep 17 00:00:00 2001 From: zdaq12 Date: Sun, 27 Sep 2026 16:39:56 -0500 Subject: [PATCH 16/19] update paths in test --- test/loss/test_loss_17.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/loss/test_loss_17.sh b/test/loss/test_loss_17.sh index 1d40f14f3..ee16ee2dd 100755 --- a/test/loss/test_loss_17.sh +++ b/test/loss/test_loss_17.sh @@ -9,10 +9,10 @@ cd ${0%/*} # make the output directory if it doesn't exist mkdir -p out -../../partmc run_drydep_sect_dil.spec +../../partmc run_drydep_sect.spec ../../partmc run_drydep_part.spec -../../extract_sectional_aero_time out/loss_drydep_sect_dil +../../extract_sectional_aero_time out/loss_drydep_sect ../../extract_aero_time out/loss_part_drydep_0001 -../../numeric_diff --by col --rel-tol 0.05 out/loss_drydep_sect_dil_aero_time.txt out/loss_part_drydep_0001_aero_time.txt +../../numeric_diff --by col --rel-tol 0.05 out/loss_drydep_sect_aero_time.txt out/loss_part_drydep_0001_aero_time.txt From deeea513884a33b2919ab3a49a143f49ec53d0df Mon Sep 17 00:00:00 2001 From: Zach D'Aquino <107204919+zdaq12@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:44:41 -0400 Subject: [PATCH 17/19] Update src/scenario.F90 Co-authored-by: Jeffrey Curtis --- src/scenario.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scenario.F90 b/src/scenario.F90 index 1f2b328f0..277a67828 100644 --- a/src/scenario.F90 +++ b/src/scenario.F90 @@ -420,7 +420,7 @@ subroutine scenario_update_aero_binned(scenario, delta_t, env_state, & scenario%aero_dilution_time, scenario%aero_dilution_rate, & env_state%elapsed_time, background, dilution_rate) call aero_binned_add_aero_dist(background_binned, bin_grid, aero_data, & - background) + background) p = exp(- dilution_rate * delta_t) if (env_state%height > old_env_state%height) then p = p * old_env_state%height / env_state%height From e7d0b3ebe6967d9c6dec4fabd88726cee7305312 Mon Sep 17 00:00:00 2001 From: Zach D'Aquino <107204919+zdaq12@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:44:51 -0400 Subject: [PATCH 18/19] Update src/scenario.F90 Co-authored-by: Jeffrey Curtis --- src/scenario.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scenario.F90 b/src/scenario.F90 index 277a67828..cd235789c 100644 --- a/src/scenario.F90 +++ b/src/scenario.F90 @@ -1154,7 +1154,7 @@ subroutine scenario_binned_loss(scenario, bin_grid, delta_t, aero_data, & if (scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_NONE .or. & scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_INVALID) then - return + return else if (scenario%loss_function_type == SCENARIO_LOSS_FUNCTION_DRYDEP) then ! Assumes a single aerosol species, as run_sect() requires. Both the From 401c5a40959a9d341a5aa5aafecdc7e721583b50 Mon Sep 17 00:00:00 2001 From: zdaq12 Date: Sat, 10 Oct 2026 12:08:14 -0500 Subject: [PATCH 19/19] replace duplicate error codes --- src/run_sect.F90 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/run_sect.F90 b/src/run_sect.F90 index 65717a04b..895f95da5 100644 --- a/src/run_sect.F90 +++ b/src/run_sect.F90 @@ -256,13 +256,13 @@ subroutine spec_file_read_run_sect(file, run_sect_opt, aero_data, & call spec_file_read_logical(file, 'do_camp_chem', & run_sect_opt%do_camp_chem) if (run_sect_opt%do_camp_chem) then - call spec_file_die_msg(263948175, file, & + call spec_file_die_msg(645601039, file, & "sectional run does not support CAMP chemistry") end if call spec_file_read_logical(file, 'do_tchem', run_sect_opt%do_tchem) if (run_sect_opt%do_tchem) then - call spec_file_die_msg(195837264, file, & + call spec_file_die_msg(366298338, file, & "sectional run does not support TChem chemistry") end if @@ -319,17 +319,17 @@ subroutine spec_file_read_run_sect(file, run_sect_opt, aero_data, & call spec_file_read_logical(file, 'do_condensation', & run_sect_opt%do_condensation) if (run_sect_opt%do_condensation) then - call spec_file_die_msg(612938475, file, & + call spec_file_die_msg(673957476, file, & "sectional run does not support condensation") end if call spec_file_read_logical(file, 'do_mosaic', run_sect_opt%do_mosaic) if (run_sect_opt%do_mosaic) then - call spec_file_die_msg(584729163, file, & + call spec_file_die_msg(129153012, file, & "sectional run does not support MOSAIC chemistry") call spec_file_read_logical(file, 'do_optical', run_sect_opt%do_optical) if (run_sect_opt%do_optical) then - call spec_file_die_msg(527436819, file, & + call spec_file_die_msg(627325616, file, & "sectional run does not support optical properties calculation") end if else @@ -339,14 +339,14 @@ subroutine spec_file_read_run_sect(file, run_sect_opt, aero_data, & call spec_file_read_logical(file, 'do_nucleation', & run_sect_opt%do_nucleation) if (run_sect_opt%do_nucleation) then - call spec_file_die_msg(391847265, file, & + call spec_file_die_msg(100312705, file, & "sectional run does not support nucleation") end if call spec_file_read_logical(file, 'do_immersion_freezing', & run_sect_opt%do_immersion_freezing) if (run_sect_opt%do_immersion_freezing) then - call spec_file_die_msg(748291635, file, & + call spec_file_die_msg(160346377, file, & "sectional run does not support immersion freezing") end if