PartMC
2.2.0
|
00001 ! Copyright (C) 2005-2011 Nicole Riemer and Matthew West 00002 ! Licensed under the GNU General Public License version 2 or (at your 00003 ! option) any later version. See the file COPYING for details. 00004 00005 !> \file 00006 !> The pmc_env_state module. 00007 00008 !> The env_state_t structure and associated subroutines. 00009 module pmc_env_state 00010 00011 use pmc_gas_state 00012 use pmc_aero_dist 00013 use pmc_constants 00014 use pmc_aero_data 00015 use pmc_aero_particle 00016 use pmc_aero_binned 00017 use pmc_util 00018 use pmc_gas_data 00019 use pmc_bin_grid 00020 use pmc_aero_state 00021 use pmc_spec_file 00022 use pmc_mpi 00023 use pmc_netcdf 00024 #ifdef PMC_USE_MPI 00025 use mpi 00026 #endif 00027 00028 !> Current environment state. 00029 !! 00030 !! All quantities are instantaneous, describing the state at a 00031 !! particular instant of time. Constant data and other data not 00032 !! associated with the current environment state is store in 00033 !! env_data_t. 00034 !! 00035 !! The emissions and dilution are both described by pairs of a state 00036 !! and a rate. The product of these gives the actual emissions or 00037 !! dilution with units quantity per time. One way to think about 00038 !! this is to set the rate to 1/3600 and then regard the state as an 00039 !! amount per hour, etc. 00040 type env_state_t 00041 !> Temperature (K). 00042 real(kind=dp) :: temp 00043 !> Relative humidity (1). 00044 real(kind=dp) :: rel_humid 00045 !> Ambient pressure (Pa). 00046 real(kind=dp) :: pressure 00047 !> Longitude (degrees). 00048 real(kind=dp) :: longitude 00049 !> Latitude (degrees). 00050 real(kind=dp) :: latitude 00051 !> Altitude (m). 00052 real(kind=dp) :: altitude 00053 !> Start time (s since 00:00 UTC on \c start_day). 00054 real(kind=dp) :: start_time 00055 !> Start day of year (UTC). 00056 integer :: start_day 00057 !> Time since \c start_time (s). 00058 real(kind=dp) :: elapsed_time 00059 !> Solar zenith angle (radians from zenith). 00060 real(kind=dp) :: solar_zenith_angle 00061 !> Box height (m). 00062 real(kind=dp) :: height 00063 !> Gas emissions. 00064 type(gas_state_t) :: gas_emissions 00065 !> Gas emisssion rate (s^{-1}). 00066 real(kind=dp) :: gas_emission_rate 00067 !> Background gas mixing ratios. 00068 type(gas_state_t) :: gas_background 00069 !> Gas-background dilution rate (s^{-1}). 00070 real(kind=dp) :: gas_dilution_rate 00071 !> Aerosol emissions. 00072 type(aero_dist_t) :: aero_emissions 00073 !> Aerosol emisssion rate (s^{-1}). 00074 real(kind=dp) :: aero_emission_rate 00075 !> Aerosol background. 00076 type(aero_dist_t) :: aero_background 00077 !> Aero-background dilute rate (s^{-1}). 00078 real(kind=dp) :: aero_dilution_rate 00079 end type env_state_t 00080 00081 contains 00082 00083 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00084 00085 !> Allocate an empty environment. 00086 subroutine env_state_allocate(env_state) 00087 00088 !> Environment. 00089 type(env_state_t), intent(out) :: env_state 00090 00091 env_state%temp = 0d0 00092 env_state%rel_humid = 0d0 00093 env_state%pressure = 0d0 00094 env_state%longitude = 0d0 00095 env_state%latitude = 0d0 00096 env_state%altitude = 0d0 00097 env_state%start_time = 0d0 00098 env_state%start_day = 0 00099 env_state%elapsed_time = 0d0 00100 env_state%solar_zenith_angle = 0d0 00101 env_state%height = 0d0 00102 00103 call gas_state_allocate(env_state%gas_emissions) 00104 call gas_state_allocate(env_state%gas_background) 00105 env_state%gas_emission_rate = 0d0 00106 env_state%gas_dilution_rate = 0d0 00107 call aero_dist_allocate(env_state%aero_emissions) 00108 call aero_dist_allocate(env_state%aero_background) 00109 env_state%aero_emission_rate = 0d0 00110 env_state%aero_dilution_rate = 0d0 00111 00112 end subroutine env_state_allocate 00113 00114 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00115 00116 !> Free all storage. 00117 subroutine env_state_deallocate(env_state) 00118 00119 !> Environment. 00120 type(env_state_t), intent(inout) :: env_state 00121 00122 call gas_state_deallocate(env_state%gas_emissions) 00123 call gas_state_deallocate(env_state%gas_background) 00124 call aero_dist_deallocate(env_state%aero_emissions) 00125 call aero_dist_deallocate(env_state%aero_background) 00126 00127 end subroutine env_state_deallocate 00128 00129 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00130 00131 !> env_state += env_state_delta 00132 subroutine env_state_add(env_state, env_state_delta) 00133 00134 !> Environment. 00135 type(env_state_t), intent(inout) :: env_state 00136 !> Increment. 00137 type(env_state_t), intent(in) :: env_state_delta 00138 00139 env_state%temp = env_state%temp + env_state_delta%temp 00140 env_state%rel_humid = env_state%rel_humid + env_state_delta%rel_humid 00141 env_state%pressure = env_state%pressure + env_state_delta%pressure 00142 env_state%longitude = env_state%longitude + env_state_delta%longitude 00143 env_state%latitude = env_state%latitude + env_state_delta%latitude 00144 env_state%altitude = env_state%altitude + env_state_delta%altitude 00145 env_state%start_time = env_state%start_time + env_state_delta%start_time 00146 env_state%start_day = env_state%start_day + env_state_delta%start_day 00147 env_state%elapsed_time = env_state%elapsed_time & 00148 + env_state_delta%elapsed_time 00149 env_state%solar_zenith_angle = env_state%solar_zenith_angle & 00150 + env_state_delta%solar_zenith_angle 00151 env_state%height = env_state%height + env_state_delta%height 00152 call gas_state_add(env_state%gas_emissions, env_state_delta%gas_emissions) 00153 env_state%gas_emission_rate = env_state%gas_emission_rate & 00154 + env_state_delta%gas_emission_rate 00155 call gas_state_add(env_state%gas_background, & 00156 env_state_delta%gas_background) 00157 env_state%gas_dilution_rate = env_state%gas_dilution_rate & 00158 + env_state_delta%gas_dilution_rate 00159 env_state%aero_emission_rate = env_state%aero_emission_rate & 00160 + env_state_delta%aero_emission_rate 00161 env_state%aero_dilution_rate = env_state%aero_dilution_rate & 00162 + env_state_delta%aero_dilution_rate 00163 00164 end subroutine env_state_add 00165 00166 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00167 00168 !> env_state *= alpha 00169 subroutine env_state_scale(env_state, alpha) 00170 00171 !> Environment. 00172 type(env_state_t), intent(inout) :: env_state 00173 !> Scale factor. 00174 real(kind=dp), intent(in) :: alpha 00175 00176 env_state%temp = env_state%temp * alpha 00177 env_state%rel_humid = env_state%rel_humid * alpha 00178 env_state%pressure = env_state%pressure * alpha 00179 env_state%longitude = env_state%longitude * alpha 00180 env_state%latitude = env_state%latitude * alpha 00181 env_state%altitude = env_state%altitude * alpha 00182 env_state%start_time = env_state%start_time * alpha 00183 env_state%start_day = nint(real(env_state%start_day, kind=dp) * alpha) 00184 env_state%elapsed_time = env_state%elapsed_time * alpha 00185 env_state%solar_zenith_angle = env_state%solar_zenith_angle * alpha 00186 env_state%height = env_state%height * alpha 00187 call gas_state_scale(env_state%gas_emissions, alpha) 00188 env_state%gas_emission_rate = env_state%gas_emission_rate * alpha 00189 call gas_state_scale(env_state%gas_background, alpha) 00190 env_state%gas_dilution_rate = env_state%gas_dilution_rate * alpha 00191 00192 end subroutine env_state_scale 00193 00194 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00195 00196 !> env_to = env_from 00197 subroutine env_state_copy(env_from, env_to) 00198 00199 !> Original. 00200 type(env_state_t), intent(in) :: env_from 00201 !> Destination. 00202 type(env_state_t), intent(inout) :: env_to 00203 00204 env_to%temp = env_from%temp 00205 env_to%rel_humid = env_from%rel_humid 00206 env_to%pressure = env_from%pressure 00207 env_to%longitude = env_from%longitude 00208 env_to%latitude = env_from%latitude 00209 env_to%altitude = env_from%altitude 00210 env_to%start_time = env_from%start_time 00211 env_to%start_day = env_from%start_day 00212 env_to%elapsed_time = env_from%elapsed_time 00213 env_to%solar_zenith_angle = env_from%solar_zenith_angle 00214 env_to%height = env_from%height 00215 call gas_state_copy(env_from%gas_emissions, env_to%gas_emissions) 00216 env_to%gas_emission_rate = env_from%gas_emission_rate 00217 call gas_state_copy(env_from%gas_background, env_to%gas_background) 00218 env_to%gas_dilution_rate = env_from%gas_dilution_rate 00219 call aero_dist_copy(env_from%aero_emissions, env_to%aero_emissions) 00220 env_to%aero_emission_rate = env_from%aero_emission_rate 00221 call aero_dist_copy(env_from%aero_background, env_to%aero_background) 00222 env_to%aero_dilution_rate = env_from%aero_dilution_rate 00223 00224 end subroutine env_state_copy 00225 00226 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00227 00228 !> Adds the given water volume to the water vapor and updates all 00229 !> environment quantities. 00230 subroutine env_state_change_water_volume(env_state, aero_data, dv) 00231 00232 !> Environment state to update. 00233 type(env_state_t), intent(inout) :: env_state 00234 !> Aero_data constants. 00235 type(aero_data_t), intent(in) :: aero_data 00236 !> Volume concentration of water added (m^3/m^3). 00237 real(kind=dp), intent(in) :: dv 00238 00239 real(kind=dp) pmv ! ambient water vapor pressure (Pa) 00240 real(kind=dp) mv ! ambient water vapor density (kg m^{-3}) 00241 ! pmv and mv are related by the factor molec_weight/(R*T) 00242 real(kind=dp) dmv ! change of water density (kg m^{-3}) 00243 00244 dmv = dv * aero_data%density(aero_data%i_water) 00245 pmv = env_state_sat_vapor_pressure(env_state) * env_state%rel_humid 00246 mv = aero_data%molec_weight(aero_data%i_water) & 00247 / (const%univ_gas_const*env_state%temp) * pmv 00248 mv = mv - dmv 00249 if (mv < 0d0) then 00250 call warn_msg(980320483, "relative humidity tried to go negative") 00251 mv = 0d0 00252 end if 00253 env_state%rel_humid = const%univ_gas_const * env_state%temp & 00254 / aero_data%molec_weight(aero_data%i_water) * mv & 00255 / env_state_sat_vapor_pressure(env_state) 00256 00257 end subroutine env_state_change_water_volume 00258 00259 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00260 00261 !> Computes the current saturation vapor pressure (Pa). 00262 real(kind=dp) function env_state_sat_vapor_pressure(env_state) 00263 00264 !> Environment state. 00265 type(env_state_t), intent(in) :: env_state 00266 00267 env_state_sat_vapor_pressure = const%water_eq_vap_press & 00268 * 10d0**(7.45d0 * (env_state%temp - const%water_freeze_temp) & 00269 / (env_state%temp - 38d0)) 00270 00271 end function env_state_sat_vapor_pressure 00272 00273 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00274 00275 !> Returns the critical relative humidity from the kappa value (1). 00276 real(kind=dp) function aero_particle_kappa_rh(aero_particle, aero_data, & 00277 env_state) 00278 00279 !> Aerosol particle. 00280 type(aero_particle_t), intent(in) :: aero_particle 00281 !> Aerosol data. 00282 type(aero_data_t), intent(in) :: aero_data 00283 !> Environment state. 00284 type(env_state_t), intent(in) :: env_state 00285 00286 real(kind=dp) :: kappa, diam, C, A 00287 00288 kappa = aero_particle_solute_kappa(aero_particle, aero_data) 00289 A = 4d0 * const%water_surf_eng * const%water_molec_weight & 00290 / (const%univ_gas_const * env_state%temp * const%water_density) 00291 C = sqrt(4d0 * A**3 / 27d0) 00292 diam = vol2diam(aero_particle_volume(aero_particle)) 00293 aero_particle_kappa_rh = C / sqrt(kappa * diam**3) + 1d0 00294 00295 end function aero_particle_kappa_rh 00296 00297 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00298 00299 !> Air density (kg m^{-3}). 00300 real(kind=dp) function env_state_air_den(env_state) 00301 00302 !> Environment state. 00303 type(env_state_t), intent(in) :: env_state 00304 00305 env_state_air_den = const%air_molec_weight & 00306 * env_state_air_molar_den(env_state) 00307 00308 end function env_state_air_den 00309 00310 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00311 00312 !> Air molar density (mol m^{-3}). 00313 real(kind=dp) function env_state_air_molar_den(env_state) 00314 00315 !> Environment state. 00316 type(env_state_t), intent(in) :: env_state 00317 00318 env_state_air_molar_den = env_state%pressure & 00319 / (const%univ_gas_const * env_state%temp) 00320 00321 end function env_state_air_molar_den 00322 00323 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00324 00325 !> Convert (mol m^{-3}) to (ppb). 00326 subroutine gas_state_mole_dens_to_ppb(gas_state, env_state) 00327 00328 !> Gas state. 00329 type(gas_state_t), intent(inout) :: gas_state 00330 !> Environment state. 00331 type(env_state_t), intent(in) :: env_state 00332 00333 gas_state%mix_rat = gas_state%mix_rat & 00334 / env_state_air_molar_den(env_state) * 1d9 00335 00336 end subroutine gas_state_mole_dens_to_ppb 00337 00338 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00339 00340 !> Convert (ppb) to (molecules m^{-3}). 00341 real(kind=dp) function env_state_ppb_to_conc(env_state, ppb) 00342 00343 !> Environment state. 00344 type(env_state_t), intent(in) :: env_state 00345 !> Mixing ratio (ppb). 00346 real(kind=dp), intent(in) :: ppb 00347 00348 env_state_ppb_to_conc = ppb / 1d9 * env_state_air_molar_den(env_state) & 00349 * const%avagadro 00350 00351 end function env_state_ppb_to_conc 00352 00353 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00354 00355 !> Convert (molecules m^{-3}) to (ppb). 00356 real(kind=dp) function env_state_conc_to_ppb(env_state, conc) 00357 00358 !> Environment state. 00359 type(env_state_t), intent(in) :: env_state 00360 !> Concentration (molecules m^{-3}). 00361 real(kind=dp), intent(in) :: conc 00362 00363 env_state_conc_to_ppb = conc * 1d9 / env_state_air_molar_den(env_state) & 00364 / const%avagadro 00365 00366 end function env_state_conc_to_ppb 00367 00368 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00369 00370 !> Do emissions and background dilution from the environment. 00371 subroutine env_state_update_gas_state(env_state, delta_t, & 00372 old_env_state, & 00373 gas_data, gas_state) 00374 00375 !> Current environment. 00376 type(env_state_t), intent(in) :: env_state 00377 !> Time increment to update over. 00378 real(kind=dp), intent(in) :: delta_t 00379 !> Previous environment. 00380 type(env_state_t), intent(in) :: old_env_state 00381 !> Gas data values. 00382 type(gas_data_t), intent(in) :: gas_data 00383 !> Gas state to update. 00384 type(gas_state_t), intent(inout) :: gas_state 00385 00386 real(kind=dp) :: effective_dilution_rate 00387 type(gas_state_t) :: emission, dilution 00388 00389 call gas_state_allocate_size(emission, gas_data%n_spec) 00390 call gas_state_allocate_size(dilution, gas_data%n_spec) 00391 00392 ! account for height changes 00393 effective_dilution_rate = env_state%gas_dilution_rate 00394 if (env_state%height > old_env_state%height) then 00395 effective_dilution_rate = effective_dilution_rate & 00396 + (env_state%height - old_env_state%height) / delta_t / & 00397 old_env_state%height 00398 end if 00399 00400 ! emission = delta_t * gas_emission_rate * gas_emissions 00401 ! but emissions are in (mol m^{-2} s^{-1}) 00402 call gas_state_copy(env_state%gas_emissions, emission) 00403 call gas_state_scale(emission, 1d0 / env_state%height) 00404 call gas_state_mole_dens_to_ppb(emission, env_state) 00405 call gas_state_scale(emission, delta_t * env_state%gas_emission_rate) 00406 00407 ! dilution = delta_t * gas_dilution_rate * (gas_background - gas_state) 00408 call gas_state_copy(env_state%gas_background, dilution) 00409 call gas_state_sub(dilution, gas_state) 00410 call gas_state_scale(dilution, delta_t * effective_dilution_rate) 00411 00412 call gas_state_add(gas_state, emission) 00413 call gas_state_add(gas_state, dilution) 00414 00415 call gas_state_ensure_nonnegative(gas_state) 00416 00417 call gas_state_deallocate(emission) 00418 call gas_state_deallocate(dilution) 00419 00420 end subroutine env_state_update_gas_state 00421 00422 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00423 00424 !> Do emissions and background dilution from the environment for a 00425 !> particle aerosol distribution. 00426 subroutine env_state_update_aero_state(env_state, delta_t, & 00427 old_env_state, aero_data, aero_state, n_emit, n_dil_in, n_dil_out) 00428 00429 !> Current environment. 00430 type(env_state_t), intent(in) :: env_state 00431 !> Time increment to update over. 00432 real(kind=dp), intent(in) :: delta_t 00433 !> Previous environment. 00434 type(env_state_t), intent(in) :: old_env_state 00435 !> Aero data values. 00436 type(aero_data_t), intent(in) :: aero_data 00437 !> Aero state to update. 00438 type(aero_state_t), intent(inout) :: aero_state 00439 !> Number of emitted particles. 00440 integer, intent(out) :: n_emit 00441 !> Number of diluted-in particles. 00442 integer, intent(out) :: n_dil_in 00443 !> Number of diluted-out particles. 00444 integer, intent(out) :: n_dil_out 00445 00446 integer :: i 00447 real(kind=dp) :: sample_prop, effective_dilution_rate 00448 type(aero_state_t) :: aero_state_delta 00449 00450 ! account for height changes 00451 effective_dilution_rate = env_state%aero_dilution_rate 00452 if (env_state%height > old_env_state%height) then 00453 effective_dilution_rate = effective_dilution_rate & 00454 + (env_state%height - old_env_state%height) / delta_t / & 00455 old_env_state%height 00456 end if 00457 00458 ! loss to background 00459 sample_prop = 1d0 - exp(- delta_t * effective_dilution_rate) 00460 call aero_state_allocate(aero_state_delta) 00461 call aero_state_sample_particles(aero_state, aero_state_delta, & 00462 sample_prop, AERO_INFO_DILUTION) 00463 n_dil_out = aero_state_total_particles(aero_state_delta) 00464 call aero_state_deallocate(aero_state_delta) 00465 00466 ! addition from background 00467 sample_prop = 1d0 - exp(- delta_t * effective_dilution_rate) 00468 call aero_state_add_aero_dist_sample(aero_state, aero_data, & 00469 env_state%aero_background, sample_prop, env_state%elapsed_time, & 00470 n_dil_in) 00471 00472 ! emissions 00473 sample_prop = 1d0 & 00474 - exp(- delta_t * env_state%aero_emission_rate / env_state%height) 00475 call aero_state_add_aero_dist_sample(aero_state, aero_data, & 00476 env_state%aero_emissions, sample_prop, env_state%elapsed_time, n_emit) 00477 00478 ! update computational volume 00479 call aero_weight_scale_comp_vol(aero_state%aero_weight, & 00480 env_state%temp / old_env_state%temp) 00481 00482 end subroutine env_state_update_aero_state 00483 00484 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00485 00486 !> Do emissions and background dilution from the environment for a 00487 !> binned aerosol distribution. 00488 subroutine env_state_update_aero_binned(env_state, delta_t, & 00489 old_env_state, bin_grid, aero_data, aero_binned) 00490 00491 !> Current environment. 00492 type(env_state_t), intent(in) :: env_state 00493 !> Time increment to update over. 00494 real(kind=dp), intent(in) :: delta_t 00495 !> Previous environment. 00496 type(env_state_t), intent(in) :: old_env_state 00497 !> Bin grid. 00498 type(bin_grid_t), intent(in) :: bin_grid 00499 !> Aero data values. 00500 type(aero_data_t), intent(in) :: aero_data 00501 !> Aero binned to update. 00502 type(aero_binned_t), intent(inout) :: aero_binned 00503 00504 type(aero_binned_t) :: emission, dilution 00505 real(kind=dp) :: effective_dilution_rate 00506 00507 call aero_binned_allocate_size(emission, bin_grid%n_bin, aero_data%n_spec) 00508 call aero_binned_allocate_size(dilution, bin_grid%n_bin, aero_data%n_spec) 00509 00510 ! account for height changes 00511 effective_dilution_rate = env_state%aero_dilution_rate 00512 if (env_state%height > old_env_state%height) then 00513 effective_dilution_rate = effective_dilution_rate & 00514 + (env_state%height - old_env_state%height) / delta_t / & 00515 old_env_state%height 00516 end if 00517 00518 ! emission = delta_t * aero_emission_rate * aero_emissions 00519 ! but emissions are #/m^2 so we need to divide by height 00520 call aero_binned_add_aero_dist(emission, bin_grid, aero_data, & 00521 env_state%aero_emissions) 00522 call aero_binned_scale(emission, & 00523 delta_t * env_state%aero_emission_rate / env_state%height) 00524 00525 ! dilution = delta_t * aero_dilution_rate 00526 ! * (aero_background - aero_binned) 00527 call aero_binned_add_aero_dist(dilution, bin_grid, aero_data, & 00528 env_state%aero_background) 00529 call aero_binned_sub(dilution, aero_binned) 00530 call aero_binned_scale(dilution, delta_t * effective_dilution_rate) 00531 00532 call aero_binned_add(aero_binned, emission) 00533 call aero_binned_add(aero_binned, dilution) 00534 00535 call aero_binned_deallocate(emission) 00536 call aero_binned_deallocate(dilution) 00537 00538 end subroutine env_state_update_aero_binned 00539 00540 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00541 00542 !> Read environment specification from a spec file. 00543 subroutine spec_file_read_env_state(file, env_state) 00544 00545 !> Spec file. 00546 type(spec_file_t), intent(inout) :: file 00547 !> Environment data. 00548 type(env_state_t), intent(inout) :: env_state 00549 00550 !> \page input_format_env_state Input File Format: Environment State 00551 !! 00552 !! The environment parameters are divided into those specified at 00553 !! the start of the simulation and then either held constant or 00554 !! computed for the rest of the simulation, and those parameters 00555 !! given as prescribed profiles for the entire simulation 00556 !! duration. The variables below are for the first type --- for 00557 !! the prescribed profiles see \ref input_format_env_data. 00558 !! 00559 !! The environment state is specified by the parameters: 00560 !! - \b rel_humidity (real, dimensionless): the relative humidity 00561 !! (0 is completely unsaturated and 1 is fully saturated) 00562 !! - \b pressure (real, unit Pa): the atmospheric pressure 00563 !! - \b latitude (real, unit degrees_north): the latitude of the 00564 !! simulation location 00565 !! - \b longitude (real, unit degrees_east): the longitude of the 00566 !! simulation location 00567 !! - \b altitude (real, unit m): the altitude of the simulation 00568 !! location 00569 !! - \b start_time (real, unit s): the time-of-day of the start of 00570 !! the simulation (in seconds past midnight) 00571 !! - \b start_day (integer): the day-of-year of the start of the 00572 !! simulation (starting from 1 on the first day of the year) 00573 !! 00574 !! See also: 00575 !! - \ref spec_file_format --- the input file text format 00576 !! - \ref output_format_env_state --- the corresponding output 00577 !! format 00578 !! - \ref input_format_env_data --- the prescribed profiles of 00579 !! other environment data 00580 00581 call spec_file_read_real(file, 'rel_humidity', env_state%rel_humid) 00582 call spec_file_read_real(file, 'pressure', env_state%pressure) 00583 call spec_file_read_real(file, 'latitude', env_state%latitude) 00584 call spec_file_read_real(file, 'longitude', env_state%longitude) 00585 call spec_file_read_real(file, 'altitude', env_state%altitude) 00586 call spec_file_read_real(file, 'start_time', env_state%start_time) 00587 call spec_file_read_integer(file, 'start_day', env_state%start_day) 00588 00589 end subroutine spec_file_read_env_state 00590 00591 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00592 00593 !> Average val over all processes. 00594 subroutine env_state_mix(val) 00595 00596 !> Value to average. 00597 type(env_state_t), intent(inout) :: val 00598 00599 #ifdef PMC_USE_MPI 00600 type(env_state_t) :: val_avg 00601 00602 call env_state_allocate(val_avg) 00603 call pmc_mpi_allreduce_average_real(val%temp, val_avg%temp) 00604 call pmc_mpi_allreduce_average_real(val%rel_humid, val_avg%rel_humid) 00605 call pmc_mpi_allreduce_average_real(val%pressure, val_avg%pressure) 00606 val%temp = val_avg%temp 00607 val%rel_humid = val_avg%rel_humid 00608 val%pressure = val_avg%pressure 00609 call env_state_deallocate(val_avg) 00610 #endif 00611 00612 end subroutine env_state_mix 00613 00614 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00615 00616 !> Average val over all processes, with the result only on the root 00617 !> process. 00618 subroutine env_state_reduce_avg(val) 00619 00620 !> Value to average. 00621 type(env_state_t), intent(inout) :: val 00622 00623 #ifdef PMC_USE_MPI 00624 type(env_state_t) :: val_avg 00625 00626 call env_state_allocate(val_avg) 00627 call pmc_mpi_reduce_avg_real(val%temp, val_avg%temp) 00628 call pmc_mpi_reduce_avg_real(val%rel_humid, val_avg%rel_humid) 00629 call pmc_mpi_reduce_avg_real(val%pressure, val_avg%pressure) 00630 if (pmc_mpi_rank() == 0) then 00631 val%temp = val_avg%temp 00632 val%rel_humid = val_avg%rel_humid 00633 val%pressure = val_avg%pressure 00634 end if 00635 call env_state_deallocate(val_avg) 00636 #endif 00637 00638 end subroutine env_state_reduce_avg 00639 00640 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00641 00642 !> Determines the number of bytes required to pack the given value. 00643 integer function pmc_mpi_pack_size_env_state(val) 00644 00645 !> Value to pack. 00646 type(env_state_t), intent(in) :: val 00647 00648 pmc_mpi_pack_size_env_state = & 00649 pmc_mpi_pack_size_real(val%temp) & 00650 + pmc_mpi_pack_size_real(val%rel_humid) & 00651 + pmc_mpi_pack_size_real(val%pressure) & 00652 + pmc_mpi_pack_size_real(val%longitude) & 00653 + pmc_mpi_pack_size_real(val%latitude) & 00654 + pmc_mpi_pack_size_real(val%altitude) & 00655 + pmc_mpi_pack_size_real(val%start_time) & 00656 + pmc_mpi_pack_size_integer(val%start_day) & 00657 + pmc_mpi_pack_size_real(val%elapsed_time) & 00658 + pmc_mpi_pack_size_real(val%solar_zenith_angle) & 00659 + pmc_mpi_pack_size_real(val%height) & 00660 + pmc_mpi_pack_size_gas_state(val%gas_emissions) & 00661 + pmc_mpi_pack_size_real(val%gas_emission_rate) & 00662 + pmc_mpi_pack_size_gas_state(val%gas_background) & 00663 + pmc_mpi_pack_size_real(val%gas_dilution_rate) & 00664 + pmc_mpi_pack_size_aero_dist(val%aero_emissions) & 00665 + pmc_mpi_pack_size_real(val%aero_emission_rate) & 00666 + pmc_mpi_pack_size_aero_dist(val%aero_background) & 00667 + pmc_mpi_pack_size_real(val%aero_dilution_rate) 00668 00669 end function pmc_mpi_pack_size_env_state 00670 00671 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00672 00673 !> Packs the given value into the buffer, advancing position. 00674 subroutine pmc_mpi_pack_env_state(buffer, position, val) 00675 00676 !> Memory buffer. 00677 character, intent(inout) :: buffer(:) 00678 !> Current buffer position. 00679 integer, intent(inout) :: position 00680 !> Value to pack. 00681 type(env_state_t), intent(in) :: val 00682 00683 #ifdef PMC_USE_MPI 00684 integer :: prev_position 00685 00686 prev_position = position 00687 call pmc_mpi_pack_real(buffer, position, val%temp) 00688 call pmc_mpi_pack_real(buffer, position, val%rel_humid) 00689 call pmc_mpi_pack_real(buffer, position, val%pressure) 00690 call pmc_mpi_pack_real(buffer, position, val%longitude) 00691 call pmc_mpi_pack_real(buffer, position, val%latitude) 00692 call pmc_mpi_pack_real(buffer, position, val%altitude) 00693 call pmc_mpi_pack_real(buffer, position, val%start_time) 00694 call pmc_mpi_pack_integer(buffer, position, val%start_day) 00695 call pmc_mpi_pack_real(buffer, position, val%elapsed_time) 00696 call pmc_mpi_pack_real(buffer, position, val%solar_zenith_angle) 00697 call pmc_mpi_pack_real(buffer, position, val%height) 00698 call pmc_mpi_pack_gas_state(buffer, position, val%gas_emissions) 00699 call pmc_mpi_pack_real(buffer, position, val%gas_emission_rate) 00700 call pmc_mpi_pack_gas_state(buffer, position, val%gas_background) 00701 call pmc_mpi_pack_real(buffer, position, val%gas_dilution_rate) 00702 call pmc_mpi_pack_aero_dist(buffer, position, val%aero_emissions) 00703 call pmc_mpi_pack_real(buffer, position, val%aero_emission_rate) 00704 call pmc_mpi_pack_aero_dist(buffer, position, val%aero_background) 00705 call pmc_mpi_pack_real(buffer, position, val%aero_dilution_rate) 00706 call assert(464101191, & 00707 position - prev_position <= pmc_mpi_pack_size_env_state(val)) 00708 #endif 00709 00710 end subroutine pmc_mpi_pack_env_state 00711 00712 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00713 00714 !> Unpacks the given value from the buffer, advancing position. 00715 subroutine pmc_mpi_unpack_env_state(buffer, position, val) 00716 00717 !> Memory buffer. 00718 character, intent(inout) :: buffer(:) 00719 !> Current buffer position. 00720 integer, intent(inout) :: position 00721 !> Value to pack. 00722 type(env_state_t), intent(inout) :: val 00723 00724 #ifdef PMC_USE_MPI 00725 integer :: prev_position 00726 00727 prev_position = position 00728 call pmc_mpi_unpack_real(buffer, position, val%temp) 00729 call pmc_mpi_unpack_real(buffer, position, val%rel_humid) 00730 call pmc_mpi_unpack_real(buffer, position, val%pressure) 00731 call pmc_mpi_unpack_real(buffer, position, val%longitude) 00732 call pmc_mpi_unpack_real(buffer, position, val%latitude) 00733 call pmc_mpi_unpack_real(buffer, position, val%altitude) 00734 call pmc_mpi_unpack_real(buffer, position, val%start_time) 00735 call pmc_mpi_unpack_integer(buffer, position, val%start_day) 00736 call pmc_mpi_unpack_real(buffer, position, val%elapsed_time) 00737 call pmc_mpi_unpack_real(buffer, position, val%solar_zenith_angle) 00738 call pmc_mpi_unpack_real(buffer, position, val%height) 00739 call pmc_mpi_unpack_gas_state(buffer, position, val%gas_emissions) 00740 call pmc_mpi_unpack_real(buffer, position, val%gas_emission_rate) 00741 call pmc_mpi_unpack_gas_state(buffer, position, val%gas_background) 00742 call pmc_mpi_unpack_real(buffer, position, val%gas_dilution_rate) 00743 call pmc_mpi_unpack_aero_dist(buffer, position, val%aero_emissions) 00744 call pmc_mpi_unpack_real(buffer, position, val%aero_emission_rate) 00745 call pmc_mpi_unpack_aero_dist(buffer, position, val%aero_background) 00746 call pmc_mpi_unpack_real(buffer, position, val%aero_dilution_rate) 00747 call assert(205696745, & 00748 position - prev_position <= pmc_mpi_pack_size_env_state(val)) 00749 #endif 00750 00751 end subroutine pmc_mpi_unpack_env_state 00752 00753 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00754 00755 !> Computes the average of val across all processes, storing the 00756 !> result in val_avg on the root process. 00757 subroutine pmc_mpi_reduce_avg_env_state(val, val_avg) 00758 00759 !> Value to average. 00760 type(env_state_t), intent(in) :: val 00761 !> Result. 00762 type(env_state_t), intent(inout) :: val_avg 00763 00764 call env_state_allocate(val_avg) 00765 call env_state_copy(val, val_avg) 00766 call pmc_mpi_reduce_avg_real(val%temp, val_avg%temp) 00767 call pmc_mpi_reduce_avg_real(val%rel_humid, val_avg%rel_humid) 00768 call pmc_mpi_reduce_avg_real(val%pressure, val_avg%pressure) 00769 00770 end subroutine pmc_mpi_reduce_avg_env_state 00771 00772 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00773 00774 !> Write full state. 00775 subroutine env_state_output_netcdf(env_state, ncid) 00776 00777 !> Environment state to write. 00778 type(env_state_t), intent(in) :: env_state 00779 !> NetCDF file ID, in data mode. 00780 integer, intent(in) :: ncid 00781 00782 !> \page output_format_env_state Output File Format: Environment State 00783 !! 00784 !! The environment state NetCDF variables are: 00785 !! - \b temperature (unit K): current air temperature 00786 !! - \b relative_humidity (dimensionless): current air 00787 !! relative humidity (value of 1 means completely saturated) 00788 !! - \b pressure (unit Pa): current air pressure 00789 !! - \b longitude (unit degrees_east): longitude of simulation location 00790 !! - \b latitude (unit degrees_north): latitude of simulation location 00791 !! - \b altitude (unit m): altitude of simulation location 00792 !! - \b start_time_of_day (unit s): time-of-day of the 00793 !! simulation start measured in seconds after midnight UTC 00794 !! - \b start_day_of_year: day-in-year number of the simulation start 00795 !! (starting from 1 on the first day of the year) 00796 !! - \b elapsed_time (unit s): elapsed time since the simulation start 00797 !! - \b solar_zenith_angle (unit radians): current angle from 00798 !! the zenith to the sun 00799 !! - \b height (unit m): current boundary layer mixing height 00800 !! 00801 !! See also: 00802 !! - \ref input_format_env_state and \ref input_format_env_data 00803 !! --- the corresponding input formats 00804 00805 call pmc_nc_write_real(ncid, env_state%temp, "temperature", unit="K", & 00806 standard_name="air_temperature") 00807 call pmc_nc_write_real(ncid, env_state%rel_humid, & 00808 "relative_humidity", unit="1", standard_name="relative_humidity") 00809 call pmc_nc_write_real(ncid, env_state%pressure, "pressure", unit="Pa", & 00810 standard_name="air_pressure") 00811 call pmc_nc_write_real(ncid, env_state%longitude, "longitude", & 00812 unit="degree_east", standard_name="longitude") 00813 call pmc_nc_write_real(ncid, env_state%latitude, "latitude", & 00814 unit="degree_north", standard_name="latitude") 00815 call pmc_nc_write_real(ncid, env_state%altitude, "altitude", unit="m", & 00816 standard_name="altitude") 00817 call pmc_nc_write_real(ncid, env_state%start_time, & 00818 "start_time_of_day", unit="s", description="time-of-day of " & 00819 // "simulation start in seconds since midnight") 00820 call pmc_nc_write_integer(ncid, env_state%start_day, & 00821 "start_day_of_year", & 00822 description="day-of-year number of simulation start") 00823 call pmc_nc_write_real(ncid, env_state%elapsed_time, "elapsed_time", & 00824 unit="s", description="elapsed time since simulation start") 00825 call pmc_nc_write_real(ncid, env_state%solar_zenith_angle, & 00826 "solar_zenith_angle", unit="radian", & 00827 description="current angle from the zenith to the sun") 00828 call pmc_nc_write_real(ncid, env_state%height, "height", unit="m", & 00829 long_name="boundary layer mixing height") 00830 00831 end subroutine env_state_output_netcdf 00832 00833 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00834 00835 !> Read full state. 00836 subroutine env_state_input_netcdf(env_state, ncid) 00837 00838 !> Environment state to read. 00839 type(env_state_t), intent(inout) :: env_state 00840 !> NetCDF file ID, in data mode. 00841 integer, intent(in) :: ncid 00842 00843 call pmc_nc_read_real(ncid, env_state%temp, "temperature") 00844 call pmc_nc_read_real(ncid, env_state%rel_humid, "relative_humidity") 00845 call pmc_nc_read_real(ncid, env_state%pressure, "pressure") 00846 call pmc_nc_read_real(ncid, env_state%longitude, "longitude") 00847 call pmc_nc_read_real(ncid, env_state%latitude, "latitude") 00848 call pmc_nc_read_real(ncid, env_state%altitude, "altitude") 00849 call pmc_nc_read_real(ncid, env_state%start_time, & 00850 "start_time_of_day") 00851 call pmc_nc_read_integer(ncid, env_state%start_day, & 00852 "start_day_of_year") 00853 call pmc_nc_read_real(ncid, env_state%elapsed_time, "elapsed_time") 00854 call pmc_nc_read_real(ncid, env_state%solar_zenith_angle, & 00855 "solar_zenith_angle") 00856 call pmc_nc_read_real(ncid, env_state%height, "height") 00857 00858 end subroutine env_state_input_netcdf 00859 00860 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00861 00862 end module pmc_env_state