PartMC  2.2.0
env_state.F90
Go to the documentation of this file.
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