! Copyright 2008-2021 Earth Sciences Department, BSC-CNS
!
! This file is part of MONARCH.
!
! MONARCH is free software: you can redistribute it and/or modify
! it under the terms of the GNU General Public License as published by
! the Free Software Foundation, either version 3 of the License, or
! (at your option) any later version.
!
! MONARCH is distributed in the hope that it will be useful,
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
! GNU General Public License for more details.
!
! You should have received a copy of the GNU General Public License
! along with MONARCH. If not, see <http://www.gnu.org/licenses/>.

!> \file
!> The monarch_species_map_t object and related functions

!> Indices, scaling factors and default values required for mapping
!! PartMC-phlex species to the SOLVER_INTERNAL_STATE and vice versa
module monarch_species_map
! MONARCH always has MPI
#define MONARCH_USE_MPI

  use monarch_constants,                    only : mint, mflt, mdbl
  use monarch_util,                         only : string_t
#ifdef DO_PARTMC
  use pmc_property

  implicit none
  private

  public :: monarch_species_map_t

  !> SOLVER_INTERNAL_STATE <-> PartMC-phlex species map
  !!
  !! Instances of this type hold parameters needed to map species
  !! concentrations between PartMC-phlex and SOLVER_INTERNAL_STATE
  type monarch_species_map_t
  private
    !> Starting index for PartMC-phlex species on the SOLVER_INTERNAL_STATE
    !! tracer array
    integer(kind=mint) :: tracer_starting_id = 0
    !> Ending index for PartMC-phlex species on the SOLVER_INTERNAL_STATE
    !! tracer array
    integer(kind=mint) :: tracer_ending_id = 0
    !> Water vaopr id in PartMC-phlex
    integer(kind=mint) :: phlex_water_vapor_id
    !> Cloud water id in PartMC-phlex
    integer(kind=mint) :: phlex_cloud_water_id = 0
    !> Rain water id in PartMC-phlex
    integer(kind=mint) :: phlex_rain_water_id = 0
    !> Cloud ice id in PartMC-phlex
    integer(kind=mint) :: phlex_cloud_ice_id = 0
    !> Graupel id in PartMC-phlex
    integer(kind=mint) :: phlex_graupel_id = 0
    !> Snow id in PartMC-phlex
    integer(kind=mint) :: phlex_snow_id = 0
    !> SOLVER_INTERNAL_STATE species names
    type(string_t), allocatable :: tracer_species_names( : )
    !> SOLVER_INTERNAL_STATE species ids
    integer(kind=mint), allocatable :: map_tracer_id( : )
    !> PartMC-phlex species ids
    integer(kind=mint), allocatable :: map_phlex_id( : )
    !> Scaling to use in transfer of concentrations from
    !! SOLVER_INTERNAL_STATE to PartMC-phlex
    !! (Includes conversion for aerosol species from [kg m-3] in MONARCH to
    !!  [ug m-3] in PartMC-phlex.)
    real(kind=mdbl), allocatable :: scale_to_phlex( : )
    !> Scaling to use in transfer of concentrations from
    !! PartMC-phlex to SOLVER_INTERNAL_STATE
    !! (Includes conversion for aerosol species from [kg m-3] in MONARCH to
    !!  [ug m-3] in PartMC-phlex.)
    real(kind=mdbl), allocatable :: scale_to_tracers( : )
    !> Flag to indicate conversion from condensed-phase PartMC species to
    !! gas-phase MONARCH species [ug m-3] <-> [ppm]
    logical, allocatable :: flip_phase( : )
    !> PartMC-phlex ids for initial concentrations
    integer(kind=mint), allocatable :: init_conc_phlex_id( : )
    !> Initial species concentrations
    real(kind=mdbl), allocatable :: init_conc( : )
    !> PartMC-phlex <-> SOLVER_INERNAL_STATE species map input data
    type(property_t), pointer :: species_map_data => null( )
    !> Initial concentration data
    type(property_t), pointer :: init_conc_data => null( )
  contains
    !> Initialize the species map
    procedure :: initialize
    !> Set the boundaries for PartMC species on the tracers array
    procedure :: set_tracer_boundaries
    !> Load the species map and initial concentration data
    procedure :: load
    !> Get the index for water vapor in the phlex_state_t state array
    procedure :: get_phlex_water_vapor_id
    !> Get the index for cloud water in the phlex_state_t state array
    procedure :: get_phlex_cloud_water_id
    !> Get the index for rain water in the phlex_state_t state array
    procedure :: get_phlex_rain_water_id
    !> Get the index for cloud ice in the phlex_state_t state array
    procedure :: get_phlex_cloud_ice_id
    !> Get the index for graupel in the phlex_state_t state array
    procedure :: get_phlex_graupel_id
    !> Get the index for snow in the phlex_state_t state array
    procedure :: get_phlex_snow_id
    !> Update a phlex_state_t object based on the state of the tracers
    procedure :: update_phlex_state
    !> Update the tracers based on the state of a phlex_state_t object
    procedure :: update_tracers
    !> Determine the number of bytes required to pack the given object
    procedure :: pack_size
    !> Packs the given object in the buffer, advancing position
    procedure :: bin_pack
    !> Unpacks the given object from the buffer, advancing position
    procedure :: bin_unpack
    !> Print the species map
    procedure :: print => do_print
    !> Create the species map
    procedure, private :: create_map
    !> Load the initial concentrations
    procedure, private :: load_init_conc
    !> Finalize the map
    final :: finalize

    ! Functions for testing only
    !> Get initial concentrations for mock MONARCH model
    procedure :: get_init_conc_TEST_ONLY
    !> Get the tracer species names
    procedure :: get_tracer_species_TEST_ONLY
  end type monarch_species_map_t

  !> Constructor for the monarch_species_map_t type
  interface monarch_species_map_t
    procedure :: constructor
  end interface monarch_species_map_t

