diff --git a/schemes/musica/micm/musica_ccpp_micm.F90 b/schemes/musica/micm/musica_ccpp_micm.F90 index 7b9fbae9..6fcaf320 100644 --- a/schemes/musica/micm/musica_ccpp_micm.F90 +++ b/schemes/musica/micm/musica_ccpp_micm.F90 @@ -108,7 +108,6 @@ subroutine micm_run(time_step, temperature, pressure, dry_air_density, & type(string_t) :: solver_state type(solver_stats_t) :: solver_stats type(error_t) :: error - integer :: i_elem call micm%solve(real(time_step, kind=c_double), & c_loc(temperature), & diff --git a/schemes/musica/musica_ccpp.F90 b/schemes/musica/musica_ccpp.F90 index d3512f4a..3fc66299 100644 --- a/schemes/musica/musica_ccpp.F90 +++ b/schemes/musica/musica_ccpp.F90 @@ -55,10 +55,12 @@ end subroutine musica_ccpp_init !! The standard name for the variable 'surface_temperature' is !! 'blackbody_temperature_at_surface' because this is what we have as !! the standard name for 'cam_in%ts', whcih represents the same quantity. - subroutine musica_ccpp_run(time_step, temperature, pressure, dry_air_density, constituent_props, & - constituents, geopotential_height_wrt_surface_at_midpoint, & - geopotential_height_wrt_surface_at_interface, surface_temperature, & - surface_geopotential, surface_albedo, & + subroutine musica_ccpp_run(time_step, temperature, pressure, dry_air_density, constituent_props, & + constituents, geopotential_height_wrt_surface_at_midpoint, & + geopotential_height_wrt_surface_at_interface, surface_geopotential, & + surface_temperature, surface_albedo, & + number_of_photolysis_wavelength_grid_sections, & + photolysis_wavelength_grid_interfaces, extraterrestrial_flux, & standard_gravitational_acceleration, errmsg, errcode) use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use ccpp_kinds, only: kind_phys @@ -74,9 +76,12 @@ subroutine musica_ccpp_run(time_step, temperature, pressure, dry_air_density, co real(kind_phys), target, intent(inout) :: constituents(:,:,:) ! kg kg-1 real(kind_phys), intent(in) :: geopotential_height_wrt_surface_at_midpoint(:,:) ! m (column, layer) real(kind_phys), intent(in) :: geopotential_height_wrt_surface_at_interface(:,:) ! m (column, interface) - real(kind_phys), intent(in) :: surface_temperature(:) ! K real(kind_phys), intent(in) :: surface_geopotential(:) ! m2 s-2 + real(kind_phys), intent(in) :: surface_temperature(:) ! K real(kind_phys), intent(in) :: surface_albedo ! unitless + integer, intent(in) :: number_of_photolysis_wavelength_grid_sections ! (count) + real(kind_phys), intent(in) :: photolysis_wavelength_grid_interfaces(:) ! nm + real(kind_phys), intent(in) :: extraterrestrial_flux(:) ! photons cm-2 s-1 nm-1 real(kind_phys), intent(in) :: standard_gravitational_acceleration ! m s-2 character(len=512), intent(out) :: errmsg integer, intent(out) :: errcode @@ -89,13 +94,16 @@ subroutine musica_ccpp_run(time_step, temperature, pressure, dry_air_density, co integer :: i_elem ! Calculate photolysis rate constants using TUV-x - call tuvx_run(temperature, dry_air_density, & - geopotential_height_wrt_surface_at_midpoint, & - geopotential_height_wrt_surface_at_interface, & - surface_temperature, surface_geopotential, & - surface_albedo, & - standard_gravitational_acceleration, & - rate_parameters, & + call tuvx_run(temperature, dry_air_density, & + geopotential_height_wrt_surface_at_midpoint, & + geopotential_height_wrt_surface_at_interface, & + surface_geopotential, surface_temperature, & + surface_albedo, & + number_of_photolysis_wavelength_grid_sections, & + photolysis_wavelength_grid_interfaces, & + extraterrestrial_flux, & + standard_gravitational_acceleration, & + rate_parameters, & errmsg, errcode) ! Get the molar mass that is set in the call to instantiate() @@ -140,4 +148,4 @@ subroutine musica_ccpp_final(errmsg, errcode) end subroutine musica_ccpp_final -end module musica_ccpp +end module musica_ccpp \ No newline at end of file diff --git a/schemes/musica/musica_ccpp.meta b/schemes/musica/musica_ccpp.meta index 85e01f3e..2929d10f 100644 --- a/schemes/musica/musica_ccpp.meta +++ b/schemes/musica/musica_ccpp.meta @@ -123,24 +123,42 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent,vertical_interface_dimension) intent = in -[ surface_temperature ] - standard_name = blackbody_temperature_at_surface - type = real | kind = kind_phys - units = K - dimensions = (horizontal_loop_extent) - intent = in [ surface_geopotential ] standard_name = surface_geopotential type = real | kind = kind_phys units = m2 s-2 dimensions = (horizontal_loop_extent) intent = in +[ surface_temperature ] + standard_name = blackbody_temperature_at_surface + type = real | kind = kind_phys + units = K + dimensions = (horizontal_loop_extent) + intent = in [ surface_albedo ] standard_name = surface_albedo_due_to_UV_and_VIS_direct type = real | kind = kind_phys units = None dimensions = () intent = in +[ number_of_photolysis_wavelength_grid_sections ] + standard_name = number_of_photolysis_wavelength_grid_sections + type = integer + units = None + dimensions = () + intent = in +[ photolysis_wavelength_grid_interfaces ] + standard_name = photolysis_wavelength_grid_interfaces + type = real | kind = kind_phys + units = nm + dimensions = (horizontal_loop_extent) + intent = in +[ extraterrestrial_flux ] + standard_name = extraterrestrial_radiation_flux + type = real | kind = kind_phys + units = photons cm-2 s-1 nm-1 + dimensions = (horizontal_loop_extent) + intent = in [ standard_gravitational_acceleration ] standard_name = standard_gravitational_acceleration units = m s-2 diff --git a/schemes/musica/tuvx/musica_ccpp_tuvx.F90 b/schemes/musica/tuvx/musica_ccpp_tuvx.F90 index 5a12a3ee..0312746c 100644 --- a/schemes/musica/tuvx/musica_ccpp_tuvx.F90 +++ b/schemes/musica/tuvx/musica_ccpp_tuvx.F90 @@ -9,21 +9,68 @@ module musica_ccpp_tuvx use musica_util, only: mappings_t, index_mappings_t implicit none - private - public :: tuvx_init, tuvx_run, tuvx_final - - type(tuvx_t), pointer :: tuvx => null() - type(grid_t), pointer :: height_grid => null() - type(grid_t), pointer :: wavelength_grid => null() - type(profile_t), pointer :: temperature_profile => null() - type(profile_t), pointer :: surface_albedo_profile => null() - + private :: reset_tuvx_map_state, cleanup_tuvx_resources + + type(tuvx_t), pointer :: tuvx => null() + type(grid_t), pointer :: height_grid => null() + type(grid_t), pointer :: wavelength_grid => null() + type(profile_t), pointer :: temperature_profile => null() + type(profile_t), pointer :: surface_albedo_profile => null() + type(profile_t), pointer :: extraterrestrial_flux_profile => null() type(index_mappings_t), pointer :: photolysis_rate_constants_mapping => null( ) - integer :: number_of_photolysis_rate_constants = 0 + integer :: number_of_photolysis_rate_constants = 0 contains + subroutine reset_tuvx_map_state( grids, profiles, radiators ) + use musica_tuvx, only: grid_map_t, profile_map_t, radiator_map_t + + type(grid_map_t), pointer :: grids + type(profile_map_t), pointer :: profiles + type(radiator_map_t), pointer :: radiators + + if (associated( grids )) deallocate( grids ) + if (associated( profiles )) deallocate( profiles ) + if (associated( radiators )) deallocate( radiators ) + + end subroutine reset_tuvx_map_state + + !> This is a helper subroutine created to deallocate objects associated with TUV-x + subroutine cleanup_tuvx_resources() + + if (associated( height_grid )) then + deallocate( height_grid ) + height_grid => null() + end if + + if (associated( wavelength_grid )) then + deallocate( wavelength_grid ) + wavelength_grid => null() + end if + + if (associated( temperature_profile )) then + deallocate( temperature_profile ) + temperature_profile => null() + end if + + if (associated( surface_albedo_profile )) then + deallocate( surface_albedo_profile ) + surface_albedo_profile => null() + end if + + if (associated( extraterrestrial_flux_profile )) then + deallocate( extraterrestrial_flux_profile ) + extraterrestrial_flux_profile => null() + end if + + if (associated( photolysis_rate_constants_mapping )) then + deallocate( photolysis_rate_constants_mapping ) + photolysis_rate_constants_mapping => null() + end if + + end subroutine cleanup_tuvx_resources + !> Initializes TUV-x subroutine tuvx_init(vertical_layer_dimension, vertical_interface_dimension, & wavelength_grid_interfaces, micm_rate_parameter_ordering, & @@ -31,7 +78,6 @@ subroutine tuvx_init(vertical_layer_dimension, vertical_interface_dimension, & use musica_tuvx, only: grid_map_t, profile_map_t, radiator_map_t use musica_util, only: error_t, configuration_t use musica_ccpp_namelist, only: filename_of_tuvx_micm_mapping_configuration - use musica_ccpp_tuvx_util, only: tuvx_deallocate use musica_ccpp_tuvx_height_grid, & only: create_height_grid, height_grid_label, height_grid_unit use musica_ccpp_tuvx_wavelength_grid, & @@ -40,11 +86,14 @@ subroutine tuvx_init(vertical_layer_dimension, vertical_interface_dimension, & only: create_temperature_profile, temperature_label, temperature_unit use musica_ccpp_tuvx_surface_albedo, & only: create_surface_albedo_profile, surface_albedo_label, surface_albedo_unit + use musica_ccpp_tuvx_extraterrestrial_flux, & + only: create_extraterrestrial_flux_profile, extraterrestrial_flux_label, & + extraterrestrial_flux_unit integer, intent(in) :: vertical_layer_dimension ! (count) integer, intent(in) :: vertical_interface_dimension ! (count) real(kind_phys), intent(in) :: wavelength_grid_interfaces(:) ! m - type(mappings_t), intent(in) :: micm_rate_parameter_ordering ! index mappings for MICM rate parameters + type(mappings_t), intent(in) :: micm_rate_parameter_ordering ! index mappings for MICM rate parameters character(len=512), intent(out) :: errmsg integer, intent(out) :: errcode @@ -62,170 +111,216 @@ subroutine tuvx_init(vertical_layer_dimension, vertical_interface_dimension, & height_grid => create_height_grid( vertical_layer_dimension, & vertical_interface_dimension, errmsg, errcode ) if (errcode /= 0) then - deallocate( grids ) + call reset_tuvx_map_state( grids, null(), null() ) return endif call grids%add( height_grid, error ) if (has_error_occurred( error, errmsg, errcode )) then - call tuvx_deallocate( grids, null(), null(), null(), height_grid, null(), & - null(), null() ) + call reset_tuvx_map_state( grids, null(), null() ) + call cleanup_tuvx_resources() return end if wavelength_grid => create_wavelength_grid( wavelength_grid_interfaces, & errmsg, errcode ) if (errcode /= 0) then - call tuvx_deallocate( grids, null(), null(), null(), height_grid, null(), & - null(), null() ) + call reset_tuvx_map_state( grids, null(), null() ) + call cleanup_tuvx_resources() return endif call grids%add( wavelength_grid, error ) if (has_error_occurred( error, errmsg, errcode )) then - call tuvx_deallocate( grids, null(), null(), null(), height_grid, & - wavelength_grid, null(), null() ) + call reset_tuvx_map_state( grids, null(), null() ) + call cleanup_tuvx_resources() return end if profiles => profile_map_t( error ) if (has_error_occurred( error, errmsg, errcode )) then - call tuvx_deallocate( grids, null(), null(), null(), height_grid, & - wavelength_grid, null(), null() ) + call reset_tuvx_map_state( grids, null(), null() ) + call cleanup_tuvx_resources() return end if temperature_profile => create_temperature_profile( height_grid, errmsg, errcode ) if (errcode /= 0) then - call tuvx_deallocate( grids, profiles, null(), null(), height_grid, & - wavelength_grid, null(), null() ) + call reset_tuvx_map_state( grids, profiles, null() ) + call cleanup_tuvx_resources() return endif call profiles%add( temperature_profile, error ) if (has_error_occurred( error, errmsg, errcode )) then - call tuvx_deallocate( grids, profiles, null(), null(), height_grid, & - wavelength_grid, temperature_profile, null() ) + call reset_tuvx_map_state( grids, profiles, null() ) + call cleanup_tuvx_resources() return end if surface_albedo_profile => create_surface_albedo_profile( wavelength_grid, & errmsg, errcode ) if (errcode /= 0) then - call tuvx_deallocate( grids, profiles, null(), null(), height_grid, & - wavelength_grid, temperature_profile, null() ) + call reset_tuvx_map_state( grids, profiles, null() ) + call cleanup_tuvx_resources() return endif call profiles%add( surface_albedo_profile, error ) if (has_error_occurred( error, errmsg, errcode )) then - call tuvx_deallocate( grids, profiles, null(), null(), height_grid, & - wavelength_grid, temperature_profile, surface_albedo_profile ) + call reset_tuvx_map_state( grids, profiles, null() ) + call cleanup_tuvx_resources() + return + end if + + extraterrestrial_flux_profile => create_extraterrestrial_flux_profile( & + wavelength_grid, wavelength_grid_interfaces, errmsg, errcode ) + if (errcode /= 0) then + call reset_tuvx_map_state( grids, profiles, null() ) + call cleanup_tuvx_resources() + return + endif + + call profiles%add( extraterrestrial_flux_profile, error ) + if (has_error_occurred( error, errmsg, errcode )) then + call reset_tuvx_map_state( grids, profiles, null() ) + call cleanup_tuvx_resources() return end if radiators => radiator_map_t( error ) if (has_error_occurred( error, errmsg, errcode )) then - call tuvx_deallocate( grids, profiles, null(), null(), height_grid, & - wavelength_grid, temperature_profile, surface_albedo_profile ) + call reset_tuvx_map_state( grids, profiles, null() ) + call cleanup_tuvx_resources() return end if tuvx => tuvx_t( trim(filename_of_tuvx_configuration), grids, profiles, & radiators, error ) if (has_error_occurred( error, errmsg, errcode )) then - call tuvx_deallocate( grids, profiles, radiators, null(), height_grid, & - wavelength_grid, temperature_profile, surface_albedo_profile ) + call reset_tuvx_map_state( grids, profiles, radiators ) + call cleanup_tuvx_resources() return end if - call tuvx_deallocate( grids, profiles, radiators, null(), height_grid, & - wavelength_grid, temperature_profile, surface_albedo_profile ) + ! Gets resources associated with TUV-x from tuvx + call reset_tuvx_map_state( grids, profiles, radiators ) + call cleanup_tuvx_resources() grids => tuvx%get_grids( error ) - if (has_error_occurred( error, errmsg, errcode )) return + if (has_error_occurred( error, errmsg, errcode )) then + deallocate( tuvx ) + return + end if height_grid => grids%get( height_grid_label, height_grid_unit, error ) if (has_error_occurred( error, errmsg, errcode )) then - call tuvx_deallocate( grids, null(), null(), tuvx, null(), null(), & - null(), null() ) + deallocate( tuvx ) + call reset_tuvx_map_state( grids, null(), null() ) return end if wavelength_grid => grids%get( wavelength_grid_label, wavelength_grid_unit, & error ) if (has_error_occurred( error, errmsg, errcode )) then - call tuvx_deallocate( grids, null(), null(), tuvx, height_grid, null(), & - null(), null() ) + deallocate( tuvx ) + call reset_tuvx_map_state( grids, null(), null() ) + call cleanup_tuvx_resources() return end if profiles => tuvx%get_profiles( error ) if (has_error_occurred( error, errmsg, errcode )) then - call tuvx_deallocate( grids, null(), null(), tuvx, height_grid, & - wavelength_grid, null(), null() ) + deallocate( tuvx ) + call reset_tuvx_map_state( grids, null(), null() ) + call cleanup_tuvx_resources() return end if temperature_profile => profiles%get( temperature_label, temperature_unit, error ) if (has_error_occurred( error, errmsg, errcode )) then - call tuvx_deallocate( grids, profiles, null(), tuvx, height_grid, & - wavelength_grid, null(), null() ) + deallocate( tuvx ) + call reset_tuvx_map_state( grids, profiles, null() ) + call cleanup_tuvx_resources() return end if surface_albedo_profile => profiles%get( surface_albedo_label, surface_albedo_unit, error ) if (has_error_occurred( error, errmsg, errcode )) then - call tuvx_deallocate( grids, profiles, null(), tuvx, height_grid, & - wavelength_grid, temperature_profile, null() ) + deallocate( tuvx ) + call reset_tuvx_map_state( grids, profiles, null() ) + call cleanup_tuvx_resources() return end if - call tuvx_deallocate( grids, profiles, null(), null(), null(), null(), & - null(), null() ) + extraterrestrial_flux_profile => & + profiles%get( extraterrestrial_flux_label, extraterrestrial_flux_unit, error ) + if (has_error_occurred( error, errmsg, errcode )) then + deallocate( tuvx ) + call reset_tuvx_map_state( grids, profiles, null() ) + call cleanup_tuvx_resources() + return + end if + call reset_tuvx_map_state( grids, profiles, null() ) + + ! 'photolysis_rate_constants_ordering' is a local variable photolysis_rate_constants_ordering => & tuvx%get_photolysis_rate_constants_ordering( error ) - if (has_error_occurred( error, errmsg, errcode )) return + if (has_error_occurred( error, errmsg, errcode )) then + deallocate( tuvx ) + return + end if number_of_photolysis_rate_constants = photolysis_rate_constants_ordering%size() call config%load_from_file( trim(filename_of_tuvx_micm_mapping_configuration), error ) if (has_error_occurred( error, errmsg, errcode )) then + deallocate( tuvx ) deallocate( photolysis_rate_constants_ordering ) - photolysis_rate_constants_ordering => null() return end if photolysis_rate_constants_mapping => & index_mappings_t( config, photolysis_rate_constants_ordering, & micm_rate_parameter_ordering, error ) + if (has_error_occurred( error, errmsg, errcode )) then + deallocate( tuvx ) + deallocate( photolysis_rate_constants_ordering ) + return + end if + deallocate( photolysis_rate_constants_ordering ) - photolysis_rate_constants_ordering => null() - if (has_error_occurred( error, errmsg, errcode )) return end subroutine tuvx_init !> Calculates photolysis rate constants for the current model conditions - subroutine tuvx_run(temperature, dry_air_density, & - geopotential_height_wrt_surface_at_midpoint, & - geopotential_height_wrt_surface_at_interface, & - surface_temperature, surface_geopotential, & - surface_albedo, & - standard_gravitational_acceleration, & + subroutine tuvx_run(temperature, dry_air_density, & + geopotential_height_wrt_surface_at_midpoint, & + geopotential_height_wrt_surface_at_interface, & + surface_geopotential, surface_temperature, & + surface_albedo, & + number_of_photolysis_wavelength_grid_sections, & + photolysis_wavelength_grid_interfaces, & + extraterrestrial_flux, & + standard_gravitational_acceleration, & rate_parameters, errmsg, errcode) - use musica_util, only: error_t - use musica_ccpp_tuvx_height_grid, only: set_height_grid_values, calculate_heights - use musica_ccpp_tuvx_temperature, only: set_temperature_values - use musica_ccpp_util, only: has_error_occurred - use musica_ccpp_tuvx_surface_albedo, only: set_surface_albedo_values + use musica_util, only: error_t + use musica_ccpp_tuvx_height_grid, only: set_height_grid_values, calculate_heights + use musica_ccpp_tuvx_temperature, only: set_temperature_values + use musica_ccpp_util, only: has_error_occurred + use musica_ccpp_tuvx_surface_albedo, only: set_surface_albedo_values + use musica_ccpp_tuvx_extraterrestrial_flux, only: set_extraterrestrial_flux_values real(kind_phys), intent(in) :: temperature(:,:) ! K (column, layer) real(kind_phys), intent(in) :: dry_air_density(:,:) ! kg m-3 (column, layer) real(kind_phys), intent(in) :: geopotential_height_wrt_surface_at_midpoint(:,:) ! m (column, layer) real(kind_phys), intent(in) :: geopotential_height_wrt_surface_at_interface(:,:) ! m (column, interface) - real(kind_phys), intent(in) :: surface_temperature(:) ! K real(kind_phys), intent(in) :: surface_geopotential(:) ! m2 s-2 + real(kind_phys), intent(in) :: surface_temperature(:) ! K real(kind_phys), intent(in) :: surface_albedo ! unitless + integer, intent(in) :: number_of_photolysis_wavelength_grid_sections ! (count) + real(kind_phys), intent(in) :: photolysis_wavelength_grid_interfaces(:) ! nm + real(kind_phys), intent(in) :: extraterrestrial_flux(:) ! photons cm-2 s-1 nm-1 real(kind_phys), intent(in) :: standard_gravitational_acceleration ! m s-2 real(kind_phys), intent(inout) :: rate_parameters(:,:,:) ! various units (column, layer, reaction) character(len=512), intent(out) :: errmsg @@ -234,10 +329,10 @@ subroutine tuvx_run(temperature, dry_air_density, & ! local variables real(kind_phys), dimension(size(geopotential_height_wrt_surface_at_midpoint, dim = 2)) :: height_midpoints real(kind_phys), dimension(size(geopotential_height_wrt_surface_at_interface, dim = 2)) :: height_interfaces - real(kind_phys) :: reciprocal_of_gravitational_acceleration ! s2 m-1 real(kind_phys), dimension(size(rate_parameters, dim=2)+2, & number_of_photolysis_rate_constants) :: photolysis_rate_constants, & ! s-1 heating_rates ! K s-1 (TODO: check units) + real(kind_phys) :: reciprocal_of_gravitational_acceleration ! s2 m-1 real(kind_phys) :: solar_zenith_angle ! degrees real(kind_phys) :: earth_sun_distance ! AU type(error_t) :: error @@ -249,6 +344,12 @@ subroutine tuvx_run(temperature, dry_air_density, & call set_surface_albedo_values( surface_albedo_profile, surface_albedo, errmsg, errcode ) if (errcode /= 0) return + call set_extraterrestrial_flux_values( extraterrestrial_flux_profile, & + number_of_photolysis_wavelength_grid_sections, & + photolysis_wavelength_grid_interfaces, & + extraterrestrial_flux, errmsg, errcode ) + if (errcode /= 0) return + do i_col = 1, size(temperature, dim=1) call calculate_heights( geopotential_height_wrt_surface_at_midpoint(i_col,:), & geopotential_height_wrt_surface_at_interface(i_col,:), & @@ -295,35 +396,12 @@ subroutine tuvx_final(errmsg, errcode) errmsg = '' errcode = 0 - if (associated( height_grid )) then - deallocate( height_grid ) - height_grid => null() - end if - - if (associated( wavelength_grid )) then - deallocate( wavelength_grid ) - wavelength_grid => null() - end if - - if (associated( temperature_profile )) then - deallocate( temperature_profile ) - temperature_profile => null() - end if - - if (associated( surface_albedo_profile )) then - deallocate( surface_albedo_profile ) - surface_albedo_profile => null() - end if - if (associated( tuvx )) then deallocate( tuvx ) tuvx => null() end if - if (associated( photolysis_rate_constants_mapping )) then - deallocate( photolysis_rate_constants_mapping ) - photolysis_rate_constants_mapping => null() - end if + call cleanup_tuvx_resources() end subroutine tuvx_final diff --git a/schemes/musica/tuvx/musica_ccpp_tuvx_extraterrestrial_flux.F90 b/schemes/musica/tuvx/musica_ccpp_tuvx_extraterrestrial_flux.F90 new file mode 100644 index 00000000..c6cfddad --- /dev/null +++ b/schemes/musica/tuvx/musica_ccpp_tuvx_extraterrestrial_flux.F90 @@ -0,0 +1,111 @@ +module musica_ccpp_tuvx_extraterrestrial_flux + use ccpp_kinds, only: kind_phys + + implicit none + + private + public :: create_extraterrestrial_flux_profile, set_extraterrestrial_flux_values + + !> Label for extraterrestrial_flux in TUV-x + character(len=*), parameter, public :: extraterrestrial_flux_label = "extraterrestrial flux" + !> Unit for extraterrestrial_flux in TUV-x + character(len=*), parameter, public :: extraterrestrial_flux_unit = "photon cm-2 s-1" + !> Wavelength grid interface values + real(kind_phys), protected, allocatable :: wavelength_grid_interfaces_(:) ! nm + !> Default value of number of wavelength grid bins + integer, parameter :: DEFAULT_NUM_WAVELENGTH_BINS = 0 + !> Number of wavelength grid bins + integer, protected :: num_wavelength_bins_ = DEFAULT_NUM_WAVELENGTH_BINS + +contains + + !> Creates a TUV-x extraterrestrial flux profile from the host-model wavelength grid + function create_extraterrestrial_flux_profile(wavelength_grid, & + wavelength_grid_interfaces, errmsg, errcode) result( profile ) + use musica_util, only: error_t + use musica_ccpp_util, only: has_error_occurred + use musica_ccpp_tuvx_wavelength_grid, only: m_to_nm + use musica_tuvx_grid, only: grid_t + use musica_tuvx_profile, only: profile_t + + type(grid_t), intent(inout) :: wavelength_grid + real(kind_phys), intent(in) :: wavelength_grid_interfaces(:) ! m + character(len=*), intent(out) :: errmsg + integer, intent(out) :: errcode + type(profile_t), pointer :: profile + + ! local variables + type(error_t) :: error + + profile => profile_t( extraterrestrial_flux_label, extraterrestrial_flux_unit, & + wavelength_grid, error ) + if ( has_error_occurred( error, errmsg, errcode ) ) return + + num_wavelength_bins_ = wavelength_grid%number_of_sections( error ) + if ( has_error_occurred( error, errmsg, errcode ) ) return + + allocate(wavelength_grid_interfaces_( size( wavelength_grid_interfaces ) )) + + wavelength_grid_interfaces_(:) = wavelength_grid_interfaces(:) * m_to_nm + + end function create_extraterrestrial_flux_profile + + !> Sets TUV-x extraterrestrial flux midpoints + ! + ! Extraterrestrial flux is read from data files and interpolated to the + ! TUV-x wavelength grid. CAM extraterrestrial flux values are multiplied by the + ! width of the wavelength bins to get the TUV-x units of photon cm-2 s-1 + ! + ! TUV-x only uses mid-point values for extraterrestrial flux + subroutine set_extraterrestrial_flux_values(profile, num_photolysis_wavelength_grid_sections, & + photolysis_wavelength_grid_interfaces, extraterrestrial_flux, errmsg, errcode) + use musica_ccpp_util, only: has_error_occurred + use musica_tuvx_profile, only: profile_t + use musica_util, only: error_t + use ccpp_kinds, only: kind_phys + use ccpp_tuvx_utils, only: rebin + + type(profile_t), intent(inout) :: profile + integer, intent(in) :: num_photolysis_wavelength_grid_sections ! (count) + real(kind_phys), intent(in) :: photolysis_wavelength_grid_interfaces(:) ! nm + real(kind_phys), intent(in) :: extraterrestrial_flux(:) ! photons cm-2 s-1 nm-1 + character(len=*), intent(out) :: errmsg + integer, intent(out) :: errcode + + ! local variables + type(error_t) :: error + real(kind_phys) :: midpoints(num_wavelength_bins_) + + if (.not. allocated(wavelength_grid_interfaces_)) then + errmsg = "[MUSICA Error] Failed to allocate the TUV-x wavelength grid interface array" + errcode = 1 + return + end if + + if (num_wavelength_bins_ <= DEFAULT_NUM_WAVELENGTH_BINS) then + errmsg = "[MUSICA Error] Invalid size of TUV-x wavelength bins." + errcode = 1 + deallocate( wavelength_grid_interfaces_ ) + return + end if + + ! Regrid normalized flux to TUV-x wavelength grid + call rebin( num_photolysis_wavelength_grid_sections, num_wavelength_bins_, & + photolysis_wavelength_grid_interfaces, wavelength_grid_interfaces_, & + extraterrestrial_flux, midpoints ) + + ! Convert normalized flux to flux on TUV-x wavelength grid + midpoints = midpoints * ( wavelength_grid_interfaces_(2 : num_wavelength_bins_ + 1) & + - wavelength_grid_interfaces_(1 :num_wavelength_bins_) ) + + call profile%set_midpoint_values( midpoints, error) + if ( has_error_occurred( error, errmsg, errcode ) ) then + deallocate( wavelength_grid_interfaces_ ) + return + end if + + deallocate( wavelength_grid_interfaces_ ) + + end subroutine set_extraterrestrial_flux_values + +end module musica_ccpp_tuvx_extraterrestrial_flux \ No newline at end of file diff --git a/schemes/musica/tuvx/musica_ccpp_tuvx_surface_albedo.F90 b/schemes/musica/tuvx/musica_ccpp_tuvx_surface_albedo.F90 index 751d18c6..d2b119b4 100644 --- a/schemes/musica/tuvx/musica_ccpp_tuvx_surface_albedo.F90 +++ b/schemes/musica/tuvx/musica_ccpp_tuvx_surface_albedo.F90 @@ -2,17 +2,16 @@ module musica_ccpp_tuvx_surface_albedo implicit none private - public :: create_surface_albedo_profile, set_surface_albedo_values, & - surface_albedo_label, surface_albedo_unit + public :: create_surface_albedo_profile, set_surface_albedo_values !> Label for surface albedo in TUV-x - character(len=*), parameter :: surface_albedo_label = "surface albedo" + character(len=*), parameter, public :: surface_albedo_label = "surface albedo" !> Unit for surface albedo in TUV-x - character(len=*), parameter :: surface_albedo_unit = "none" + character(len=*), parameter, public :: surface_albedo_unit = "none" !> Default value of number of wavelength bins integer, parameter :: DEFAULT_NUM_WAVELENGTH_BINS = 0 !> Number of wavelength bins - integer, protected :: num_wavelength_bins = DEFAULT_NUM_WAVELENGTH_BINS + integer, protected :: num_wavelength_bins_ = DEFAULT_NUM_WAVELENGTH_BINS contains @@ -32,13 +31,13 @@ function create_surface_albedo_profile( wavelength_grid, errmsg, errcode ) & ! local variables type(error_t) :: error - num_wavelength_bins = wavelength_grid%number_of_sections( error ) - if ( has_error_occurred( error, errmsg, errcode ) ) return - profile => profile_t( surface_albedo_label, surface_albedo_unit, & wavelength_grid, error ) if ( has_error_occurred( error, errmsg, errcode ) ) return + num_wavelength_bins_ = wavelength_grid%number_of_sections( error ) + if ( has_error_occurred( error, errmsg, errcode ) ) return + end function create_surface_albedo_profile !> Sets TUV-x surface albedo values @@ -58,10 +57,10 @@ subroutine set_surface_albedo_values( profile, host_surface_albedo, & ! local variables type(error_t) :: error - real(kind_phys) :: surface_albedo_interfaces(num_wavelength_bins + 1) + real(kind_phys) :: surface_albedo_interfaces(num_wavelength_bins_ + 1) - if (size(surface_albedo_interfaces) <= DEFAULT_NUM_WAVELENGTH_BINS + 1) then - errmsg = "[MUSICA Error] Invalid size of TUV-x wavelength interfaces." + if (num_wavelength_bins_ <= DEFAULT_NUM_WAVELENGTH_BINS) then + errmsg = "[MUSICA Error] Invalid size of TUV-x wavelength bins." errcode = 1 return end if diff --git a/schemes/musica/tuvx/musica_ccpp_tuvx_temperature.F90 b/schemes/musica/tuvx/musica_ccpp_tuvx_temperature.F90 index c8ac9cc7..7e9961b7 100644 --- a/schemes/musica/tuvx/musica_ccpp_tuvx_temperature.F90 +++ b/schemes/musica/tuvx/musica_ccpp_tuvx_temperature.F90 @@ -2,13 +2,12 @@ module musica_ccpp_tuvx_temperature implicit none private - public :: create_temperature_profile, set_temperature_values, & - temperature_label, temperature_unit + public :: create_temperature_profile, set_temperature_values !> Label for temperature in TUV-x - character(len=*), parameter :: temperature_label = "temperature" + character(len=*), parameter, public :: temperature_label = "temperature" !> Unit for temperature in TUV-x - character(len=*), parameter :: temperature_unit = "K" + character(len=*), parameter, public :: temperature_unit = "K" contains diff --git a/schemes/musica/tuvx/musica_ccpp_tuvx_util.F90 b/schemes/musica/tuvx/musica_ccpp_tuvx_util.F90 deleted file mode 100644 index 25ac1a28..00000000 --- a/schemes/musica/tuvx/musica_ccpp_tuvx_util.F90 +++ /dev/null @@ -1,55 +0,0 @@ -module musica_ccpp_tuvx_util - implicit none - - private - public :: tuvx_deallocate - -contains - - !> This is a helper subroutine created to deallocate objects associated with TUV-x - subroutine tuvx_deallocate(grids, profiles, radiators, tuvx, height_grid, & - wavelength_grid, temperature_profile, surface_albedo_profile) - use musica_tuvx, only: tuvx_t, grid_map_t, profile_map_t, radiator_map_t, & - grid_t, profile_t - - type(grid_map_t), pointer :: grids - type(profile_map_t), pointer :: profiles - type(radiator_map_t), pointer :: radiators - type(tuvx_t), pointer :: tuvx - type(grid_t), pointer :: height_grid - type(grid_t), pointer :: wavelength_grid - type(profile_t), pointer :: temperature_profile - type(profile_t), pointer :: surface_albedo_profile - - if (associated( grids )) deallocate( grids ) - if (associated( profiles )) deallocate( profiles ) - if (associated( radiators )) deallocate( radiators ) - - if (associated( tuvx )) then - deallocate( tuvx ) - tuvx => null() - end if - - if (associated( height_grid )) then - deallocate( height_grid ) - height_grid => null() - end if - - if (associated( wavelength_grid )) then - deallocate( wavelength_grid ) - wavelength_grid => null() - end if - - if (associated( temperature_profile )) then - deallocate( temperature_profile ) - temperature_profile => null() - end if - - if (associated( surface_albedo_profile )) then - deallocate( surface_albedo_profile ) - surface_albedo_profile => null() - end if - - end subroutine tuvx_deallocate - -end module musica_ccpp_tuvx_util \ No newline at end of file diff --git a/schemes/musica/tuvx/musica_ccpp_tuvx_wavelength_grid.F90 b/schemes/musica/tuvx/musica_ccpp_tuvx_wavelength_grid.F90 index 96528d5d..20e34f5c 100644 --- a/schemes/musica/tuvx/musica_ccpp_tuvx_wavelength_grid.F90 +++ b/schemes/musica/tuvx/musica_ccpp_tuvx_wavelength_grid.F90 @@ -1,4 +1,5 @@ module musica_ccpp_tuvx_wavelength_grid + use ccpp_kinds, only: kind_phys implicit none @@ -20,6 +21,8 @@ module musica_ccpp_tuvx_wavelength_grid character(len=*), parameter, public :: wavelength_grid_label = "wavelength" !> Unit for wavelength grid in TUV-x character(len=*), parameter, public :: wavelength_grid_unit = "nm" + !> Conversion factor from meters to nanometers (CAM-SIMA -> TUV-x) + real(kind_phys), parameter, public :: m_to_nm = 1.0e9 contains @@ -42,7 +45,7 @@ function create_wavelength_grid( wavelength_grid_interfaces, errmsg, errcode ) & reaL(kind_phys) :: midpoints( size( wavelength_grid_interfaces ) - 1 ) ! nm type(error_t) :: error - interfaces(:) = wavelength_grid_interfaces(:) * 1.0e9 + interfaces(:) = wavelength_grid_interfaces(:) * m_to_nm midpoints(:) = & 0.5 * ( interfaces( 1: size( interfaces ) - 1 ) & + interfaces( 2: size( interfaces ) ) ) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6a7d1e30..9ac2d8c0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -10,13 +10,13 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH};${CMAKE_CURRENT_LIST_DIR}/cmake) set(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_MODULE_PATH}/SetDefaults.cmake) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -# -------------------------------------------------------------------------------- -# NOTE: If 'CCPP_ENABLE_MUSICA_TESTS' on, this is not a stand-alone cmake project anymore. -# MUSICA CCPP wrapper needs MUSICA library and ccpp-framework/src. -# To 'CCPP_ENABLE_MUSICA_TESTS', you either build a cmake project through -# 'docker/Dockerfile.musica' or follow the build instructions in the file. -# The following '$ENV' variables are set by the docker file. -# -------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------------------- +# NOTE: If 'CCPP_ENABLE_MUSICA_TESTS' is enabled, this is no longer a stand-alone CMake project. +# The MUSICA CCPP wrapper requires both the MUSICA library and ccpp-framework/src. +# To enable 'CCPP_ENABLE_MUSICA_TESTS', you can either build a CMake project using +# 'docker/Dockerfile.musica' or follow the build instructions outlined in that file. +# The following '$ENV' variables are configured by the Dockerfile. +# --------------------------------------------------------------------------------------------- option(CCPP_ENABLE_MUSICA_TESTS "Build the MUSICA tests" OFF) option(CCPP_ENABLE_MEMCHECK "Enable memory checks in tests" OFF) @@ -24,12 +24,14 @@ set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) if (CCPP_ENABLE_MUSICA_TESTS) - set(MUSICA_VERSION $ENV{MUSICA_VERSION}) set(MUSICA_SRC_PATH ${CMAKE_SOURCE_DIR}/../schemes/musica) + set(TO_BE_CCPPIZED_SRC_PATH ${CMAKE_SOURCE_DIR}/../to_be_ccppized) set(CCPP_SRC_PATH ${CMAKE_SOURCE_DIR}/$ENV{CCPP_SRC_PATH}) set(CCPP_TEST_SRC_PATH ${CMAKE_SOURCE_DIR}/include) - add_subdirectory(musica) - + include(TestUtils) + include(CTest) enable_testing() + + add_subdirectory(musica) endif() diff --git a/test/docker/Dockerfile.musica b/test/docker/Dockerfile.musica index 83dea485..e98255f7 100644 --- a/test/docker/Dockerfile.musica +++ b/test/docker/Dockerfile.musica @@ -6,10 +6,12 @@ FROM ubuntu:22.04 ARG MUSICA_GIT_TAG=326b5119768d5be9654baf96ae3bd6a1b757fdc8 +ARG CAM_SIMA_CHEMISTRY_DATA_TAG=abc7cacbec3d33d5c0ed5bb79a157e93b42c45c0 +ARG BUILD_TYPE=Debug RUN apt update \ && apt install -y sudo \ - && adduser test_user \ + && useradd -m test_user \ && echo "test_user ALL=(root) NOPASSWD: ALL" >> /etc/sudoers.d/test_user \ && chmod 0440 /etc/sudoers.d/test_user @@ -34,7 +36,6 @@ RUN sudo apt update \ libopenmpi-dev \ m4 \ make \ - nlohmann-json3-dev \ openmpi-bin \ python3 \ tree \ @@ -43,25 +44,22 @@ RUN sudo apt update \ zlib1g-dev \ && sudo apt clean -ENV PATH="${PATH}:/usr/lib/openmpi/bin" - ENV FC=mpif90 ENV FFLAGS="-I/usr/include/" # Install MUSICA (MUSICA-C) -RUN git clone https://github.com/NCAR/musica.git - -RUN cd musica \ - && git fetch \ +RUN git clone https://github.com/NCAR/musica.git \ + && cd musica \ && git checkout ${MUSICA_GIT_TAG} \ - && cmake \ - -S . \ - -B build \ - -D CMAKE_BUILD_TYPE=Release \ - -D MUSICA_ENABLE_TESTS=OFF \ - -D MUSICA_BUILD_FORTRAN_INTERFACE=OFF \ - -D MUSICA_ENABLE_MICM=ON \ - -D MUSICA_ENABLE_TUVX=ON \ + && cmake -S . -B build \ + -D CMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -D MUSICA_ENABLE_TESTS=OFF \ + -D MUSICA_BUILD_FORTRAN_INTERFACE=OFF \ + -D MUSICA_ENABLE_MICM=ON \ + -D MUSICA_ENABLE_TUVX=ON \ + -D CMAKE_Fortran_COMPILER=mpif90 \ + -D CMAKE_C_COMPILER=mpicc \ + -D CMAKE_CXX_COMPILER=mpicxx \ && cd build \ && sudo make install @@ -71,7 +69,7 @@ RUN sudo chown -R test_user:test_user atmospheric_physics # Clone the MUSICA chemistry data set repository RUN git clone https://github.com/NCAR/cam-sima-chemistry-data.git \ && cd cam-sima-chemistry-data \ - && git checkout 144d982715f5bd6fa61e76f255a52db1843c55f2 \ + && git checkout ${CAM_SIMA_CHEMISTRY_DATA_TAG} \ && mv mechanisms /home/test_user/atmospheric_physics/schemes/musica/configurations # Must make ccpp-framework available before building test @@ -83,9 +81,8 @@ ENV CCPP_SRC_PATH="lib/ccpp-framework/src" ENV CCPP_FORTRAN_TOOLS_PATH="lib/ccpp-framework/scripts/fortran_tools" RUN cd atmospheric_physics/test \ - && cmake -S . \ - -B build \ - -D CMAKE_BUILD_TYPE=Debug \ + && cmake -S . -B build \ + -D CMAKE_BUILD_TYPE={BUILD_TYPE} \ -D CCPP_ENABLE_MUSICA_TESTS=ON \ -D CCPP_ENABLE_MEMCHECK=ON \ && cmake --build ./build diff --git a/test/docker/Dockerfile.musica.no_install b/test/docker/Dockerfile.musica.no_install index e8f70fb0..cb4edf56 100644 --- a/test/docker/Dockerfile.musica.no_install +++ b/test/docker/Dockerfile.musica.no_install @@ -9,10 +9,12 @@ FROM ubuntu:22.04 ARG MUSICA_GIT_TAG=326b5119768d5be9654baf96ae3bd6a1b757fdc8 +ARG CAM_SIMA_CHEMISTRY_DATA_TAG=abc7cacbec3d33d5c0ed5bb79a157e93b42c45c0 +ARG BUILD_TYPE=Debug RUN apt update \ && apt install -y sudo \ - && adduser test_user \ + && useradd -m test_user \ && echo "test_user ALL=(root) NOPASSWD: ALL" >> /etc/sudoers.d/test_user \ && chmod 0440 /etc/sudoers.d/test_user @@ -37,7 +39,6 @@ RUN sudo apt update \ libopenmpi-dev \ m4 \ make \ - nlohmann-json3-dev \ openmpi-bin \ python3 \ tree \ @@ -46,8 +47,6 @@ RUN sudo apt update \ zlib1g-dev \ && sudo apt clean -ENV PATH="${PATH}:/usr/lib/openmpi/bin" - ENV FC=mpif90 ENV FFLAGS="-I/usr/include/" ENV MUSICA_GIT_TAG=${MUSICA_GIT_TAG} @@ -58,7 +57,7 @@ RUN sudo chown -R test_user:test_user atmospheric_physics # Clone the MUSICA chemistry data set repository RUN git clone https://github.com/NCAR/cam-sima-chemistry-data.git \ && cd cam-sima-chemistry-data \ - && git checkout 144d982715f5bd6fa61e76f255a52db1843c55f2 \ + && git checkout ${CAM_SIMA_CHEMISTRY_DATA_TAG} \ && mv mechanisms /home/test_user/atmospheric_physics/schemes/musica/configurations # Must make ccpp-framework available before building test @@ -70,9 +69,8 @@ ENV CCPP_SRC_PATH="lib/ccpp-framework/src" ENV CCPP_FORTRAN_TOOLS_PATH="lib/ccpp-framework/scripts/fortran_tools" RUN cd atmospheric_physics/test \ - && cmake -S . \ - -B build \ - -D CMAKE_BUILD_TYPE=Debug \ + && cmake -S . -B build \ + -D CMAKE_BUILD_TYPE=${BUILD_TYPE} \ -D CCPP_ENABLE_MUSICA_TESTS=ON \ -D CCPP_ENABLE_MEMCHECK=ON \ && cmake --build ./build diff --git a/test/musica/CMakeLists.txt b/test/musica/CMakeLists.txt index 74b29693..7cdba304 100644 --- a/test/musica/CMakeLists.txt +++ b/test/musica/CMakeLists.txt @@ -1,5 +1,4 @@ include(FetchContent) -include(TestUtils) FetchContent_Declare(musica GIT_REPOSITORY https://github.com/NCAR/musica.git @@ -29,6 +28,7 @@ file(GLOB MUSICA_CCPP_SOURCES target_sources(test_musica_api PUBLIC ${MUSICA_CCPP_SOURCES} + ${TO_BE_CCPPIZED_SRC_PATH}/ccpp_tuvx_utils.F90 ${CCPP_SRC_PATH}/ccpp_constituent_prop_mod.F90 ${CCPP_SRC_PATH}/ccpp_hash_table.F90 ${CCPP_SRC_PATH}/ccpp_hashable.F90 @@ -46,8 +46,6 @@ set_target_properties(test_musica_api LINKER_LANGUAGE Fortran ) -include(CTest) - add_test( NAME test_musica_api COMMAND $ diff --git a/test/musica/test_musica_api.F90 b/test/musica/test_musica_api.F90 index 61cca2f7..cc7272b9 100644 --- a/test/musica/test_musica_api.F90 +++ b/test/musica/test_musica_api.F90 @@ -144,40 +144,43 @@ subroutine test_chapman() implicit none - integer, parameter :: NUM_SPECIES = 5 + integer, parameter :: NUM_SPECIES = 5 ! This test requires that the number of grid cells = 4, which is the default ! vector dimension for MICM. This restriction will be removed once ! https://github.com/NCAR/musica/issues/217 is finished. - integer, parameter :: NUM_COLUMNS = 2 - integer, parameter :: NUM_LAYERS = 2 - integer, parameter :: NUM_WAVELENGTH_BINS = 102 - integer :: NUM_GRID_CELLS = NUM_COLUMNS * NUM_LAYERS - integer :: solver_type = Rosenbrock - integer :: errcode - character(len=512) :: errmsg - real(kind_phys) :: time_step = 60._kind_phys ! s - real(kind_phys), dimension(NUM_WAVELENGTH_BINS+1) :: photolysis_wavelength_grid_interfaces ! m - real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: geopotential_height_wrt_surface_at_midpoint ! m - real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS+1) :: geopotential_height_wrt_surface_at_interface ! m - real(kind_phys), dimension(NUM_COLUMNS) :: surface_temperature ! K - real(kind_phys), dimension(NUM_COLUMNS) :: surface_geopotential ! m2 s-2 - real(kind_phys) :: surface_albedo ! unitless - real(kind_phys) :: standard_gravitational_acceleration ! s2 m-1 - real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: temperature ! K - real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: pressure ! Pa - real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: dry_air_density ! kg m-3 - real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS,NUM_SPECIES) :: constituents ! kg kg-1 - real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS,NUM_SPECIES) :: initial_constituents ! kg kg-1 - type(ccpp_constituent_prop_ptr_t), allocatable :: constituent_props_ptr(:) - type(ccpp_constituent_properties_t), allocatable, target :: constituent_props(:) - type(ccpp_constituent_properties_t), pointer :: const_prop - real(kind_phys) :: molar_mass, base_conc - character(len=512) :: species_name, units - character(len=:), allocatable :: micm_species_name - logical :: tmp_bool, is_advected - integer :: i, j, k - integer :: N2_index, O2_index, O_index, O1D_index, O3_index - real(kind_phys) :: total_O, total_O_init + integer, parameter :: NUM_COLUMNS = 2 + integer, parameter :: NUM_LAYERS = 2 + integer, parameter :: NUM_WAVELENGTH_BINS = 102 + integer :: NUM_GRID_CELLS = NUM_COLUMNS * NUM_LAYERS + integer :: solver_type = Rosenbrock + integer :: errcode + character(len=512) :: errmsg + real(kind_phys) :: time_step = 60._kind_phys ! s + real(kind_phys), dimension(NUM_WAVELENGTH_BINS+1) :: photolysis_wavelength_grid_interfaces ! m + real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: geopotential_height_wrt_surface_at_midpoint ! m + real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS+1) :: geopotential_height_wrt_surface_at_interface ! m + real(kind_phys), dimension(NUM_COLUMNS) :: surface_geopotential ! m2 s-2 + real(kind_phys), dimension(NUM_COLUMNS) :: surface_temperature ! K + real(kind_phys) :: surface_albedo ! unitless + integer, parameter :: num_photolysis_wavelength_grid_sections = 8 ! (count) + real(kind_phys), dimension(num_photolysis_wavelength_grid_sections+1) :: flux_data_photolysis_wavelength_interfaces ! nm + real(kind_phys), dimension(num_photolysis_wavelength_grid_sections) :: extraterrestrial_flux ! photons cm-2 s-1 nm-1 + real(kind_phys) :: standard_gravitational_acceleration ! s2 m-1 + real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: temperature ! K + real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: pressure ! Pa + real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: dry_air_density ! kg m-3 + real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS,NUM_SPECIES) :: constituents ! kg kg-1 + real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS,NUM_SPECIES) :: initial_constituents ! kg kg-1 + type(ccpp_constituent_prop_ptr_t), allocatable :: constituent_props_ptr(:) + type(ccpp_constituent_properties_t), allocatable, target :: constituent_props(:) + type(ccpp_constituent_properties_t), pointer :: const_prop + real(kind_phys) :: molar_mass, base_conc + character(len=512) :: species_name, units + character(len=:), allocatable :: micm_species_name + logical :: tmp_bool, is_advected + integer :: i, j, k + integer :: N2_index, O2_index, O_index, O1D_index, O3_index + real(kind_phys) :: total_O, total_O_init call get_wavelength_edges(photolysis_wavelength_grid_interfaces) solver_type = Rosenbrock @@ -196,6 +199,12 @@ subroutine test_chapman() pressure(:,2) = (/ 8000.04_kind_phys, 9000.04_kind_phys /) dry_air_density(:,1) = (/ 3.5_kind_phys, 4.5_kind_phys /) dry_air_density(:,2) = (/ 5.5_kind_phys, 6.5_kind_phys /) + flux_data_photolysis_wavelength_interfaces(:) = & + (/ 200.0_kind_phys, 210.0_kind_phys, 220.0_kind_phys, 230.0_kind_phys, & + 240.0_kind_phys, 250.0_kind_phys, 260.0_kind_phys, 270.0_kind_phys, 280.0_kind_phys /) + extraterrestrial_flux(:) = & + (/ 1.5e13_kind_phys, 1.5e13_kind_phys, 1.4e13_kind_phys, 1.4e13_kind_phys, & + 1.3e13_kind_phys, 1.2e13_kind_phys, 1.1e13_kind_phys, 1.0e13_kind_phys /) filename_of_micm_configuration = 'musica_configurations/chapman/micm/config.json' filename_of_tuvx_configuration = 'musica_configurations/chapman/tuvx/config.json' @@ -286,11 +295,12 @@ subroutine test_chapman() write(*,*) "[MUSICA INFO] Initial Concentrations" write(*,fmt="(4(3x,e13.6))") constituents - call musica_ccpp_run(time_step, temperature, pressure, dry_air_density, constituent_props_ptr, & - constituents, geopotential_height_wrt_surface_at_midpoint, & - geopotential_height_wrt_surface_at_interface, surface_temperature, & - surface_geopotential, surface_albedo, standard_gravitational_acceleration, & - errmsg, errcode) + call musica_ccpp_run( time_step, temperature, pressure, dry_air_density, constituent_props_ptr, & + constituents, geopotential_height_wrt_surface_at_midpoint, & + geopotential_height_wrt_surface_at_interface, surface_geopotential, & + surface_temperature, surface_albedo, num_photolysis_wavelength_grid_sections, & + flux_data_photolysis_wavelength_interfaces, extraterrestrial_flux, & + standard_gravitational_acceleration, errmsg, errcode ) if (errcode /= 0) then write(*,*) trim(errmsg) stop 3 @@ -343,40 +353,43 @@ subroutine test_terminator() implicit none - integer, parameter :: NUM_SPECIES = 2 + integer, parameter :: NUM_SPECIES = 2 ! This test requires that the number of grid cells = 4, which is the default ! vector dimension for MICM. This restriction will be removed once ! https://github.com/NCAR/musica/issues/217 is finished. - integer, parameter :: NUM_COLUMNS = 2 - integer, parameter :: NUM_LAYERS = 2 - integer, parameter :: NUM_WAVELENGTH_BINS = 102 - integer :: NUM_GRID_CELLS = NUM_COLUMNS * NUM_LAYERS - integer :: solver_type = Rosenbrock - integer :: errcode - character(len=512) :: errmsg - real(kind_phys) :: time_step = 60._kind_phys ! s - real(kind_phys), dimension(NUM_WAVELENGTH_BINS+1) :: photolysis_wavelength_grid_interfaces ! m - real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: geopotential_height_wrt_surface_at_midpoint ! m - real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS+1) :: geopotential_height_wrt_surface_at_interface ! m - real(kind_phys), dimension(NUM_COLUMNS) :: surface_temperature ! K - real(kind_phys), dimension(NUM_COLUMNS) :: surface_geopotential ! m2 s-2 - real(kind_phys) :: surface_albedo ! unitless - real(kind_phys) :: standard_gravitational_acceleration ! s2 m-1 - real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: temperature ! K - real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: pressure ! Pa - real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: dry_air_density ! kg m-3 - real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS,NUM_SPECIES) :: constituents ! kg kg-1 - real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS,NUM_SPECIES) :: initial_constituents ! kg kg-1 - type(ccpp_constituent_prop_ptr_t), allocatable :: constituent_props_ptr(:) - type(ccpp_constituent_properties_t), allocatable, target :: constituent_props(:) - type(ccpp_constituent_properties_t), pointer :: const_prop - real(kind_phys) :: molar_mass, base_conc - character(len=512) :: species_name, units - character(len=:), allocatable :: micm_species_name - logical :: tmp_bool, is_advected - integer :: i, j, k - integer :: Cl_index, Cl2_index - real(kind_phys) :: total_Cl, total_Cl_init + integer, parameter :: NUM_COLUMNS = 2 + integer, parameter :: NUM_LAYERS = 2 + integer, parameter :: NUM_WAVELENGTH_BINS = 102 + integer :: NUM_GRID_CELLS = NUM_COLUMNS * NUM_LAYERS + integer :: solver_type = Rosenbrock + integer :: errcode + character(len=512) :: errmsg + real(kind_phys) :: time_step = 60._kind_phys ! s + real(kind_phys), dimension(NUM_WAVELENGTH_BINS+1) :: photolysis_wavelength_grid_interfaces ! m + real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: geopotential_height_wrt_surface_at_midpoint ! m + real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS+1) :: geopotential_height_wrt_surface_at_interface ! m + real(kind_phys), dimension(NUM_COLUMNS) :: surface_geopotential ! m2 s-2 + real(kind_phys), dimension(NUM_COLUMNS) :: surface_temperature ! K + real(kind_phys) :: surface_albedo ! unitless + integer, parameter :: num_photolysis_wavelength_grid_sections = 8 ! (count) + real(kind_phys), dimension(num_photolysis_wavelength_grid_sections+1) :: flux_data_photolysis_wavelength_interfaces ! nm + real(kind_phys), dimension(num_photolysis_wavelength_grid_sections) :: extraterrestrial_flux ! photons cm-2 s-1 nm-1 + real(kind_phys) :: standard_gravitational_acceleration ! s2 m-1 + real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: temperature ! K + real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: pressure ! Pa + real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS) :: dry_air_density ! kg m-3 + real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS,NUM_SPECIES) :: constituents ! kg kg-1 + real(kind_phys), dimension(NUM_COLUMNS,NUM_LAYERS,NUM_SPECIES) :: initial_constituents ! kg kg-1 + type(ccpp_constituent_prop_ptr_t), allocatable :: constituent_props_ptr(:) + type(ccpp_constituent_properties_t), allocatable, target :: constituent_props(:) + type(ccpp_constituent_properties_t), pointer :: const_prop + real(kind_phys) :: molar_mass, base_conc + character(len=512) :: species_name, units + character(len=:), allocatable :: micm_species_name + logical :: tmp_bool, is_advected + integer :: i, j, k + integer :: Cl_index, Cl2_index + real(kind_phys) :: total_Cl, total_Cl_init call get_wavelength_edges(photolysis_wavelength_grid_interfaces) solver_type = Rosenbrock @@ -395,6 +408,12 @@ subroutine test_terminator() pressure(:,2) = (/ 8000.04_kind_phys, 9000.04_kind_phys /) dry_air_density(:,1) = (/ 3.5_kind_phys, 4.5_kind_phys /) dry_air_density(:,2) = (/ 5.5_kind_phys, 6.5_kind_phys /) + flux_data_photolysis_wavelength_interfaces(:) = & + (/ 200.0_kind_phys, 210.0_kind_phys, 220.0_kind_phys, 230.0_kind_phys, & + 240.0_kind_phys, 250.0_kind_phys, 260.0_kind_phys, 270.0_kind_phys, 280.0_kind_phys /) + extraterrestrial_flux(:) = & + (/ 1.5e13_kind_phys, 1.5e13_kind_phys, 1.4e13_kind_phys, 1.4e13_kind_phys, & + 1.3e13_kind_phys, 1.2e13_kind_phys, 1.1e13_kind_phys, 1.0e13_kind_phys /) filename_of_micm_configuration = 'musica_configurations/terminator/micm/config.json' filename_of_tuvx_configuration = 'musica_configurations/terminator/tuvx/config.json' @@ -473,11 +492,12 @@ subroutine test_terminator() write(*,*) "[MUSICA INFO] Initial Concentrations" write(*,fmt="(4(3x,e13.6))") constituents - call musica_ccpp_run(time_step, temperature, pressure, dry_air_density, constituent_props_ptr, & - constituents, geopotential_height_wrt_surface_at_midpoint, & - geopotential_height_wrt_surface_at_interface, surface_temperature, & - surface_geopotential, surface_albedo, standard_gravitational_acceleration, & - errmsg, errcode) + call musica_ccpp_run( time_step, temperature, pressure, dry_air_density, constituent_props_ptr, & + constituents, geopotential_height_wrt_surface_at_midpoint, & + geopotential_height_wrt_surface_at_interface, surface_geopotential, & + surface_temperature, surface_albedo, num_photolysis_wavelength_grid_sections, & + flux_data_photolysis_wavelength_interfaces, extraterrestrial_flux, & + standard_gravitational_acceleration, errmsg, errcode ) if (errcode /= 0) then write(*,*) trim(errmsg) stop 3 diff --git a/test/musica/tuvx/CMakeLists.txt b/test/musica/tuvx/CMakeLists.txt index 2c8623fd..ecd179be 100644 --- a/test/musica/tuvx/CMakeLists.txt +++ b/test/musica/tuvx/CMakeLists.txt @@ -110,4 +110,34 @@ add_test( WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ) -add_memory_check_test(test_tuvx_surface_albedo $ "" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) \ No newline at end of file +add_memory_check_test(test_tuvx_surface_albedo $ "" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + +# Extraterrestrial flux +add_executable(test_tuvx_extraterrestrial_flux test_tuvx_extraterrestrial_flux.F90) + +target_sources(test_tuvx_extraterrestrial_flux + PUBLIC + ${MUSICA_SRC_PATH}/tuvx/musica_ccpp_tuvx_wavelength_grid.F90 + ${MUSICA_SRC_PATH}/tuvx/musica_ccpp_tuvx_extraterrestrial_flux.F90 + ${MUSICA_SRC_PATH}/musica_ccpp_util.F90 + ${TO_BE_CCPPIZED_SRC_PATH}/ccpp_tuvx_utils.F90 + ${CCPP_TEST_SRC_PATH}/ccpp_kinds.F90 +) + +target_link_libraries(test_tuvx_extraterrestrial_flux + PRIVATE + musica-fortran +) + +set_target_properties(test_tuvx_extraterrestrial_flux + PROPERTIES + LINKER_LANGUAGE Fortran +) + +add_test( + NAME test_tuvx_extraterrestrial_flux + COMMAND $ + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} +) + +add_memory_check_test(test_tuvx_extraterrestrial_flux $ "" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) \ No newline at end of file diff --git a/test/musica/tuvx/configs/ts1_tsmlt.json b/test/musica/tuvx/configs/ts1_tsmlt.json deleted file mode 100644 index b2a2f986..00000000 --- a/test/musica/tuvx/configs/ts1_tsmlt.json +++ /dev/null @@ -1,2061 +0,0 @@ -{ - "__description": "TUV-x configuration for the MOZART-TS1 and MOZART-TSMLT chemical mechanisms", - "O2 absorption" : { - "cross section parameters file": "data/cross_sections/O2_parameters.txt" - }, - "grids": [ - { - "name": "time", - "type": "from config file", - "units": "hours", - "values": [ 12.0, 14.0 ] - } - ], - "profiles": [ - { - "name": "O3", - "type": "O3", - "units": "molecule cm-3", - "file path": "data/profiles/atmosphere/ussa.ozone" - }, - { - "name": "air", - "type": "air", - "units": "molecule cm-3", - "file path": "data/profiles/atmosphere/ussa.dens" - }, - { - "name": "O2", - "type": "O2", - "units": "molecule cm-3", - "file path": "data/profiles/atmosphere/ussa.dens" - }, - { - "name": "solar zenith angle", - "type": "solar zenith angle", - "units": "degrees", - "year" : 2002, - "month": 3, - "day": 21, - "longitude": 0.0, - "latitude": 0.0 - }, - { - "name": "Earth-Sun distance", - "type": "Earth-Sun distance", - "units": "AU", - "year" : 2002, - "month": 3, - "day": 21 - }, - { - "name": "extraterrestrial flux", - "enable diagnostics" : true, - "type": "extraterrestrial flux", - "units": "photon cm-2 s-1", - "file path": ["data/profiles/solar/susim_hi.flx", - "data/profiles/solar/atlas3_1994_317_a.dat", - "data/profiles/solar/sao2010.solref.converted", - "data/profiles/solar/neckel.flx"], - "interpolator": ["","","","fractional target"] - } - ], - "radiative transfer": { - "__output": true, - "solver" : { - "type" : "delta eddington" - }, - "cross sections": [ - { - "name": "air", - "type": "air" - }, - { - "name": "O3", - "netcdf files": [ - { "file path": "data/cross_sections/O3_1.nc" }, - { "file path": "data/cross_sections/O3_2.nc" }, - { "file path": "data/cross_sections/O3_3.nc" }, - { "file path": "data/cross_sections/O3_4.nc" } - ], - "type": "O3" - }, - { - "name": "O2", - "netcdf files": [ - { - "file path": "data/cross_sections/O2_1.nc", - "lower extrapolation": { "type": "boundary" } - } - ], - "type": "base" - } - ], - "radiators": [ - { - "enable diagnostics" : true, - "name": "air", - "type": "base", - "treat as air": true, - "cross section": "air", - "vertical profile": "air", - "vertical profile units": "molecule cm-3" - }, - { - "enable diagnostics" : true, - "name": "O2", - "type": "base", - "cross section": "O2", - "vertical profile": "O2", - "vertical profile units": "molecule cm-3" - }, - { - "enable diagnostics" : true, - "name": "O3", - "type": "base", - "cross section": "O3", - "vertical profile": "O3", - "vertical profile units": "molecule cm-3" - }, - { - "enable diagnostics" : true, - "name": "aerosols", - "type": "aerosol", - "optical depths": [2.40e-01, 1.06e-01, 4.56e-02, 1.91e-02, 1.01e-02, 7.63e-03, - 5.38e-03, 5.00e-03, 5.15e-03, 4.94e-03, 4.82e-03, 4.51e-03, - 4.74e-03, 4.37e-03, 4.28e-03, 4.03e-03, 3.83e-03, 3.78e-03, - 3.88e-03, 3.08e-03, 2.26e-03, 1.64e-03, 1.23e-03, 9.45e-04, - 7.49e-04, 6.30e-04, 5.50e-04, 4.21e-04, 3.22e-04, 2.48e-04, - 1.90e-04, 1.45e-04, 1.11e-04, 8.51e-05, 6.52e-05, 5.00e-05, - 3.83e-05, 2.93e-05, 2.25e-05, 1.72e-05, 1.32e-05, 1.01e-05, - 7.72e-06, 5.91e-06, 4.53e-06, 3.46e-06, 2.66e-06, 2.04e-06, - 1.56e-06, 1.19e-06, 9.14e-07], - "single scattering albedo": 0.99, - "asymmetry factor": 0.61, - "550 nm optical depth": 0.235 - } - ] - }, - "photolysis": { - "reactions": [ - { - "name": "jo2_a", - "__reaction": "O2 + hv -> O + O1D", - "cross section": { - "apply O2 bands": true, - "netcdf files": [ - { - "file path": "data/cross_sections/O2_1.nc", - "lower extrapolation": { "type": "boundary" }, - "interpolator": { "type": "fractional target" } - } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 0, - "override bands": [ - { - "band": "lyman-alpha", - "value": 0.53 - }, - { - "band": "schumann-runge continuum", - "value": 1.0 - } - ] - }, - "heating" : { - "energy term": 175.05 - } - }, - { - "name": "jo2_b", - "__reaction": "O2 + hv -> O + O", - "cross section": { - "apply O2 bands": true, - "netcdf files": [ - { - "file path": "data/cross_sections/O2_1.nc", - "lower extrapolation": { "type": "boundary" }, - "interpolator": { "type": "fractional target" } - } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0, - "override bands": [ - { - "band": "lyman-alpha", - "value": 0.47 - }, - { - "band": "schumann-runge continuum", - "value": 0.0 - } - ] - }, - "heating" : { - "energy term": 242.37 - } - }, - { - "name": "jo3_a", - "__reaction": "O3 + hv -> O2 + O(1D)", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/O3_1.nc" }, - { "file path": "data/cross_sections/O3_2.nc" }, - { "file path": "data/cross_sections/O3_3.nc" }, - { "file path": "data/cross_sections/O3_4.nc" } - ], - "type": "O3" - }, - "quantum yield": { - "type": "O3+hv->O2+O(1D)" - }, - "heating" : { - "energy term": 310.32 - } - }, - { - "name": "jo3_b", - "__reaction": "O3 + hv -> O2 + O(3P)", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/O3_1.nc" }, - { "file path": "data/cross_sections/O3_2.nc" }, - { "file path": "data/cross_sections/O3_3.nc" }, - { "file path": "data/cross_sections/O3_4.nc" } - ], - "type": "O3" - }, - "quantum yield": { - "type": "O3+hv->O2+O(3P)" - }, - "heating" : { - "energy term": 1179.87 - } - }, - { - "name": "jn2o", - "__reaction": "N2O + hv -> N2 + O(1D)", - "cross section": { - "type": "N2O+hv->N2+O(1D)" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jno2", - "__reaction": "NO2 + hv -> NO + O(3P)", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/NO2_1.nc" } - ], - "type": "NO2 tint" - }, - "quantum yield": { - "netcdf files": ["data/quantum_yields/NO2_1.nc"], - "type": "NO2 tint", - "lower extrapolation": { "type": "boundary" } - } - }, - { - "name": "jn2o5_a", - "__reaction": "N2O5 + hv -> NO2 + NO3", - "cross section": { - "type":"temperature based", - "netcdf file": "data/cross_sections/N2O5_JPL06.nc", - "parameterization": { - "type": "HARWOOD", - "aa": [ -18.27, -18.42, -18.59, -18.72, -18.84, - -18.90, -18.93, -18.87, -18.77, -18.71, - -18.31, -18.14, -18.01, -18.42, -18.59, - -18.13 ], - "bb": [ -91.0, -104.0, -112.0, -135.0, -170.0, - -226.0, -294.0, -388.0, -492.0, -583.0, - -770.0, -885.0, -992.0, -949.0, -966.0, - -1160.0 ], - "base temperature": 0.0, - "base wavelength": 0.0, - "logarithm": "base 10", - "minimum wavelength": 260.0, - "maximum wavelength": 410.0, - "temperature ranges": [ - { - "maximum": 199.999999999999, - "fixed value": 200 - }, - { - "minimum": 200, - "maximum": 295 - }, - { - "minimum": 295.00000000001, - "fixed value": 295.0 - } - ] - }, - "parameterization wavelength grid": { - "name": "custom wavelengths", - "type": "from config file", - "units": "nm", - "values": [ - 255.0, 265.0, 275.0, 285.0, 295.0, 305.0, - 315.0, 325.0, 335.0, 345.0, 355.0, 365.0, - 375.0, 385.0, 395.0, 405.0, 415.0 - ] - } - }, - "quantum yield": { - "type": "Taylor series", - "constant value": 0.0, - "coefficients": [ -2.832441, 0.012809638 ], - "override bands": [ - { - "band": "range", - "minimum wavelength": 300.0, - "value": 1.0 - } - ] - } - }, - { - "name": "jn2o5_b", - "__reaction": "N2O5 + hv -> NO + O + NO3", - "cross section": { - "type":"temperature based", - "netcdf file": "data/cross_sections/N2O5_JPL06.nc", - "parameterization": { - "type": "HARWOOD", - "aa": [ -18.27, -18.42, -18.59, -18.72, -18.84, - -18.90, -18.93, -18.87, -18.77, -18.71, - -18.31, -18.14, -18.01, -18.42, -18.59, - -18.13 ], - "bb": [ -91.0, -104.0, -112.0, -135.0, -170.0, - -226.0, -294.0, -388.0, -492.0, -583.0, - -770.0, -885.0, -992.0, -949.0, -966.0, - -1160.0 ], - "base temperature": 0.0, - "base wavelength": 0.0, - "logarithm": "base 10", - "minimum wavelength": 260.0, - "maximum wavelength": 410.0, - "temperature ranges": [ - { - "maximum": 199.999999999999, - "fixed value": 200 - }, - { - "minimum": 200, - "maximum": 295 - }, - { - "minimum": 295.00000000001, - "fixed value": 295.0 - } - ] - }, - "parameterization wavelength grid": { - "name": "custom wavelengths", - "type": "from config file", - "units": "nm", - "values": [ - 255.0, 265.0, 275.0, 285.0, 295.0, 305.0, - 315.0, 325.0, 335.0, 345.0, 355.0, 365.0, - 375.0, 385.0, 395.0, 405.0, 415.0 - ] - } - }, - "quantum yield": { - "type": "Taylor series", - "constant value": 0.0, - "coefficients": [ 3.832441, -0.012809638 ], - "override bands": [ - { - "band": "range", - "minimum wavelength": 300.0, - "value": 0.0 - } - ] - } - }, - { - "name": "jhno3", - "__reaction": "HNO3 + hv -> OH + NO2", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/HNO3_JPL06.nc" } - ], - "type": "HNO3+hv->OH+NO2" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jno3_a", - "__reaction": "NO3 + hv -> NO2 + O(3P)", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/NO3_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "netcdf files": [ - "data/quantum_yields/NO3-NO2+O(3P)_1.nc" - ], - "type": "tint", - "lower extrapolation": { - "type": "constant", - "value": 1.0 - } - } - }, - { - "name": "jno3_b", - "__reaction": "NO3 + hv -> NO + O2", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/NO3_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "netcdf files": [ - "data/quantum_yields/NO3-NO+O2_1.nc" - ], - "type": "tint" - } - }, - { - "name": "jch3ooh", - "__reaction": "CH3OOH + hv -> CH3O + OH", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/CH3OOH_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jch2o_a", - "__reaction": "CH2O + hv -> H + HCO", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/CH2O_1.nc" } - ], - "type": "CH2O" - }, - "quantum yield": { - "netcdf files": [ - "data/quantum_yields/CH2O_1.nc" - ], - "type": "base", - "lower extrapolation": { - "type": "boundary" - } - } - }, - { - "name": "jch2o_b", - "__reaction": "CH2O + hv -> H2 + CO", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/CH2O_1.nc" } - ], - "type": "CH2O" - }, - "quantum yield": { - "netcdf files": [ - "data/quantum_yields/CH2O_1.nc" - ], - "type": "CH2O", - "lower extrapolation": { - "type": "boundary" - } - } - }, - { - "name": "jh2o2", - "__reaction": "H2O2 + hv -> OH + OH", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/H2O2_1.nc" } - ], - "type": "H2O2+hv->OH+OH" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jch3cho", - "__reaction": "CH3CHO + hv -> CH3 + HCO", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/CH3CHO_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "netcdf files": [ - "data/quantum_yields/CH3CHO_1.nc" - ], - "type": "CH3CHO+hv->CH3+HCO" - } - }, - { - "name": "jpan", - "__reaction": "PAN + hv -> 0.6*CH3CO3 + 0.6*NO2 + 0.4*CH3O2 + 0.4*NO3 + 0.4*CO2", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/PAN_1.nc" } - ], - "type": "CH3ONO2+hv->CH3O+NO2" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jmvk", - "__reaction": "MVK + hv -> 0.7*C3H6 + 0.7*CO + 0.3*CH3O2 + 0.3*CH3CO3", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/MVK_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "MVK+hv->Products" - } - }, - { - "name": "jacet", - "__reaction": "CH3COCH3 + hv -> CH3CO + CH3", - "cross section": { - "type": "temperature based", - "parameterization": { - "type": "TAYLOR_SERIES", - "netcdf file": { - "file path": "data/cross_sections/ACETONE_JPL06.nc" - }, - "base temperature": 0.0, - "temperature ranges": [ - { - "maximum": 234.999999999999, - "fixed value": 235.0 - }, - { - "minimum": 235.0, - "maximum": 298.0 - }, - { - "minimum": 298.00000000001, - "fixed value": 298.0 - } - ] - } - }, - "quantum yield": { - "type": "CH3COCH3+hv->CH3CO+CH3", - "branch": "CO+CH3CO", - "low wavelength value": 1, - "minimum temperature": 218, - "maximum temperature": 295 - } - }, - { - "name": "jmgly", - "__reaction": "CH3COCHO + hv -> CH3CO3 + CO + HO2", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/CH3COCHO_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "CH3COCHO+hv->CH3CO+HCO" - } - }, - { - "name": "jglyald", - "__reaction": "GLYALD + hv -> 2*HO2 + CO + CH2O", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/HOCH2CHO_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 0.5 - } - }, - { - "name": "jbrcl", - "__reaction": "BrCl + hv -> Br + Cl", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/BrCl_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jbro", - "__reaction": "BrO + hv -> Br + O", - "cross section": { - "netcdf files": [ - { - "file path": "data/cross_sections/BRO_JPL06.nc" - } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jbrono2_a", - "__reaction": "BrONO2 + hv -> Br + NO3", - "cross section": { - "type": "temperature based", - "parameterization": { - "type": "TAYLOR_SERIES", - "netcdf file": { - "file path": "data/cross_sections/BRONO2_JPL06.nc" - }, - "base temperature": 296.0, - "temperature ranges": [ - { - "maximum": 199.999999999999, - "fixed value": 200.0 - }, - { - "minimum": 200.0, - "maximum": 296.0 - }, - { - "minimum": 296.00000000001, - "fixed value": 296.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 0.85 - } - }, - { - "name": "jbrono2_b", - "__reaction": "BrONO2 + hv -> BrO + NO2", - "cross section": { - "type": "temperature based", - "parameterization": { - "type": "TAYLOR_SERIES", - "netcdf file": { - "file path": "data/cross_sections/BRONO2_JPL06.nc" - }, - "base temperature": 296.0, - "temperature ranges": [ - { - "maximum": 199.999999999999, - "fixed value": 200.0 - }, - { - "minimum": 200.0, - "maximum": 296.0 - }, - { - "minimum": 296.00000000001, - "fixed value": 296.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 0.15 - } - }, - { - "name": "jccl4", - "__reaction": "CCl4 + hv -> Products", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/CCl4_1.nc" } - ], - "type": "CCl4+hv->Products" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jcf2clbr", - "__reaction": "CF2BrCl + hv -> Products", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/CF2BrCl_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jcf3br", - "__reaction": "CF3Br + hv -> Products", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/H1301_JPL06.nc", - "parameterization": { - "AA": [ 62.563, -2.0068, 1.6592e-2, -5.6465e-5, 6.7459e-8 ], - "BB": [ -9.1755e-1, 1.8575e-2, -1.3857e-4, 4.5066e-7, -5.3803e-10 ], - "lp": [ 0.0, 1.0, 2.0, 3.0, 4.0 ], - "minimum wavelength": 178.0, - "maximum wavelength": 280.0, - "base temperature": 273.0, - "base wavelength": 0.0, - "logarithm": "base 10", - "temperature ranges": [ - { - "maximum": 209.999999999999, - "fixed value": 210.0 - }, - { - "minimum": 210.0, - "maximum": 300.0 - }, - { - "minimum": 300.00000000001, - "fixed value": 300.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jcfcl3", - "__reaction": "CCl3F + hv -> Products", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/CFCL3_JPL06.nc", - "parameterization": { - "AA": [ -84.611, 7.9551e-1, -2.0550e-3, -4.4812e-6, 1.5838e-8 ], - "BB": [ -5.7912, 1.1689e-1, -8.8069e-4, 2.9335e-6, -3.6421e-9 ], - "lp": [ 0.0, 1.0, 2.0, 3.0, 4.0 ], - "minimum wavelength": 174.1, - "maximum wavelength": 230.0, - "base temperature": 273.0, - "base wavelength": 0.0, - "logarithm": "base 10", - "temperature ranges": [ - { - "maximum": 209.999999999999, - "fixed value": 210.0 - }, - { - "minimum": 210, - "maximum": 300 - }, - { - "minimum": 300.00000000001, - "fixed value": 300.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jcfc113", - "__reaction": "CFC-113 + hv -> Products", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/CFC113_JPL06.nc", - "parameterization": { - "AA": [ -1087.9, 20.004, -1.3920e-1, 4.2828e-4, -4.9384e-7 ], - "BB": [ 12.493, -2.3937e-1, 1.7142e-3, -5.4393e-6, 6.4548e-9 ], - "lp": [ 0.0, 1.0, 2.0, 3.0, 4.0 ], - "minimum wavelength": 182.0, - "maximum wavelength": 230.0, - "base temperature": 273.0, - "base wavelength": 0.0, - "logarithm": "base 10", - "temperature ranges": [ - { - "maximum": 209.999999999999, - "fixed value": 210.0 - }, - { - "minimum": 210, - "maximum": 300 - }, - { - "minimum": 300.00000000001, - "fixed value": 300.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jcfc114", - "__reaction": "CFC-114 + hv -> Products", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/CFC114_JPL10.nc", - "parameterization": { - "AA": [ -160.50, 2.4807, -1.5202e-2, 3.8412e-5, -3.4373e-8 ], - "BB": [ -1.5296, 3.5248e-2, -2.9951e-4, 1.1129e-6, -1.5259e-9 ], - "lp": [ 0.0, 1.0, 2.0, 3.0, 4.0 ], - "minimum wavelength": 172.0, - "maximum wavelength": 220.0, - "base temperature": 273.0, - "base wavelength": 0.0, - "logarithm": "base 10", - "temperature ranges": [ - { - "maximum": 209.999999999999, - "fixed value": 210.0 - }, - { - "minimum": 210, - "maximum": 300 - }, - { - "minimum": 300.00000000001, - "fixed value": 300.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jcfc115", - "__reaction": "CFC-115 + hv -> Products", - "cross section": { - "type": "base", - "netcdf files": [ - { "file path": "data/cross_sections/CFC115_JPL10.nc" } - ] - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jcf2cl2", - "__reaction": "CCl2F2 + hv -> Products", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/CF2CL2_JPL06.nc", - "parameterization": { - "AA": [ -43.8954569, -2.403597e-1, -4.2619e-4, 9.8743e-6, 0.0 ], - "BB": [ 4.8438e-3, 4.96145e-4, -5.6953e-6, 0.0, 0.0 ], - "lp": [ 0.0, 1.0, 2.0, 3.0, 4.0 ], - "minimum wavelength": 200.0, - "maximum wavelength": 231.0, - "base temperature": 296.0, - "base wavelength": 200.0, - "logarithm": "natural", - "temperature ranges": [ - { - "maximum": 219.999999999999, - "fixed value": 220.0 - }, - { - "minimum": 220, - "maximum": 296 - }, - { - "minimum": 296.00000000001, - "fixed value": 296.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jch2br2", - "__reaction": "CH2BR2 + hv -> 2*BR", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/CH2BR2_1.nc", - "parameterization": { - "AA": [ -70.211776, 1.940326e-1, 2.726152e-3, -1.695472e-5, 2.500066e-8 ], - "BB": [ 2.899280, -4.327724e-2, 2.391599e-4, -5.807506e-7, 5.244883e-10 ], - "lp": [ 0.0, 1.0, 2.0, 3.0, 4.0 ], - "minimum wavelength": 210.0, - "maximum wavelength": 290.0, - "base temperature": 273.0, - "base wavelength": 0.0, - "logarithm": "base 10", - "temperature ranges": [ - { - "maximum": 209.999999999999, - "fixed value": 210.0 - }, - { - "minimum": 210, - "maximum": 300 - }, - { - "minimum": 300.00000000001, - "fixed value": 300.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jch3br", - "__reaction": "CH3Br + hv -> Products", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/CH3BR_JPL06.nc", - "parameterization": { - "AA": [ 46.520, -1.4580, 1.1469e-2, -3.7627e-5, 4.3264e-8 ], - "BB": [ 9.3408e-1, -1.6887e-2, 1.1487e-4, -3.4881e-7, 3.9945e-10 ], - "lp": [ 0.0, 1.0, 2.0, 3.0, 4.0 ], - "minimum wavelength": 200.0, - "maximum wavelength": 280.0, - "base temperature": 273.0, - "base wavelength": 0.0, - "logarithm": "base 10", - "temperature ranges": [ - { - "maximum": 209.999999999999, - "fixed value": 210.0 - }, - { - "minimum": 210, - "maximum": 300 - }, - { - "minimum": 300.00000000001, - "fixed value": 300.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jch3ccl3", - "__reaction": "CH3CCl3+hv->Products", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/CH3CCl3_1.nc" } - ], - "type": "tint" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jch3cl", - "__reaction": "CH3Cl + hv -> Products", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/CH3CL_JPL06.nc", - "parameterization": { - "AA": [ -299.80, 5.1047, -3.3630e-2, 9.5805e-5, -1.0135e-7 ], - "BB": [ -7.1727, 1.4837e-1, -1.1463e-3, 3.9188e-6, -4.9994e-9 ], - "lp": [ 0.0, 1.0, 2.0, 3.0, 4.0 ], - "minimum wavelength": 174.1, - "maximum wavelength": 216.0, - "base temperature": 273.0, - "base wavelength": 0.0, - "logarithm": "base 10", - "temperature ranges": [ - { - "maximum": 209.999999999999, - "fixed value": 210.0 - }, - { - "minimum": 210, - "maximum": 300 - }, - { - "minimum": 300.00000000001, - "fixed value": 300.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jchbr3", - "__reaction": "CHBr3 + hv -> Products", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/CHBR3_JPL10.nc", - "parameterization": { - "AA": [ -32.6067, 0.10308, 6.39e-5, -7.7392e-7, -2.2513e-9, 6.1376e-12 ], - "BB": [ 0.1582, -0.0014758, 3.8058e-6, 9.187e-10, -1.0772e-11, 0.0 ], - "lp": [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 ], - "minimum wavelength": 260.0, - "maximum wavelength": 362.0, - "base temperature": 296.0, - "base wavelength": 0.0, - "logarithm": "base 10", - "invert temperature offset": true, - "temperature ranges": [ - { - "maximum": 259.999999999999, - "fixed value": 260.0 - }, - { - "minimum": 260.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jcl2", - "__reaction": "Cl2 + hv -> Cl + Cl", - "cross section": { - "type": "Cl2+hv->Cl+Cl" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jcl2o2", - "__reaction": "ClOOCl + hv -> Cl + ClOO", - "__comments": "TODO - this doesn't exactly match the products in TS1", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/CL2O2_JPL10.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jclo", - "__reaction": "ClO + hv -> Cl + O", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/CLO_JPL06.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jclono2_a", - "__reaction": "ClONO2 + hv -> Cl + NO3", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/ClONO2_1.nc" } - ], - "type": "ClONO2" - }, - "quantum yield": { - "type": "ClONO2+hv->Cl+NO3" - } - }, - { - "name": "jclono2_b", - "__reaction": "ClONO2 + hv -> ClO + NO2", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/ClONO2_1.nc" } - ], - "type": "ClONO2" - }, - "quantum yield": { - "type": "ClONO2+hv->ClO+NO2" - } - }, - { - "name": "jcof2", - "__reaction": "CF2O + hv -> Products", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/CF2O_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jcofcl", - "__reaction": "CClFO + hv -> Products", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/CClFO_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jh2402", - "__reaction": "H2402 + hv -> 2*BR + 2*COF2", - "__comments": "TUV data set name CF2BrCF2Br", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/H2402_JPL06.nc", - "parameterization": { - "AA": [ 34.026, -1.152616, 8.959798e-3, -2.9089e-5, 3.307212e-8 ], - "BB": [ 4.010664e-1, -8.358968e-3, 6.415741e-5, -2.157554e-7, 2.691871e-10 ], - "lp": [ 0.0, 1.0, 2.0, 3.0, 4.0 ], - "minimum wavelength": 190.0, - "maximum wavelength": 290.0, - "base temperature": 273.0, - "base wavelength": 0.0, - "logarithm": "base 10", - "temperature ranges": [ - { - "maximum": 209.999999999999, - "fixed value": 210.0 - }, - { - "minimum": 210.0, - "maximum": 300.0 - }, - { - "minimum": 300.00000000001, - "fixed value": 300.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jhcfc141b", - "__reaction": "HCFC-141b + hv -> Products", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/HCFC141b_JPL10.nc", - "parameterization": { - "AA": [ -682.913042, 12.122290, -8.187699e-2, 2.437244e-4, -2.719103e-7 ], - "BB": [ 4.074747, -8.053899e-2, 5.946552e-4, -1.945048e-6, 2.380143e-9 ], - "lp": [ 0.0, 1.0, 2.0, 3.0, 4.0 ], - "minimum wavelength": 172.0, - "maximum wavelength": 240.0, - "base temperature": 273.0, - "base wavelength": 0.0, - "logarithm": "base 10", - "temperature ranges": [ - { - "maximum": 209.999999999999, - "fixed value": 210.0 - }, - { - "minimum": 210.0, - "maximum": 300.0 - }, - { - "minimum": 300.00000000001, - "fixed value": 300.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jhcfc142b", - "__reaction": "HCFC-142b + hv -> Products", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/HCFC142b_JPL10.nc", - "parameterization": { - "AA": [ -328.092008, 6.342799, -4.810362e-2, 1.611991e-4, -2.042613e-7 ], - "BB": [ 4.289533e-1, -9.042817e-3, 7.018009e-5, -2.389064e-7, 3.039799e-10 ], - "lp": [ 0.0, 1.0, 2.0, 3.0, 4.0 ], - "minimum wavelength": 172.0, - "maximum wavelength": 230.0, - "base temperature": 273.0, - "base wavelength": 0.0, - "logarithm": "base 10", - "temperature ranges": [ - { - "maximum": 209.999999999999, - "fixed value": 210.0 - }, - { - "minimum": 210.0, - "maximum": 300.0 - }, - { - "minimum": 300.00000000001, - "fixed value": 300.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jhcfc22", - "__reaction": "HCFC-22 + hv -> Products", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/HCFC22_JPL06.nc", - "parameterization wavelength grid": { - "name": "custom wavelengths", - "type": "from config file", - "units": "nm", - "values": [ - 169.0, 171.0, 173.0, 175.0, 177.0, 179.0, 181.0, 183.0, 185.0, - 187.0, 189.0, 191.0, 193.0, 195.0, 197.0, 199.0, 201.0, 203.0, - 205.0, 207.0, 209.0, 211.0, 213.0, 215.0, 217.0, 219.0, 221.0 - ] - }, - "parameterization": { - "AA": [ -106.029, 1.5038, -8.2476e-3, 1.4206e-5 ], - "BB": [ -1.3399e-1, 2.7405e-3, -1.8028e-5, 3.8504e-8 ], - "lp": [ 0.0, 1.0, 2.0, 3.0 ], - "minimum wavelength": 174.0, - "maximum wavelength": 204.0, - "base temperature": 273.0, - "base wavelength": 0.0, - "logarithm": "base 10", - "temperature ranges": [ - { - "maximum": 209.999999999999, - "fixed value": 210.0 - }, - { - "minimum": 210.0, - "maximum": 300.0 - }, - { - "minimum": 300.00000000001, - "fixed value": 300.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jhcl", - "__reaction": "HCl + hv -> H + Cl", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/HCl_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jhobr", - "__reaction": "HOBr + hv -> OH + Br", - "cross section": { - "type": "HOBr+hv->OH+Br" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jhocl", - "__reaction": "HOCl + hv -> HO + Cl", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/HOCl_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "joclo", - "__reaction": "OClO + hv -> Products", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/OClO_1.nc" }, - { "file path": "data/cross_sections/OClO_2.nc" }, - { "file path": "data/cross_sections/OClO_3.nc" } - ], - "type": "OClO+hv->Products" - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jho2no2_a", - "__reaction": "HNO4 + hv -> OH + NO3", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/HO2NO2_JPL06.nc", - "parameterization": { - "type": "BURKHOLDER", - "netcdf file": { - "file path": "data/cross_sections/HO2NO2_temp_JPL06.nc" - }, - "A": -988.0, - "B": 0.69, - "temperature ranges": [ - { - "maximum": 279.999999999999, - "fixed value": 280.0 - }, - { - "minimum": 280.0, - "maximum": 350.0 - }, - { - "minimum": 350.00000000001, - "fixed value": 350.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 0.30, - "override bands": [ - { - "band": "range", - "minimum wavelength": 200.0, - "value": 0.20 - } - ] - } - }, - { - "name": "jho2no2_b", - "__reaction": "HNO4 + hv -> HO2 + NO2", - "cross section": { - "type": "temperature based", - "netcdf file": "data/cross_sections/HO2NO2_JPL06.nc", - "parameterization": { - "type": "BURKHOLDER", - "netcdf file": { - "file path": "data/cross_sections/HO2NO2_temp_JPL06.nc" - }, - "A": -988.0, - "B": 0.69, - "temperature ranges": [ - { - "maximum": 279.999999999999, - "fixed value": 280.0 - }, - { - "minimum": 280.0, - "maximum": 350.0 - }, - { - "minimum": 350.00000000001, - "fixed value": 350.0 - } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 0.70, - "override bands": [ - { - "band": "range", - "minimum wavelength": 200.0, - "value": 0.80 - } - ] - } - }, - { - "name": "jmacr_a", - "__reaction": "CH2=C(CH3)CHO->1.34HO2+0.66MCO3+1.34CH2O+CH3CO3", - "__comments": "Methacrolein photolysis channel 1", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/Methacrolein_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 0.005 - } - }, - { - "name": "jmacr_b", - "__reaction": "CH2=C(CH3)CHO->0.66OH+1.34CO", - "__comments": "Methacrolein photolysis channel 2", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/Methacrolein_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 0.005 - } - }, - { - "name": "jhyac", - "__reaction": "CH2(OH)COCH3->CH3CO3+HO2+CH2O", - "__comments": "hydroxy acetone TODO: the products of this reaction differ from standalone TUV-x", - "cross section": { - "netcdf files": [ - { "file path": "data/cross_sections/Hydroxyacetone_1.nc" } - ], - "type": "base" - }, - "quantum yield": { - "type": "base", - "constant value": 0.65 - } - }, - { - "name": "jh2o_a", - "__reaction": "H2O + hv -> OH + H", - "cross section": { - "type": "base", - "merge data": true, - "netcdf files": [ - { - "file path": "data/cross_sections/H2O_1.nc", - "zero above": 183.0 - }, - { - "file path": "data/cross_sections/H2O_2.nc", - "zero below": 183.00000000001, - "zero above": 190.0 - }, - { - "file path": "data/cross_sections/H2O_3.nc", - "zero below": 190.00000000001 - } - ] - }, - "quantum yield" : { - "type": "base", - "netcdf files": [ "data/quantum_yields/H2O_H_OH.nc" ] - } - }, - { - "name": "jh2o_b", - "__reaction": "H2O + hv -> H2 + O1D", - "cross section": { - "type": "base", - "merge data": true, - "netcdf files": [ - { - "file path": "data/cross_sections/H2O_1.nc", - "zero above": 183.0 - }, - { - "file path": "data/cross_sections/H2O_2.nc", - "zero below": 183.00000000001, - "zero above": 190.0 - }, - { - "file path": "data/cross_sections/H2O_3.nc", - "zero below": 190.00000000001 - } - ] - }, - "quantum yield" : { - "type": "base", - "netcdf files": [ "data/quantum_yields/H2O_H2_O1D.nc" ] - } - }, - { - "name": "jh2o_c", - "__reaction": "H2O + hv -> 2*H + O", - "cross section": { - "type": "base", - "merge data": true, - "netcdf files": [ - { - "file path": "data/cross_sections/H2O_1.nc", - "zero above": 183.0 - }, - { - "file path": "data/cross_sections/H2O_2.nc", - "zero below": 183.00000000001, - "zero above": 190.0 - }, - { - "file path": "data/cross_sections/H2O_3.nc", - "zero below": 190.00000000001 - } - ] - }, - "quantum yield" : { - "type": "base", - "netcdf files": [ "data/quantum_yields/H2O_2H_O3P.nc" ] - } - }, - { - "name": "jch4_a", - "__reaction": "CH4 + hv -> H + CH3O2", - "cross section": { - "type": "base", - "netcdf files": [ - { "file path": "data/cross_sections/CH4_1.nc" } - ] - }, - "quantum yield": { - "type": "base", - "constant value": 0.45 - } - }, - { - "name": "jch4_b", - "__reaction": "CH4 + hv -> 1.44*H2 + 0.18*CH2O + 0.18*O + 0.33*OH + 0.33*H + 0.44*CO2 + 0.38*CO + 0.05*H2O", - "cross section": { - "type": "base", - "netcdf files": [ - { "file path": "data/cross_sections/CH4_1.nc" } - ] - }, - "quantum yield": { - "type": "base", - "constant value": 0.55 - } - }, - { - "name": "jco2", - "__reaction": "CO2 + hv -> CO + O", - "cross section": { - "type": "base", - "netcdf files": [ - { "file path": "data/cross_sections/CO2_1.nc" } - ] - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jhbr", - "__reaction": "HBR + hv -> BR + H", - "cross section": { - "type": "base", - "netcdf files": [ - { "file path": "data/cross_sections/HBr_1.nc" } - ] - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jhf", - "__reaction": "HF + hv -> H + F", - "cross section": { - "type": "base", - "netcdf files": [ - { "file path": "data/cross_sections/HF_1.nc" } - ] - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jsf6", - "__reaction": "SF6 + hv -> sink", - "cross section": { - "type": "base", - "netcdf files": [ - { "file path": "data/cross_sections/SF6_1.nc" } - ] - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jh2so4", - "__reaction": "H2SO4 + hv -> SO3 + H2O", - "cross section": { - "type": "base", - "data": { - "default value": 0.0, - "point values": [ - { "wavelength": 121.65, "value": 6.3e-17 }, - { "wavelength": 525.0, "value": 1.43e-26 }, - { "wavelength": 625.0, "value": 1.8564e-25 }, - { "wavelength": 725.0, "value": 3.086999e-24 } - ] - } - }, - "quantum yield": { - "type": "H2SO4 Mills", - "netcdf files": [ - "data/quantum_yields/H2SO4_mills.nc" - ], - "parameterized wavelengths": [ - 525, - 625, - 725 - ], - "collision interval s": [ - 1.1e-9, - 8.9e-9, - 1.7e-7 - ], - "molecular diameter m": 4.18e-10, - "molecular weight kg mol-1": 98.078479e-3 - } - }, - { - "name": "jocs", - "__reaction": "OCS + hv -> S + CO", - "cross section": { - "type": "base", - "netcdf files": [ - { "file path": "data/cross_sections/OCS_1.nc" } - ] - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jso", - "__reaction": "SO + hv -> S + O", - "cross section": { - "type": "base", - "netcdf files": [ - { "file path": "data/cross_sections/SO_1.nc" } - ] - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jso2", - "__reaction": "SO2 + hv -> SO + O", - "cross section": { - "type": "base", - "netcdf files": [ - { "file path": "data/cross_sections/SO2_Mills.nc" } - ] - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jso3", - "__reaction": "SO3 + hv -> SO2 + O", - "cross section": { - "type": "base", - "netcdf files": [ - { "file path": "data/cross_sections/SO3_1.nc" } - ] - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - }, - { - "name": "jno_i", - "__reaction": "NO + hv -> NOp + e", - "cross section": { - "type": "base", - "data": { - "default value": 0.0, - "point values": [ - { "wavelength": 121.65, "value": 2.0e-18 } - ] - } - }, - "quantum yield": { - "type": "base", - "constant value": 1.0 - } - } - ] - }, - "__CAM options": { - "aliasing": { - "default matching": "backup", - "pairs": [ - { - "to": "jalknit", - "__reaction": "ALKNIT + hv -> NO2 + 0.4*CH3CHO + 0.1*CH2O + 0.25*CH3COCH3 + HO2 + 0.8*MEK", - "from": "jch3ooh" - }, - { - "to": "jpooh", - "__reaction": "POOH (C3H6OHOOH) + hv -> CH3CHO + CH2O + HO2 + OH", - "from": "jch3ooh" - }, - { - "to": "jch3co3h", - "__reaction": "CH3COOOH + hv -> CH3O2 + OH + CO2", - "from": "jh2o2", - "scale by": 0.28 - }, - { - "to": "jmpan", - "__reaction": "MPAN + hv -> MCO3 + NO2", - "from": "jpan" - }, - { - "to": "jc2h5ooh", - "__reaction": "C2H5OOH + hv -> CH3CHO + HO2 + OH", - "from": "jch3ooh" - }, - { - "to": "jc3h7ooh", - "__reaction": "C3H7OOH + hv -> 0.82*CH3COCH3 + OH + HO2", - "from": "jch3ooh" - }, - { - "to": "jc6h5ooh", - "__reaction": "C6H5OOH + hv -> PHENO + OH", - "from": "jch3ooh" - }, - { - "to": "jeooh", - "__reaction": "EOOH + hv -> EO + OH", - "from": "jch3ooh" - }, - { - "to": "jrooh", - "__reaction": "ROOH + hv -> CH3CO3 + CH2O + OH", - "from": "jch3ooh" - }, - { - "to": "jxooh", - "__reaction": "XOOH + hv -> OH", - "from": "jch3ooh" - }, - { - "to": "jonitr", - "__reaction": "ONITR + hv -> NO2", - "from": "jch3cho" - }, - { - "to": "jisopooh", - "__reaction": "ISOPOOH + hv -> 0.402*MVK + 0.288*MACR + 0.69*CH2O + HO2", - "from": "jch3ooh" - }, - { - "to": "jmek", - "__reaction": "MEK + hv -> CH3CO3 + C2H5O2", - "from": "jacet" - }, - { - "to": "jalkooh", - "__reaction": "ALKOOH + hv -> .4*CH3CHO + .1*CH2O + .25*CH3COCH3 + .9*HO2 + .8*MEK + OH", - "from": "jch3ooh" - }, - { - "to": "jbenzooh", - "__reaction": "BENZOOH + hv -> OH + GLYOXAL + 0.5*BIGALD1 + HO2", - "from": "jch3ooh" - }, - { - "to": "jbepomuc", - "__reaction": "BEPOMUC + hv -> BIGALD1 + 1.5*HO2 + 1.5*CO", - "from": "jno2", - "scale by": 0.1 - }, - { - "to": "jbigald", - "__reaction": "BIGALD + hv -> 0.45*CO + 0.13*GLYOXAL + 0.56*HO2 + 0.13*CH3CO3 + 0.18*CH3COCHO", - "from": "jno2", - "scale by": 0.2 - }, - { - "to": "jbigald1", - "__reaction": "BIGALD1 + hv -> 0.6*MALO2 + HO2", - "from": "jno2", - "scale by": 0.14 - }, - { - "to": "jbigald2", - "__reaction": "BIGALD2 + hv -> 0.6*HO2 + 0.6*DICARBO2", - "from": "jno2", - "scale by": 0.2 - }, - { - "to": "jbigald3", - "__reaction": "BIGALD3 + hv -> 0.6*HO2 + 0.6*CO + 0.6*MDIALO2", - "from": "jno2", - "scale by": 0.2 - }, - { - "to": "jbigald4", - "__reaction": "BIGALD4 + hv -> HO2 + CO + CH3COCHO + CH3CO3", - "from": "jno2", - "scale by": 0.006 - }, - { - "to": "jbzooh", - "__reaction": "BZOOH + hv -> BZALD + OH + HO2", - "from": "jch3ooh" - }, - { - "to": "jmekooh", - "__reaction": "MEKOOH + hv -> OH + CH3CO3 + CH3CHO", - "from": "jch3ooh" - }, - { - "to": "jtolooh", - "__reaction": "TOLOOH + hv -> OH + .45*GLYOXAL + .45*CH3COCHO + .9*BIGALD", - "from": "jch3ooh" - }, - { - "to": "jterpooh", - "__reaction": "TERPOOH + hv -> OH + .1*CH3COCH3 + HO2 + MVK + MACR", - "from": "jch3ooh" - }, - { - "to": "jhonitr", - "__reaction": "HONITR + hv -> NO2 + 0.67*HO2 + 0.33*CH3CHO + 0.33*CH2O + 0.33*CO + 0.33*GLYALD + 0.33*CH3CO3 + 0.17*HYAC + 0.17*CH3COCH3", - "from": "jch2o_a" - }, - { - "to": "jhpald", - "__reaction": "HPALD + hv -> BIGALD3 + OH + HO2", - "from": "jno2", - "scale by": 0.006 - }, - { - "to": "jisopnooh", - "__reaction": "ISOPNOOH + hv -> NO2 + HO2 + ISOPOOH", - "from": "jch3ooh" - }, - { - "to": "jnc4cho", - "__reaction": "NC4CHO + hv -> BIGALD3 + NO2 + HO2", - "from": "jch2o_a" - }, - { - "to": "jnoa", - "__reaction": "NOA + hv -> NO2 + CH2O + CH3CO3", - "from": "jch2o_a" - }, - { - "to": "jnterpooh", - "__reaction": "NTERPOOH + hv -> TERPROD1 + NO2 + OH", - "from": "jch3ooh" - }, - { - "to": "jphenooh", - "__reaction": "PHENOOH + hv -> OH + HO2 + 0.7*GLYOXAL", - "from": "jch3ooh" - }, - { - "to": "jtepomuc", - "__reaction": "TEPOMUC + hv -> 0.5*CH3CO3 + HO2 + 1.5*CO", - "from": "jno2", - "scale by": 0.1 - }, - { - "to": "jterp2ooh", - "__reaction": "TERP2OOH + hv -> OH + 0.375*CH2O + 0.3*CH3COCH3 + 0.25*CO + CO2 + TERPROD2 + HO2 + 0.25*GLYALD", - "from": "jch3ooh" - }, - { - "to": "jterpnit", - "__reaction": "TERPNIT + hv -> TERPROD1 + NO2 + HO2", - "from": "jch3ooh" - }, - { - "to": "jterprd1", - "__reaction": "TERPROD1 + hv -> HO2 + CO + TERPROD2", - "from": "jch3cho" - }, - { - "to": "jterprd2", - "__reaction": "TERPROD2 + hv -> 0.15*RO2 + 0.68*CH2O + 0.8*CO2 + 0.5*CH3COCH3 + 0.65*CH3CO3 + 1.2*HO2 + 1.7*CO", - "from": "jch3cho" - }, - { - "to": "jxylenooh", - "__reaction": "XYLENOOH + hv -> OH + HO2 + 0.34*GLYOXAL + 0.54*CH3COCHO + 0.06*BIGALD1 + 0.2*BIGALD2 + 0.15*BIGALD3 + 0.21*BIGALD4", - "from": "jch3ooh" - }, - { - "to": "jxylolooh", - "__reaction": "XYLOLOOH + hv -> OH + 0.17*GLYOXAL + 0.51*CH3COCHO + HO2", - "from": "jch3ooh" - }, - { - "to": "jsoa1_a1", - "__reaction": "soa1_a1 + hv -> Products", - "from": "jno2", - "scale by": 0.0004 - }, - { - "to": "jsoa1_a2", - "__reaction": "soa1_a2 + hv -> Products", - "from": "jno2", - "scale by": 0.0004 - }, - { - "to": "jsoa2_a1", - "__reaction": "soa2_a1 + hv -> Products", - "from": "jno2", - "scale by": 0.0004 - }, - { - "to": "jsoa2_a2", - "__reaction": "soa2_a2 + hv -> Products", - "from": "jno2", - "scale by": 0.0004 - }, - { - "to": "jsoa3_a1", - "__reaction": "soa3_a1 + hv -> Products", - "from": "jno2", - "scale by": 0.0004 - }, - { - "to": "jsoa3_a2", - "__reaction": "soa3_a2 + hv -> Products", - "from": "jno2", - "scale by": 0.0004 - }, - { - "to": "jsoa4_a1", - "__reaction": "soa4_a1 + hv -> Products", - "from": "jno2", - "scale by": 0.0004 - }, - { - "to": "jsoa4_a2", - "__reaction": "soa4_a2 + hv -> Products", - "from": "jno2", - "scale by": 0.0004 - }, - { - "to": "jsoa5_a1", - "__reaction": "soa5_a1 + hv -> Products", - "from": "jno2", - "scale by": 0.0004 - }, - { - "to": "jsoa5_a2", - "__reaction": "soa5_a2 + hv -> Products", - "from": "jno2", - "scale by": 0.0004 - }, - { - "to": "jglyoxal", - "__reaction": "GLYOXAL + hv -> 2*CO + 2*HO2", - "from": "jmgly" - } - ] - } - } -} diff --git a/test/musica/tuvx/test_tuvx_extraterrestrial_flux.F90 b/test/musica/tuvx/test_tuvx_extraterrestrial_flux.F90 new file mode 100644 index 00000000..8a652027 --- /dev/null +++ b/test/musica/tuvx/test_tuvx_extraterrestrial_flux.F90 @@ -0,0 +1,68 @@ +program test_tuvx_extraterrestrial_flux + + use musica_ccpp_tuvx_extraterrestrial_flux + + implicit none + +#define ASSERT(x) if (.not.(x)) then; write(*,*) "Assertion failed[", __FILE__, ":", __LINE__, "]: x"; stop 1; endif +#define ASSERT_NEAR( a, b, abs_error ) if( (abs(a - b) >= abs_error) .and. (abs(a - b) /= 0.0) ) then; write(*,*) "Assertion failed[", __FILE__, ":", __LINE__, "]: a, b"; stop 1; endif + + call test_update_extraterrestrial_flux() + +contains + + subroutine test_update_extraterrestrial_flux() + use musica_util, only: error_t + use musica_tuvx_grid, only: grid_t + use musica_tuvx_profile, only: profile_t + use musica_ccpp_tuvx_wavelength_grid, only: create_wavelength_grid + use ccpp_kinds, only: kind_phys + + integer, parameter :: NUM_WAVELENGTH_BINS = 4 + integer, parameter :: NUM_PHOTOLYSIS_WAVELENGTH_GRID_SECTIONS = 8 + real, parameter :: ABS_ERROR = 1e-6 + real, parameter :: MAGNITUDE_REDUCER = 1e-15 ! Its purpose is to adjust the magnitude of the values to reduce absolute errors + real(kind_phys) :: wavelength_grid_interfaces(NUM_WAVELENGTH_BINS + 1) = & + [200.0e-9_kind_phys, 220.0e-9_kind_phys, 240.0e-9_kind_phys, 260.0e-9_kind_phys, 280.0e-9_kind_phys] ! m + real(kind_phys) :: photolysis_wavelength_grid_interfaces(NUM_PHOTOLYSIS_WAVELENGTH_GRID_SECTIONS + 1) = & + [200.0_kind_phys, 210.0_kind_phys, 220.0_kind_phys, 230.0_kind_phys, 240.0_kind_phys, & + 250.0_kind_phys, 260.0_kind_phys, 270.0_kind_phys, 280.0_kind_phys] ! nm + real(kind_phys) :: extraterrestrial_flux(NUM_PHOTOLYSIS_WAVELENGTH_GRID_SECTIONS) = & + [1.5e13_kind_phys, 1.5e13_kind_phys, 1.4e13_kind_phys, 1.4e13_kind_phys, & + 1.3e13_kind_phys, 1.2e13_kind_phys, 1.1e13_kind_phys, 1.0e13_kind_phys] + real(kind_phys) :: expected_extraterrestrial_flux_midpoints(NUM_WAVELENGTH_BINS) = & + [3.0e14_kind_phys, 2.8e14_kind_phys, 2.5e14_kind_phys, 2.1e14_kind_phys] + real(kind_phys) :: extraterrestrial_flux_midpoints(NUM_WAVELENGTH_BINS) + type(grid_t), pointer :: wavelength_grid + type(profile_t), pointer :: profile + type(error_t) :: error + character(len=512) :: errmsg + integer :: errcode + integer :: i + + wavelength_grid => create_wavelength_grid (wavelength_grid_interfaces, errmsg, errcode ) + ASSERT(errcode == 0) + ASSERT(associated(wavelength_grid)) + + profile => create_extraterrestrial_flux_profile( wavelength_grid, wavelength_grid_interfaces, errmsg, errcode ) + ASSERT(errcode == 0) + ASSERT(associated(profile)) + + call set_extraterrestrial_flux_values( profile, NUM_PHOTOLYSIS_WAVELENGTH_GRID_SECTIONS, & + photolysis_wavelength_grid_interfaces, & + extraterrestrial_flux, errmsg, errcode ) + ASSERT(errcode == 0) + + call profile%get_midpoint_values( extraterrestrial_flux_midpoints, error ) + ASSERT(error%is_success()) + + do i = 1, size(extraterrestrial_flux_midpoints) + ASSERT_NEAR(extraterrestrial_flux_midpoints(i) * MAGNITUDE_REDUCER, expected_extraterrestrial_flux_midpoints(i) * MAGNITUDE_REDUCER, ABS_ERROR) + end do + + deallocate( profile ) + deallocate( wavelength_grid ) + + end subroutine test_update_extraterrestrial_flux + +end program test_tuvx_extraterrestrial_flux \ No newline at end of file diff --git a/to_be_ccppized/ccpp_tuvx_utils.F90 b/to_be_ccppized/ccpp_tuvx_utils.F90 new file mode 100644 index 00000000..837801bc --- /dev/null +++ b/to_be_ccppized/ccpp_tuvx_utils.F90 @@ -0,0 +1,91 @@ +module ccpp_tuvx_utils + + implicit none + + private + public :: rebin, read_extraterrestrial_flux + + character(len=50), dimension(4), public :: filepath_of_extraterrestrial_flux + +contains + + !> Regrids normalized flux data to match a specified wavelength grid + !! This function is copied from CAM/src/chemistry/utils/mo_util.F90 + subroutine rebin( source_dimension, target_dimension, source_coordinates, & + target_coordinates, source, target ) + use ccpp_kinds, only: kind_phys + + integer, intent(in) :: source_dimension + integer, intent(in) :: target_dimension + real(kind_phys), intent(in) :: source_coordinates(source_dimension+1) + real(kind_phys), intent(in) :: target_coordinates(target_dimension+1) + real(kind_phys), intent(in) :: source(source_dimension) + real(kind_phys), intent(out) :: target(target_dimension) + + ! local variables + integer :: i, si, si1, sil, siu + real(kind_phys) :: y, sl, su, tl, tu + + do i = 1, target_dimension + tl = target_coordinates(i) + if( tl < source_coordinates( source_dimension + 1) ) then + do sil = 1, source_dimension + 1 + if( tl <= source_coordinates( sil ) ) then + exit + end if + end do + tu = target_coordinates( i + 1 ) + do siu = 1, source_dimension + 1 + if( tu <= source_coordinates( siu ) ) then + exit + end if + end do + y = 0._kind_phys + sil = max( sil, 2 ) + siu = min( siu, source_dimension + 1 ) + do si = sil, siu + si1 = si - 1 + sl = max( tl, source_coordinates( si1 ) ) + su = min( tu, source_coordinates( si ) ) + y = y + ( su - sl ) * source( si1 ) + end do + target(i) = y / (target_coordinates( i + 1 ) - target_coordinates( i ) ) + else + target(i) = 0._kind_phys + end if + end do + + end subroutine rebin + + !> Reads a data file to retrieve the extraterrestrial radiation flux values. + ! This function is a temporary implementation and will be replaced in + ! future versions of the code. + subroutine read_extraterrestrial_flux(num_wavelength_grid_sections, & + wavelength_grid_interfaces, extraterrestrial_flux) + use ccpp_kinds, only: kind_phys + + integer, intent(out) :: num_wavelength_grid_sections ! (count) + real(kind_phys), allocatable, intent(out) :: wavelength_grid_interfaces(:) ! nm + real(kind_phys), allocatable, intent(out) :: extraterrestrial_flux(:) ! photons cm-2 s-1 nm-1 + + filepath_of_extraterrestrial_flux(1) = 'musica_configurations/chapman/tuvx/data/profiles/solar/susim_hi.flx' + filepath_of_extraterrestrial_flux(2) = 'musica_configurations/chapman/tuvx/data/profiles/solar/atlas3_1994_317_a.dat' + filepath_of_extraterrestrial_flux(3) = 'musica_configurations/chapman/tuvx/data/profiles/solar/sao2010.solref.converted' + filepath_of_extraterrestrial_flux(4) = 'musica_configurations/chapman/tuvx/data/profiles/solar/neckel.flx' + + num_wavelength_grid_sections = 8 + + allocate(wavelength_grid_interfaces(num_wavelength_grid_sections + 1)) + allocate(extraterrestrial_flux(num_wavelength_grid_sections)) + + wavelength_grid_interfaces(:) = & + [200.0_kind_phys, 210.0_kind_phys, 220.0_kind_phys, 230.0_kind_phys, & + 240.0_kind_phys, 250.0_kind_phys, 260.0_kind_phys, 270.0_kind_phys, 280.0_kind_phys] + + extraterrestrial_flux(:) = & + [1.5e13_kind_phys, 1.5e13_kind_phys, 1.4e13_kind_phys, 1.4e13_kind_phys, & + 1.3e13_kind_phys, 1.2e13_kind_phys, 1.1e13_kind_phys, 1.0e13_kind_phys] + + end subroutine read_extraterrestrial_flux + +end module ccpp_tuvx_utils \ No newline at end of file