contains

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Constructor for the SOLVER_INTERNAL_STATE <-> PartMC-phlex species map
  function constructor( ) result( new_obj )

    !> New species map
    type(monarch_species_map_t), pointer :: new_obj

    ! Allocate space for the new object
    allocate( new_obj )

  end function constructor

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Set TRACER boundaries
  !! Call this from the primary process and pass the updated object to all
  !! other processes
  !! TODO Remove after pmc_interface manages its own state memory
  subroutine set_tracer_boundaries( this, starting_tracer_id,                &
      ending_tracer_id )

    use monarch_util,                       only : assert, assert_msg,       &
                                                   to_string

    !> Species map
    class(monarch_species_map_t), intent(inout) :: this
    !> Starting id on the tracer id for PartMC-phlex species
    integer(kind=mint), intent(in) :: starting_tracer_id
    !> Ending id on the tracer id for PartMC-phlex species
    integer(kind=mint), intent(in) :: ending_tracer_id

    integer(kind=mint) :: i_map

    ! Make sure the boundaries have not already been set
    call assert( 241359273, this%tracer_starting_id .eq. 0 )
    call assert( 404798631, this%tracer_ending_id .eq. 0 )

    ! Set the tracer ids
    this%tracer_starting_id = starting_tracer_id
    this%tracer_ending_id   = ending_tracer_id

    ! Loop through and update tracer ids
    do i_map = 1, size( this%map_tracer_id )
      this%map_tracer_id( i_map ) = this%map_tracer_id( i_map ) +            &
              this%tracer_starting_id - 1
      call assert_msg( 450258014,                                            &
              this%map_tracer_id( i_map ) .le. this%tracer_ending_id .and.   &
              this%map_tracer_id( i_map ) .ge. this%tracer_starting_id,      &
              "Monarch id for species '"//                                   &
              this%tracer_species_names( i_map )%string//                    &
              "' out of specified tracer array bounds. Specified index:"//   &
              to_string( this%map_tracer_id( i_map ) )//                     &
              " in range: "//to_string( this%tracer_starting_id )//          &
              " to "//to_string( this%tracer_ending_id ) )
    end do

  end subroutine set_tracer_boundaries

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Initialize the species map
  subroutine initialize( this, phlex_core )

    use pmc_phlex_core,                     only : phlex_core_t

    !> Species map
    class(monarch_species_map_t), intent(inout) :: this
    !> Phlex core
    type(phlex_core_t), intent(in) :: phlex_core

    call this%create_map( phlex_core )
    call this%load_init_conc( phlex_core )

  end subroutine initialize

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Load species map and initial concentration data
  subroutine load( this, species_map_data, init_conc_data )

    !> Species map
    class(monarch_species_map_t), intent(inout) :: this
    !> Species map data
    type(property_t), pointer, intent(inout) :: species_map_data
    !> Initial concentration data
    type(property_t), pointer, intent(inout) :: init_conc_data

    this%species_map_data => species_map_data
    this%init_conc_data   => init_conc_data

  end subroutine load

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Get the index for water vapor in the phlex_state_t state array
  pure function get_phlex_water_vapor_id( this ) result( water_vapor_id )

    !> Index for water vapor on the phlex_state_t state array
    integer(kind=mint) :: water_vapor_id
    !> Species map
    class(monarch_species_map_t), intent(in) :: this

    water_vapor_id = this%phlex_water_vapor_id

  end function get_phlex_water_vapor_id

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Get the index for cloud water in the phlex_state_t state array.
  !! Returns zero if no cloud water species was included in the interface
  !! input data.
  pure function get_phlex_cloud_water_id( this ) result( cloud_water_id )

    !> Index for cloud water on the phlex_state_t state array
    integer(kind=mint) :: cloud_water_id
    !> Species map
    class(monarch_species_map_t), intent(in) :: this

    cloud_water_id = this%phlex_cloud_water_id

  end function get_phlex_cloud_water_id

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Get the index for rain water in the phlex_state_t state array.
  !! Returns zero if no rain water species was included in the interface
  !! input data.
  pure function get_phlex_rain_water_id( this ) result( rain_water_id )

    !> Index for rain water on the phlex_state_t state array
    integer(kind=mint) :: rain_water_id
    !> Species map
    class(monarch_species_map_t), intent(in) :: this

    rain_water_id = this%phlex_rain_water_id

  end function get_phlex_rain_water_id

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Get the index for cloud ice in the phlex_state_t state array.
  !! Returns zero if no cloud ice species was included in the interface
  !! input data.
  pure function get_phlex_cloud_ice_id( this ) result( cloud_ice_id )

    !> Index for cloud ice on the phlex_state_t state array
    integer(kind=mint) :: cloud_ice_id
    !> Species map
    class(monarch_species_map_t), intent(in) :: this

    cloud_ice_id = this%phlex_cloud_ice_id

  end function get_phlex_cloud_ice_id

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Get the index for graupel in the phlex_state_t state array.
  !! Returns zero if no graupel species was included in the interface input
  !! data.
  pure function get_phlex_graupel_id( this ) result( graupel_id )

    !> Index for graupel on the phlex_state_t state array
    integer(kind=mint) :: graupel_id
    !> Species map
    class(monarch_species_map_t), intent(in) :: this

    graupel_id = this%phlex_graupel_id

  end function get_phlex_graupel_id

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Get the index for snow in the phlex_state_t state array.
  !! Returns zero if no snow species was included in the interface input data.
  pure function get_phlex_snow_id( this ) result( snow_id )

    !> Index for snow on the phlex_state_t state array
    integer(kind=mint) :: snow_id
    !> Species map
    class(monarch_species_map_t), intent(in) :: this

    snow_id = this%phlex_snow_id

  end function get_phlex_snow_id

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Update a phlex_state_t object based on the state of the tracers
  subroutine update_phlex_state( this, phlex_state, tracers,                 &
      number_density_air__molm3 )

    use pmc_phlex_state,                    only : phlex_state_t

    !> Species map
    class(monarch_species_map_t), intent(in) :: this
    !> The phlex state to update
    class(phlex_state_t), intent(inout) :: phlex_state
    !> The tracer array slice
    real(kind=mflt), intent(in) :: tracers(:)
    !> Number density of air [mol m-3] for species that flip phase in        &
    !! conversion
    real(kind=mdbl), intent(in) :: number_density_air__molm3

    real(kind=mdbl) :: flip_conversion
    integer(kind=mint) :: i_spec

    ! Reset the phlex-state concentrations to initial conditions
    ! (Initial conditions should just be for constants and other species not
    !  in the SOLVER_INTERNAL_STATE)
    phlex_state%state_var( : ) = 0.0
    phlex_state%state_var( this%init_conc_phlex_id( : )  ) =                 &
        this%init_conc( : )

    ! Then add scaled MONARCH concentrations
    ! (scaling can be for, for example, splitting a single
    !    MONARCH species, like sulfate, into several PMC species, like
    !    SO4mm, HSO4m, H2SO4_aq, and Hp, at a constant ratio.)
    ! (loop through species to update because some species are mapped
    !    multiple times)
    do i_spec = 1, size( this%map_phlex_id )
      if( this%flip_phase( i_spec ) ) then
        flip_conversion = number_density_air__molm3
      else
        flip_conversion = 1.0
      end if
      phlex_state%state_var( this%map_phlex_id( i_spec )  )    =             &
          phlex_state%state_var( this%map_phlex_id( i_spec ) ) +             &
          tracers( this%map_tracer_id( i_spec ) )              *             &
          this%scale_to_phlex( i_spec )                        *             &
          flip_conversion
    end do

  end subroutine update_phlex_state

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Update the tracers based on the state of a phlex_state_t object
  subroutine update_tracers( this, phlex_state, tracers,                     &
      number_density_air__molm3 )

    use pmc_phlex_state,                    only : phlex_state_t

    !> Species map
    class(monarch_species_map_t), intent(in) :: this
    !> The phlex state
    class(phlex_state_t), intent(in) :: phlex_state
    !> The tracer array slice to update
    real(kind=mflt), intent(inout) :: tracers(:)
    !> Number density of air [mol m-3] for species that flip phase in
    !! conversion
    real(kind=mdbl), intent(in) :: number_density_air__molm3

    real(kind=mdbl) :: flip_conversion
    integer(kind=mint) :: i_spec

    ! Reset the tracer species concentrations
    tracers( this%map_tracer_id( : ) ) = 0.0

    ! Loop through the map updating the tracer concentrations
    do i_spec = 1, size( this%map_phlex_id )
      if( this%flip_phase( i_spec ) ) then
        flip_conversion = 1.0 / number_density_air__molm3
      else
        flip_conversion = 1.0
      end if
      tracers( this%map_tracer_id( i_spec ) )                  =             &
          tracers( this%map_tracer_id( i_spec ) )              +             &
          phlex_state%state_var( this%map_phlex_id( i_spec ) ) *             &
          this%scale_to_tracers( i_spec )                      *             &
          flip_conversion
    end do

  end subroutine update_tracers

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Determine the size of a binary required to pack the species map
  integer(kind=mint)function pack_size( this, comm )

    use monarch_mpi,                only : mnrc_mpi_pack_size_integer,       &
                                           mnrc_mpi_pack_size_integer_array, &
                                           mnrc_mpi_pack_size_logical_array, &
                                           mnrc_mpi_pack_size_double_array

    !> Species map
    class(monarch_species_map_t), intent(in) :: this
    !> MPI communicator
    integer(kind=mint), intent(in) :: comm

    pack_size =                                                              &
        mnrc_mpi_pack_size_integer( this%tracer_starting_id      , comm )  + &
        mnrc_mpi_pack_size_integer( this%tracer_ending_id        , comm )  + &
        mnrc_mpi_pack_size_integer( this%phlex_water_vapor_id    , comm )  + &
        mnrc_mpi_pack_size_integer( this%phlex_cloud_water_id    , comm )  + &
        mnrc_mpi_pack_size_integer( this%phlex_rain_water_id     , comm )  + &
        mnrc_mpi_pack_size_integer( this%phlex_cloud_ice_id      , comm )  + &
        mnrc_mpi_pack_size_integer( this%phlex_graupel_id        , comm )  + &
        mnrc_mpi_pack_size_integer( this%phlex_snow_id           , comm )  + &
        mnrc_mpi_pack_size_integer_array( this%map_tracer_id     , comm )  + &
        mnrc_mpi_pack_size_integer_array( this%map_phlex_id      , comm )  + &
        mnrc_mpi_pack_size_double_array(  this%scale_to_phlex    , comm )  + &
        mnrc_mpi_pack_size_double_array(  this%scale_to_tracers  , comm )  + &
        mnrc_mpi_pack_size_logical_array( this%flip_phase        , comm )  + &
        mnrc_mpi_pack_size_integer_array( this%init_conc_phlex_id, comm )  + &
        mnrc_mpi_pack_size_double_array(  this%init_conc         , comm )

  end function pack_size

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Pack the given object to the buffer, advancing position
  subroutine bin_pack( this, buffer, pos, comm )
#ifdef MONARCH_USE_MPI
    use monarch_mpi,                 only : mnrc_mpi_pack_integer,           &
                                            mnrc_mpi_pack_integer_array,     &
                                            mnrc_mpi_pack_logical_array,     &
                                            mnrc_mpi_pack_double_array
    use monarch_util,                only : assert
#endif

    !> Species map
    class(monarch_species_map_t), intent(in) :: this
    !> Memory buffer
    character, intent(inout) :: buffer( : )
    !> Current buffer position
    integer(kind=mint), intent(inout) :: pos
    !> MPI communicator
    integer(kind=mint), intent(in) :: comm

#ifdef MONARCH_USE_MPI
    integer(kind=mint) :: prev_position

    prev_position = pos
    call mnrc_mpi_pack_integer( buffer, pos, this%tracer_starting_id  , comm )
    call mnrc_mpi_pack_integer( buffer, pos, this%tracer_ending_id    , comm )
    call mnrc_mpi_pack_integer( buffer, pos, this%phlex_water_vapor_id, comm )
    call mnrc_mpi_pack_integer( buffer, pos, this%phlex_cloud_water_id, comm )
    call mnrc_mpi_pack_integer( buffer, pos, this%phlex_rain_water_id , comm )
    call mnrc_mpi_pack_integer( buffer, pos, this%phlex_cloud_ice_id  , comm )
    call mnrc_mpi_pack_integer( buffer, pos, this%phlex_graupel_id    , comm )
    call mnrc_mpi_pack_integer( buffer, pos, this%phlex_snow_id       , comm )
    call mnrc_mpi_pack_integer_array( buffer, pos, this%map_tracer_id , comm )
    call mnrc_mpi_pack_integer_array( buffer, pos, this%map_phlex_id  , comm )
    call mnrc_mpi_pack_double_array(  buffer, pos, this%scale_to_phlex, comm )
    call mnrc_mpi_pack_double_array(  buffer, pos, this%scale_to_tracers,    &
                                                                        comm )
    call mnrc_mpi_pack_logical_array( buffer, pos, this%flip_phase,     comm )
    call mnrc_mpi_pack_integer_array( buffer, pos, this%init_conc_phlex_id,  &
                                                                        comm )
    call mnrc_mpi_pack_double_array(  buffer, pos, this%init_conc     , comm )
    call assert( 853728922, &
         pos - prev_position <= this%pack_size( comm ) )

#endif

  end subroutine bin_pack

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Unpack the given object to the buffer, advancing position
  subroutine bin_unpack( this, buffer, pos, comm )
#ifdef MONARCH_USE_MPI
    use monarch_mpi,                 only : mnrc_mpi_unpack_integer,         &
                                            mnrc_mpi_unpack_integer_array,   &
                                            mnrc_mpi_unpack_logical_array,   &
                                            mnrc_mpi_unpack_double_array
    use monarch_util,                only : assert
#endif

    !> Species map
    class(monarch_species_map_t), intent(inout) :: this
    !> Memory buffer
    character, intent(inout) :: buffer( : )
    !> Current buffer position
    integer(kind=mint), intent(inout) :: pos
    !> MPI communicator
    integer(kind=mint), intent(in) :: comm

#ifdef MONARCH_USE_MPI
    integer(kind=mint) :: prev_position

    prev_position = pos
    call mnrc_mpi_unpack_integer( buffer, pos, this%tracer_starting_id, comm )
    call mnrc_mpi_unpack_integer( buffer, pos, this%tracer_ending_id  , comm )
    call mnrc_mpi_unpack_integer( buffer, pos, this%phlex_water_vapor_id,    &
                                                                        comm )
    call mnrc_mpi_unpack_integer( buffer, pos, this%phlex_cloud_water_id,    &
                                                                        comm )
    call mnrc_mpi_unpack_integer( buffer, pos, this%phlex_rain_water_id,comm )
    call mnrc_mpi_unpack_integer( buffer, pos, this%phlex_cloud_ice_id, comm )
    call mnrc_mpi_unpack_integer( buffer, pos, this%phlex_graupel_id  , comm )
    call mnrc_mpi_unpack_integer( buffer, pos, this%phlex_snow_id     , comm )
    call mnrc_mpi_unpack_integer_array(buffer, pos, this%map_tracer_id, comm )
    call mnrc_mpi_unpack_integer_array(buffer, pos, this%map_phlex_id , comm )
    call mnrc_mpi_unpack_double_array( buffer, pos, this%scale_to_phlex,comm )
    call mnrc_mpi_unpack_double_array( buffer, pos, this%scale_to_tracers,   &
                                                                        comm )
    call mnrc_mpi_unpack_logical_array( buffer, pos, this%flip_phase,   comm )
    call mnrc_mpi_unpack_integer_array(buffer, pos, this%init_conc_phlex_id, &
                                                                        comm )
    call mnrc_mpi_unpack_double_array( buffer, pos, this%init_conc    , comm )
    call assert( 389567211, &
         pos - prev_position <= this%pack_size( comm ) )
#endif

  end subroutine bin_unpack

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Print the species mapping data
  subroutine do_print( this, file_unit )

    !> Species map
    class(monarch_species_map_t), intent(in) :: this
    !> File unit to print to
    integer(kind=mint), intent(in) :: file_unit

    integer(kind=mint) :: i_spec
    character(len=*), parameter :: fmt_blank_line = "('')"
    character(len=*), parameter :: fmt1 = "(1x,'| ',A16,' | ',A9,' | ',A6"// &
                                        ",' | ',A16,' | ',A13,' | ',A11,' |')"
    character(len=*), parameter :: fmt2 = "(1x,'| ',A16,' | ',I9,' | ',I6"// &
                                        ",' | ',3x,ES13.3,' | ',ES13.3,"//   &
                                        "' | ',L11,' |')"
    character(len=*), parameter :: fmt3 = "(1x,'| ',A6,' | ',A21,' |')"
    character(len=*), parameter :: fmt4 = "(1x,'| ',I6,' | ',8x,ES13.3,' |')"

    write(file_unit,fmt_blank_line)
    write(file_unit,*) "******************************************"
    write(file_unit,*) "** TRACERS <-> PartMC-Phlex Species Map **"
    write(file_unit,*) "******************************************"
    write(file_unit,fmt_blank_line)
    write(file_unit,*) "Starting tracer id:         ",                       &
                       this%tracer_starting_id
    write(file_unit,*) "Ending tracer id:           ",                       &
                       this%tracer_ending_id
    write(file_unit,*) "PartMC-phlex water vapor id:",                       &
                       this%phlex_water_vapor_id
    write(file_unit,*) "PartMC-phlex cloud water id:",                       &
                       this%phlex_cloud_water_id
    write(file_unit,*) "PartMC-phlex rain water id: ",                       &
                       this%phlex_rain_water_id
    write(file_unit,*) "PartMC-phlex cloud ice id:  ",                       &
                       this%phlex_cloud_ice_id
    write(file_unit,*) "PartMC-phlex graupel id:    ",                       &
                       this%phlex_graupel_id
    write(file_unit,*) "PartMC-phlex snow id:       ",                       &
                       this%phlex_snow_id
    write(file_unit,fmt_blank_line)
    write(file_unit,*) "*** TRACERS <-> PartMC-phlex Map ***"
    write(file_unit,fmt1) "Species name", "tracer id", "PMC id",             &
                          "scale to tracers", "scale to PMC", "flip phase"
    if( allocated( this%tracer_species_names ) ) then
      do i_spec = 1, size( this%tracer_species_names )
        write(file_unit,fmt2) this%tracer_species_names( i_spec ) %string,   &
                   this%map_tracer_id( i_spec ),                             &
                   this%map_phlex_id( i_spec ),                              &
                   this%scale_to_tracers( i_spec ),                          &
                   this%scale_to_phlex( i_spec ),                            &
                   this%flip_phase( i_spec )
      end do
    end if
    write(file_unit,fmt_blank_line)
    write(file_unit,*) "*** Initial concentrations ***"
    write(file_unit,fmt3) "PMC id", "Initial concentration"
    if( allocated( this%init_conc_phlex_id ) ) then
      do i_spec = 1, size( this%init_conc_phlex_id )
        write(file_unit,fmt4) this%init_conc_phlex_id( i_spec ),             &
                              this%init_conc( i_spec )
      end do
    end if
    write(file_unit,fmt_blank_line)
    write(file_unit,*) "*** TRACERS <-> PartMC-phlex map input data ***"
    call this%species_map_data%print( file_unit )
    write(file_unit,fmt_blank_line)
    write(file_unit,*) "*** Initial concentration input data ***"
    call this%init_conc_data%print( file_unit )
    write(file_unit,fmt_blank_line)
    write(file_unit,*) "**********************************************"
    write(file_unit,*) "** End TRACERS <-> PartMC-Phlex Species Map **"
    write(file_unit,*) "**********************************************"
    write(file_unit,fmt_blank_line)

  end subroutine do_print

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Create the PartMC-phlex <-> SOLVER_INTERNAL_STATE species map
  subroutine create_map( this, phlex_core )

    use pmc_aero_rep_data,                  only : aero_rep_data_t
    use pmc_chem_spec_data,                 only : chem_spec_data_t
    use pmc_phlex_core,                     only : phlex_core_t
    use monarch_util,                       only : assert_msg

    !> Species map
    class(monarch_species_map_t), intent(inout) :: this
    !> Phlex core
    type(phlex_core_t), intent(in) :: phlex_core

    type(chem_spec_data_t), pointer :: chem_spec_data
    class(aero_rep_data_t), pointer :: aero_rep_ptr
    type(property_t), pointer :: gas_species_list, aero_species_list,        &
                                 species_data, pmc_spec_props
    character(len=:), allocatable :: key_name, spec_name, rep_name,          &
                                     gen_spec_name
    integer(kind=mint) :: i_spec, num_spec
    real(kind=mdbl) :: scale_factor, molec_weight
    logical :: flip_phase

    ! Get the gas-phase species ids
    key_name = "gas-phase species"
    call assert_msg( 939097252, &
            this%species_map_data%get_property_t( key_name,                  &
                                                  gas_species_list ),        &
            "Missing set of gas-phase species MONARCH ids" )
    num_spec = gas_species_list%size( )

    ! Get the aerosol-phase species ids
    key_name = "aerosol-phase species"
    if( this%species_map_data%get_property_t( key_name,                      &
                                              aero_species_list ) ) then
      num_spec = num_spec + aero_species_list%size( )
    end if

    ! Set up the species map and MONARCH names array
    allocate( this%tracer_species_names( num_spec ) )
    allocate( this%map_tracer_id(        num_spec ) )
    allocate( this%map_phlex_id(         num_spec ) )
    allocate( this%scale_to_phlex(       num_spec ) )
    allocate( this%scale_to_tracers(     num_spec ) )
    allocate( this%flip_phase(           num_spec ) )

    ! Assume no concentration scaling or phase flipping, unless specified in
    ! the input data
    this%scale_to_phlex( : )   = real( 1.0, kind=mdbl )
    this%scale_to_tracers( : ) = real( 1.0, kind=mdbl )
    this%flip_phase( : )       = .false.

    ! Get the chemical species data
    call assert_msg( 731700229,                                              &
            phlex_core%get_chem_spec_data( chem_spec_data ),                 &
            "No chemical species data in phlex_core." )

    ! Set the gas-phase water id
    key_name = "gas-phase water"
    call assert_msg( 413656652,                                              &
            this%species_map_data%get_string( key_name, spec_name ),         &
            "Missing gas-phase water species for MONARCH interface." )
    this%phlex_water_vapor_id = chem_spec_data%gas_state_id( spec_name )
    call assert_msg( 910692272, this%phlex_water_vapor_id.gt.0,              &
            "Could not find gas-phase water species '"//spec_name//"'." )

    ! Get the cloud water id, if one exists
    key_name = "cloud water"
    if( this%species_map_data%get_property_t( key_name, species_data ) ) then
      this%phlex_cloud_water_id =                                            &
          get_phlex_bulk_water_spec_id( phlex_core, species_data )
    end if

    ! Get the rain water id, if one exists
    key_name = "rain water"
    if( this%species_map_data%get_property_t( key_name, species_data ) ) then
      this%phlex_rain_water_id =                                             &
          get_phlex_bulk_water_spec_id( phlex_core, species_data )
    end if

    ! Get the cloud ice id, if one exists
    key_name = "cloud ice"
    if( this%species_map_data%get_property_t( key_name, species_data ) ) then
      this%phlex_cloud_ice_id =                                              &
          get_phlex_bulk_water_spec_id( phlex_core, species_data )
    end if

    ! Get the graupel id, if one exists
    key_name = "graupel"
    if( this%species_map_data%get_property_t( key_name, species_data ) ) then
      this%phlex_graupel_id =                                                &
          get_phlex_bulk_water_spec_id( phlex_core, species_data )
    end if

    ! Get the snow id, if one exists
    key_name = "snow"
    if( this%species_map_data%get_property_t( key_name, species_data ) ) then
      this%phlex_snow_id =                                                   &
          get_phlex_bulk_water_spec_id( phlex_core, species_data )
    end if

    ! Loop through the gas-phase species and set up the map
    call gas_species_list%iter_reset( )
    i_spec = 1
    do while( gas_species_list%get_key( spec_name ) )

      this%tracer_species_names( i_spec )%string = spec_name

      call assert_msg( 599522862,                                            &
              gas_species_list%get_property_t( val=species_data ),           &
              "Missing species data for '"//spec_name//"' in PartMC-phlex "//&
              "<-> MONARCH species map." )

      key_name = "monarch id"
      call assert_msg( 643926329,                                            &
              species_data%get_int( key_name, this%map_tracer_id( i_spec ) ),&
              "Missing monarch id for species '"//spec_name//" in "//        &
              "PartMC-phlex <-> MONARCH species map." )

      this%map_phlex_id( i_spec ) = chem_spec_data%gas_state_id( spec_name )
      call assert_msg( 916977002, this%map_phlex_id( i_spec ) .gt.0,         &
                "Could not find species '"//spec_name//"' in PartMC-phlex." )

      ! Check for scaling factors
      key_name = "scale to PMC"
      if( species_data%get_real( key_name, scale_factor ) ) then
        this%scale_to_phlex( i_spec ) = scale_factor
      end if

      key_name = "scale to MONARCH"
      if( species_data%get_real( key_name, scale_factor ) ) then
        this%scale_to_tracers( i_spec ) = scale_factor
      end if

      call gas_species_list%iter_next( )
      i_spec = i_spec + 1
    end do

    ! Loop through the aerosol-phase species and add them to the map
    if( associated( aero_species_list ) ) then

      call aero_species_list%iter_reset( )
      do while( aero_species_list%get_key( spec_name ) )

        this%tracer_species_names( i_spec ) %string = spec_name

        call assert_msg( 567689501,                                          &
                aero_species_list%get_property_t( val=species_data ),        &
                "Missing species data for '"//spec_name//"' in " //          &
                "PartMC-phlex <-> MONARCH species map." )

        key_name = "monarch id"
        call assert_msg( 615451741,                                          &
                species_data%get_int( key_name,                              &
                                      this%map_tracer_id( i_spec ) ),        &
                "Missing monarch id for species '"//spec_name//"' in "//     &
                "PartMC-phlex <-> MONARCH species map." )

        ! Get the PartMC-phlex aerosol representation name
        key_name = "aerosol representation name"
        call assert_msg( 963222513,                                          &
                species_data%get_string( key_name, rep_name ),               &
                "Missing aerosol representation name for species '"//        &
                spec_name//"' in PartMC-phlex <-> MONARCH species map." )

        ! Get the PartMC-phlex id
        this%map_phlex_id( i_spec ) = get_phlex_aero_species_id( phlex_core, &
                                         spec_name, rep_name )

        ! Check for scaling factors
        key_name = "scale to PMC"
        if( species_data%get_real( key_name, scale_factor ) ) then
          this%scale_to_phlex( i_spec ) = scale_factor
        end if

        key_name = "scale to MONARCH"
        if( species_data%get_real( key_name, scale_factor ) ) then
          this%scale_to_tracers( i_spec ) = scale_factor
        end if

        ! Incorporate the conversion from [kg m-3] in MONARCH to [ug m-3] in
        ! PartMC-phlex
        this%scale_to_phlex( i_spec )   =                                    &
            this%scale_to_phlex( i_spec ) * 1.0d9
        this%scale_to_tracers( i_spec ) =                                    &
            this%scale_to_tracers( i_spec ) * 1.0e-9

        key_name = "flip phase"
        if( species_data%get_logical( key_name, flip_phase ) ) then
          this%flip_phase( i_spec ) = flip_phase
        end if

        ! Get the MW for phase flips and include it in the scaling factor
        if( this%flip_phase( i_spec ) ) then

          ! Find the aerosol representation
          call assert_msg( 241132181,                                        &
            phlex_core%get_aero_rep( rep_name, aero_rep_ptr ),               &
            "Could not find aerosol representation '"//rep_name//"'" )

          ! Get the generic species name
          gen_spec_name = aero_rep_ptr%spec_name( spec_name )
          call assert_msg( 802723906, allocated( gen_spec_name ) .and.       &
                           len( gen_spec_name ) .gt. 0,                      &
                           "Error finding generic name for species '"//      &
                           spec_name//"' in aerosol representation '"//      &
                           rep_name//"'" )

          call assert_msg( 575886535, chem_spec_data%get_property_set(       &
                                            gen_spec_name, pmc_spec_props ), &
                           "Missing property set in PartMC for phase-flip "//&
                           "species '"//gen_spec_name//"'" )

          key_name = "molecular weight [kg mol-1]"
          call assert_msg( 150863984, pmc_spec_props%get_real( key_name,     &
                                                             molec_weight ), &
                           "Missing property '"//key_name//"' for phase-"//  &
                           "flip species '"//spec_name//"'" )
          this%scale_to_phlex( i_spec )   =                                  &
              this%scale_to_phlex( i_spec ) * molec_weight * 1.0e-6
          this%scale_to_tracers( i_spec ) =                                  &
              this%scale_to_tracers( i_spec ) / molec_weight * 1.0e6
        end if

        call aero_species_list%iter_next( )
        i_spec = i_spec + 1
      end do
    end if

  end subroutine create_map

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Get a bulk water species id from PartMC-phlex
  function get_phlex_bulk_water_spec_id( phlex_core, species_props )         &
      result( spec_id )

    use pmc_phlex_core,                     only : phlex_core_t
    use monarch_util,                       only : assert_msg

    !> Species id in the phlex_state_t state array
    integer(kind=mint) :: spec_id
    !> Phlex core
    type(phlex_core_t), intent(in) :: phlex_core
    !> Species properties
    type(property_t), intent(in) :: species_props

    character(len=:), allocatable :: key_name, spec_name, rep_name

    ! Get the unique name in PartMC-phlex for the species
    key_name = "name"
    call assert_msg( 331869051,                                              &
            species_props%get_string( key_name, spec_name ),                 &
            "Missing species name for bulk water species map." )

    ! Get the PartMC-phlex aerosol representation name
    key_name = "aerosol representation name"
    call assert_msg( 173694000,                                              &
            species_props%get_string( key_name, rep_name ),                  &
            "Missing aerosol representation name for species '"//            &
            spec_name//"' in PartMC-phlex <-> MONARCH species map." )

    ! Get the PartMC-phlex id
    spec_id = get_phlex_aero_species_id( phlex_core, spec_name, rep_name )

  end function get_phlex_bulk_water_spec_id

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Get an aerosol-phase species id from PartMC-phlex
  function get_phlex_aero_species_id( phlex_core, spec_name, rep_name )      &
      result( spec_id )

    use pmc_aero_rep_data,                  only : aero_rep_data_t
    use pmc_phlex_core,                     only : phlex_core_t
    use monarch_util,                       only : assert_msg

    !> Species id in the phlex_state_t state array
    integer(kind=mint) :: spec_id
    !> Phlex core
    type(phlex_core_t), intent(in) :: phlex_core
    !> Aerosol species unique name
    character(len=:), allocatable, intent(in) :: spec_name
    !> Aerosol representation name
    character(len=:), allocatable, intent(in) :: rep_name

    class(aero_rep_data_t), pointer :: aero_rep_ptr

    ! Find the aerosol representation
    call assert_msg( 377850668,                                              &
            phlex_core%get_aero_rep( rep_name, aero_rep_ptr ),               &
            "Could not find aerosol representation '"//rep_name//"'" )

    ! Find the species id
    spec_id = 0
    spec_id = aero_rep_ptr%spec_state_id( spec_name )

    ! Make sure the species exists
    call assert_msg( 887136850, spec_id .gt. 0,                              &
                "Could not find aerosol species '"//spec_name//"' in "//     &
                "aerosol representation '"//rep_name//"'." )

  end function get_phlex_aero_species_id

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Load initial concentrations
  subroutine load_init_conc( this, phlex_core )

    use pmc_aero_rep_data,                  only : aero_rep_data_t
    use pmc_chem_spec_data,                 only : chem_spec_data_t
    use pmc_phlex_core,                     only : phlex_core_t
    use monarch_util,                       only : assert_msg

    !> Species map
    class(monarch_species_map_t) :: this
    !> Phlex core
    type(phlex_core_t), intent(in) :: phlex_core

    type(chem_spec_data_t), pointer :: chem_spec_data
    class(aero_rep_data_t), pointer :: aero_rep_ptr
    type(property_t), pointer :: gas_species_list, aero_species_list,        &
                                 species_data
    character(len=:), allocatable :: key_name, spec_name, rep_name
    integer(kind=mint) :: i_spec, num_spec

    num_spec = 0

    ! Get the gas-phase species
    key_name = "gas-phase species"
    if( this%init_conc_data%get_property_t( key_name,                        &
                                            gas_species_list ) ) then
      num_spec = num_spec + gas_species_list%size( )
    end if

    ! Get the aerosol-phase species
    key_name = "aerosol-phase species"
    if( this%init_conc_data%get_property_t( key_name,                        &
                                            aero_species_list ) ) then
      num_spec = num_spec + aero_species_list%size( )
    end if

    ! Get the chemical species data
    call assert_msg( 885063268,                                              &
            phlex_core%get_chem_spec_data( chem_spec_data ),                 &
            "No chemical species data in phlex_core." )

    ! Allocate space for the initial concentrations and indices
    allocate( this%init_conc_phlex_id( num_spec ) )
    allocate( this%init_conc( num_spec ) )

    ! Add the gas-phase initial concentrations
    if( associated( gas_species_list ) ) then

      ! Loop through the gas-phase species and load the initial concentrations
      call gas_species_list%iter_reset( )
      i_spec = 1
      do while( gas_species_list%get_key( spec_name ) )

        call assert_msg( 325582312,                                          &
                gas_species_list%get_property_t( val=species_data ),         &
                "Missing species data for '"//spec_name//"' for "//          &
                "PartMC-phlex initial concentrations." )

        key_name = "init conc"
        call assert_msg( 445070498,                                          &
                species_data%get_real( key_name, this%init_conc( i_spec ) ), &
                "Missing 'init conc' for species '"//spec_name//" for "//    &
                "PartMC-phlex initial concentrations." )

        this%init_conc_phlex_id( i_spec ) =                                  &
                chem_spec_data%gas_state_id( spec_name )
        call assert_msg( 940200584, this%init_conc_phlex_id( i_spec ) .gt.0, &
                "Could not find species '"//spec_name//"' in PartMC-phlex." )

        call gas_species_list%iter_next( )
        i_spec = i_spec + 1
      end do

    end if

    ! Add the aerosol-phase species initial concentrations
    if( associated( aero_species_list ) ) then

      call aero_species_list%iter_reset( )
      do while( aero_species_list%get_key( spec_name ) )

        call assert_msg( 331096555,                                          &
                aero_species_list%get_property_t( val=species_data ),        &
                "Missing species data for '"//spec_name//"' for " //         &
                "PartMC-phlex initial concentrations." )

        key_name = "init conc"
        call assert_msg( 782275469,                                          &
                species_data%get_real( key_name, this%init_conc( i_spec ) ), &
                "Missing 'init conc' for species '"//spec_name//"' for "//   &
                "PartMC-phlex initial concentrations." )

        key_name = "aerosol representation name"
        call assert_msg( 150863332,                                          &
                species_data%get_string( key_name, rep_name ),               &
                "Missing aerosol representation name for species '"//        &
                spec_name//"' for PartMC-phlex initial concentrations." )

        ! Find the species PartMC id
        this%init_conc_phlex_id( i_spec ) = 0
        call assert_msg( 258814777,                                          &
                phlex_core%get_aero_rep( rep_name, aero_rep_ptr ),           &
                "Could not find aerosol representation '"//rep_name//"'" )
        this%init_conc_phlex_id( i_spec ) =                                  &
                aero_rep_ptr%spec_state_id( spec_name )
        call assert_msg( 437149649, this%init_conc_phlex_id( i_spec ) .gt. 0,&
                "Could not find aerosol species '"//spec_name//"' in "//     &
                "aerosol representation '"//rep_name//"'." )

        call aero_species_list%iter_next( )
        i_spec = i_spec + 1
      end do
    end if

  end subroutine load_init_conc

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Finalize a monarch_species_map_t object
  elemental subroutine finalize( this )

    !> PartMC-phlex <-> MONARCH species map
    type(monarch_species_map_t), intent(inout) :: this

    if( allocated( this%tracer_species_names ) ) &
        deallocate( this%tracer_species_names  )
    if( allocated( this%map_tracer_id        ) ) &
        deallocate( this%map_tracer_id         )
    if( allocated( this%map_phlex_id         ) ) &
        deallocate( this%map_phlex_id          )
    if( allocated( this%scale_to_phlex       ) ) &
        deallocate( this%scale_to_phlex        )
    if( allocated( this%scale_to_tracers     ) ) &
        deallocate( this%scale_to_tracers      )
    if( allocated( this%init_conc_phlex_id   ) ) &
        deallocate( this%init_conc_phlex_id    )
    if( allocated( this%init_conc            ) ) &
        deallocate( this%init_conc             )
    if( associated( this%species_map_data    ) ) &
        deallocate( this%species_map_data      )
    if( associated( this%init_conc_data      ) ) &
        deallocate( this%init_conc_data        )

  end subroutine finalize

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Get initial concentrations for the mock MONARCH model (for testing only)
  subroutine get_init_conc_TEST_ONLY( this, phlex_state, tracer_conc,        &
      tracer_water_conc, WATER_VAPOR_ID, tracer_air_density )

    use pmc_phlex_state,                    only : phlex_state_t

    !> PartMC-phlex <-> tracer species map
    class(monarch_species_map_t) :: this
    !> PartMC-phlex state to update
    type(phlex_state_t), intent(inout) :: phlex_state
    !> tracer species concentrations to update
    real, intent(inout) :: tracer_conc( :,:,:,: )
    !> Atmospheric water concentrations [kg_H2O kg_air-1]
    real, intent(out) :: tracer_water_conc( :,:,:,: )
    !> Index in water_conc corresponding to water vapor
    integer, intent(in) :: WATER_VAPOR_ID
    !> Air density [kg_air m-3]
    real, intent(out) :: tracer_air_density( :,:,: )

    integer(kind=mint) :: i_spec, water_id

    ! Reset the species concentrations in PMC and tracer
    phlex_state%state_var( : ) = 0.0
    tracer_conc( :,:,:,: ) = 0.0
    tracer_water_conc( :, :, :, WATER_VAPOR_ID ) = 0.0

    ! Set the air density to a nominal value
    tracer_air_density( :,:,: ) = 1.225

    ! Set initial concentrations in PMC
    phlex_state%state_var( this%init_conc_phlex_id( : ) ) =                  &
            this%init_conc( : )

    ! Copy species concentrations to tracer array
    forall( i_spec = 1:size( this%map_tracer_id ) )
      tracer_conc( :, :, :, this%map_tracer_id( i_spec ) ) =                 &
              phlex_state%state_var( this%map_phlex_id( i_spec ) )
    end forall

    ! Set the relative humidity
    tracer_water_conc( :, :, :, WATER_VAPOR_ID ) =                           &
            phlex_state%state_var( this%phlex_water_vapor_id ) *             &
            1.0d-9 / 1.225d0

  end subroutine get_init_conc_TEST_ONLY

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  !> Get the tracer species names and indices (for testing only)
  subroutine get_tracer_species_TEST_ONLY( this, species_names, tracer_ids )

    !> PartMC-phlex <-> tracers species map
    class(monarch_species_map_t) :: this
    !> Set of species names
    type(string_t), allocatable, intent(out) :: species_names( : )
    !> Tracer ids
    integer(kind=mint), allocatable, intent(out) :: tracer_ids( : )

    species_names = this%tracer_species_names
    tracer_ids = this%map_tracer_id

  end subroutine get_tracer_species_TEST_ONLY

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#endif
end module monarch_species_map
