R/telescope.R

Defines functions telescope

Documented in telescope

# Author: Kate Harborne
# Date: 28/10/2020
# Title: telescope - a class for describing telescope properties
#
#'A class to describe the basic properties of the observing telescope
#'
#'The purpose of this function is to generate the observing telescope whose
#' properties will be used to compute the properties of the observation.
#' Several telescope types are included and can be accessed using the
#' \code{type} parameter. Alternatively, you may describe the properties of
#' another telescope by specifying \code{type = "IFU"} and listing the other
#' required properties explicitly.
#'
#'@param type String that describes the type of telescope you wish to create.
#' Current pre-loaded types include "SAMI", "MaNGA", "CALIFA", "MUSE" and
#' "Hector". Input is NOT case sensitive. If you wish to specify different
#' observing properties below, set \code{type = "IFU"} to define your own.
#'@param fov Numeric describing the field of view of the instrument in arcsec.
#'@param aperture_shape String to describe the shape of the IFU aperture.
#' Options include "circular", "hexagonal" or "square".
#'@param wave_range Numeric vector of length 2 describing the wave range of the
#' IFU (i.e. \code{c(wave_min, wave_max)}) in units of angstrom.
#'@param wave_centre Numeric describing the central wavelength of the
#' spectrograph used in the observation in units of angstrom. If unsupplied,
#' default is the exact centre of the provided `wave_range` parameter.
#'@param wave_res Numeric describing the wavelength resolution in angstrom.
#'@param spatial_res Numeric describing the size of spatial pixels in arcsec.
#'@param filter String describing the relevent filter through which luminosities
#' of individual particles are calculated.
#'@param lsf_fwhm Numeric describing the full-width half-maximum of the Gaussian
#' line spread function.
#'@param signal_to_noise Numeric describing the minimum signal-to-noise ratio per
#' angstrom. Default is NA, meaning that no noise will be added to the
#' observation.
#'@param method Providing backward compatibility for \code{method}
#' specification. String to describe whether cubes output are "spectral", "gas",
#' "sf gas" or "velocity" (as in SimSpin v1) along the z-axis. Default is
#' "spectral". For v2.1.6  onwards, \code{method} should be specified in
#' \link{build_datacube}. Support  for this input will remain in all
#' versions 2.X.X.
#'@return Returns an object of class "telescope" that describes the properties
#' of the instrument doing the observation. Required to run
#' \code{build_datacube()}.
#'@examples
#'telescope = telescope(type="SAMI")
#'

telescope = function(type="IFU", fov, aperture_shape="circular", wave_range=c(3700,5700),
                     wave_centre, wave_res=1.04, spatial_res, filter="g", lsf_fwhm=2.65,
                     signal_to_noise = NA, method){

  if (!missing(method)){

    if (method != "spectral" &
        method != "velocity" &
        method != "gas" &
        method != "sf gas" ){
      stop("Error: Invalid method. \n Please specify method = 'spectral', 'velocity', 'gas' or 'sf gas' and try again.")
    } else {
      warning(">>> WARNING! >>> \n
             `method` is now specified within the build_datacube function directly,
              rather than within the telescope() class. \n
              Support for this input will remain in versions 2.X.X, but please consider
              updating your code.")

      method = stringr::str_to_lower(method)
    }
  }

  if (length(wave_range)!=2){
    stop("Error: length(wave_range) should be 2. \n Please specify wave_range = c(wave_min, wave_max) and try again.")
  }
  if (wave_range[1] > wave_range[2]){
    wave_range = c(wave_range[2], wave_range[1]) # ensure that the wave_range is c(wave_min, wave_max)
  }
  if (stringr::str_to_lower(aperture_shape) != "circular" &
      stringr::str_to_lower(aperture_shape) != "hexagonal" &
      stringr::str_to_lower(aperture_shape) != "square"){
    stop("Error: Invalid aperture_shape. \n Please specify aperture_shape = 'circular', 'hexagonal' or 'square' and try again.")
  }
  if (missing(wave_centre)){
    wave_centre = wave_range[1] + (diff(wave_range)/2)
  }
  if (stringr::str_to_lower(filter) == "r"){
    filter = SimSpin::filt_r_SDSS
    filter_name = "r_SDSS"
  } else if (stringr::str_to_lower(filter) == "u"){
    filter = SimSpin::filt_u_SDSS
    filter_name = "u_SDSS"
  } else if (stringr::str_to_lower(filter) == "g"){
    filter = SimSpin::filt_g_SDSS
    filter_name = "g_SDSS"
  } else if (stringr::str_to_lower(filter) == "i"){
    filter = SimSpin::filt_i_SDSS
    filter_name = "i_SDSS"
  } else if (stringr::str_to_lower(filter) == "z"){
    filter = SimSpin::filt_z_SDSS
    filter_name = "z_SDSS"
  } else {
    stop("Error: Invalid filter. \n Please specify filter = 'r', 'u' or 'g', 'i' or 'z' and try again.")
  }

  if (missing(method)){
    if(stringr::str_to_upper(type)  == "SAMI"){
      fov = 15
      spatial_res = 0.5
      output = list(type            = "SAMI",
                    fov             = fov,
                    aperture_shape  = "circular",
                    wave_range      = c(3750,5750),
                    wave_centre     = 4800,
                    spatial_res     = spatial_res,
                    filter_name     = filter_name,
                    filter          = filter,
                    wave_res        = 1.04,
                    lsf_fwhm        = 2.65,
                    signal_to_noise = signal_to_noise,
                    sbin            =  floor(fov/spatial_res))
    }

    if(stringr::str_to_upper(type)  == "MANGA"){

      spatial_res = 0.5

      if (missing(fov)){
        fov = 12
      } else {
        fov_pos = c(12, 17, 22, 27, 32)
        if (!fov %in% fov_pos){
          if (fov > max(fov_pos)){
            suggested_fov = max(fov_pos)
          } else {
            suggested_fov = fov_pos[which((fov_pos - fov) > 0)[1]]
          }
          warning(paste0(">>> WARNING! >>> \n
                         `fov` specified is not an option for telescope type `MaNGA`. \n
                         `fov` options include 12, 17, 22, 27, or 32. \n
                         Setting 'fov' to the nearest available option. \n
                         fov = ", suggested_fov))
          fov = suggested_fov
        } # catching any inputs that are not suitable for MaNGA telescope
      }

      output = list(type            = "MaNGA",
                    fov             = fov,
                    aperture_shape  = "hexagonal",
                    wave_range      = c(3600,6350),
                    wave_centre     = 4700,
                    spatial_res     = spatial_res,
                    filter_name     = filter_name,
                    filter          = filter,
                    wave_res        = 1.04,
                    lsf_fwhm        = 2.85,
                    signal_to_noise = signal_to_noise,
                    sbin            = floor(fov/spatial_res))
    }

    if(stringr::str_to_upper(type)  == "MUSE"){

      if (missing(spatial_res)){
        spatial_res = 0.2
      } else {
        pos_spatial_res = c(0.025, 0.2)
        if (!spatial_res %in% pos_spatial_res){
          spatial_res = 0.2
          warning(">>> WARNING! >>> \n
                  `spatial_res` specified is not an option for telescope type `MUSE`. \n
                  `spatial_res` options include 0.025 (NFM) or 0.2 (WFM). \n
                  Setting `spatial_res` to the default. \n
                  spatial_res = 0.2 ")

        }
      }

      if (missing(fov)){
        fov = 5
      } else {
        if (fov > 60){
          warning(paste0(">>> WARNING! >>> \n
                         `fov` specified is not an option for telescope type 'MUSE'. \n
                         `fov` options must be less than 60. \n
                         Setting `fov` to the nearest available option. \n
                         fov = 60"))
          fov = 60
        } # catching any inputs that are not suitable for MaNGA telescope
      }

      output = list(type            = "MUSE",
                    fov             = fov,
                    aperture_shape  = "square",
                    wave_range      = c(4700.15,9351.4),
                    wave_centre     = 6975,
                    spatial_res     = spatial_res,
                    filter_name     = filter_name,
                    filter          = filter,
                    wave_res        = 1.25,
                    lsf_fwhm        = 2.51,
                    signal_to_noise = signal_to_noise,
                    sbin            = floor(fov/spatial_res))

    }

    if(stringr::str_to_upper(type)  == "HECTOR"){
      fov = 30
      spatial_res = 0.1
      output = list(type            = "Hector",
                    fov             = fov,
                    aperture_shape  = "hexagonal",
                    wave_range      = c(3720,5910),
                    wave_centre     = 4815,
                    spatial_res     = spatial_res,
                    filter_name     = filter_name,
                    filter          = filter,
                    wave_res        = 1.6,
                    lsf_fwhm        = 1.3,
                    signal_to_noise = signal_to_noise,
                    sbin            =  floor(fov/spatial_res))

    }

    if(stringr::str_to_upper(type)  == "CALIFA"){
      fov = 74
      spatial_res = 1
      output = list(type            = "CALIFA",
                    fov             = fov,
                    aperture_shape  = "hexagonal",
                    wave_range      = c(3700,4750),
                    wave_centre     = 4225,
                    spatial_res     = spatial_res,
                    filter_name     = filter_name,
                    filter          = filter,
                    wave_res        = 2.7,
                    lsf_fwhm        = 2.7,
                    signal_to_noise = signal_to_noise,
                    sbin            = floor(fov/spatial_res))

    }

    if(stringr::str_to_upper(type)  == "IFU"){

      if (missing(fov)){fov = 15} # setting to the default parameter expected
      if (missing(spatial_res)){spatial_res = 0.5}

      output = list(type            = "IFU",
                    fov             = fov,
                    aperture_shape  = stringr::str_to_lower(aperture_shape),
                    wave_range      = wave_range,
                    wave_centre     = wave_centre,
                    wave_res        = wave_res,
                    spatial_res     = spatial_res,
                    filter_name     = filter_name,
                    filter          = filter,
                    lsf_fwhm        = lsf_fwhm,
                    signal_to_noise = signal_to_noise,
                    sbin            = floor(fov / spatial_res))
    }

  } else {

    if(stringr::str_to_upper(type)  == "SAMI"){
      fov = 15
      spatial_res = 0.5
      output = list(type            = "SAMI",
                    method          = method,
                    fov             = fov,
                    aperture_shape  = "circular",
                    wave_range      = c(3750,5750),
                    wave_centre     = 4800,
                    spatial_res     = spatial_res,
                    filter_name     = filter_name,
                    filter          = filter,
                    wave_res        = 1.04,
                    lsf_fwhm        = 2.65,
                    signal_to_noise = signal_to_noise,
                    sbin            =  floor(fov/spatial_res))
    }

    if(stringr::str_to_upper(type)  == "MANGA"){

      spatial_res = 0.5

      if (missing(fov)){
        fov = 12
      } else {
        fov_pos = c(12, 17, 22, 27, 32)
        if (!fov %in% fov_pos){
          suggested_fov = fov_pos[which((fov_pos - fov) > 0)[1]]
          warning(paste0(">>> WARNING! >>> \n
                         `fov` specified is not an option for telescope type `MaNGA`. \n
                         `fov` options include 12, 17, 22, 27, or 32. \n
                         Setting `fov` to the nearest available option. \n
                         fov = ", suggested_fov))
          fov = suggested_fov
        } # catching any inputs that are not suitable for MaNGA telescope
      }

      output = list(type            = "MaNGA",
                    method          = method,
                    fov             = fov,
                    aperture_shape  = "hexagonal",
                    wave_range      = c(3600,6350),
                    wave_centre     = 4700,
                    spatial_res     = spatial_res,
                    filter_name     = filter_name,
                    filter          = filter,
                    wave_res        = 1.04,
                    lsf_fwhm        = 2.85,
                    signal_to_noise = signal_to_noise,
                    sbin            =  floor(fov/spatial_res))
    }

    if(stringr::str_to_upper(type)  == "MUSE"){

      if (missing(spatial_res)){
        spatial_res = 0.2
      } else {
        pos_spatial_res = c(0.025, 0.2)
        if (!spatial_res %in% pos_spatial_res){
          spatial_res = 0.2
          warning(">>> WARNING! >>> \n
                  `spatial_res` specified is not an option for telescope type `MUSE`. \n
                  `spatial_res` options include 0.025 (NFM) or 0.2 (WFM). \n
                  Setting 'spatial_res' to the default. \n
                  spatial_res = 0.2 ")

        }
      }

      if (missing(fov)){
          fov = 5
        } else {
          if (fov > 60){
            warning(paste0(">>> WARNING! >>> \n
                         `fov` specified is not an option for telescope type `MUSE`. \n
                         `fov` options must be less than 60. \n
                         Setting `fov` to the nearest available option. \n
                         fov = 60"))
            fov = 60
          } # catching any inputs that are not suitable for MaNGA telescope
        }

      output = list(type            = "MUSE",
                    method          = method,
                    fov             = fov,
                    aperture_shape  = "square",
                    wave_range      = c(4700.15,9351.4),
                    wave_centre     = 6975,
                    spatial_res     = spatial_res,
                    filter_name     = filter_name,
                    filter          = filter,
                    wave_res        = 1.25,
                    lsf_fwhm        = 2.51,
                    signal_to_noise = signal_to_noise,
                    sbin            = floor(fov/spatial_res))

    }

    if(stringr::str_to_upper(type)  == "HECTOR"){
      fov = 30
      spatial_res = 0.1
      output = list(type            = "Hector",
                    method          = method,
                    fov             = fov,
                    aperture_shape  = "hexagonal",
                    wave_range      = c(3720,5910),
                    wave_centre     = 4815,
                    spatial_res     = spatial_res,
                    filter_name     = filter_name,
                    filter          = filter,
                    wave_res        = 1.6,
                    lsf_fwhm        = 1.3,
                    signal_to_noise = signal_to_noise,
                    sbin            =  floor(fov/spatial_res))

    }

    if(stringr::str_to_upper(type)  == "CALIFA"){
      fov = 74
      spatial_res = 1
      output = list(type            = "CALIFA",
                    method          = method,
                    fov             = fov,
                    aperture_shape  = "hexagonal",
                    wave_range      = c(3700,4750),
                    wave_centre     = 4225,
                    spatial_res     = spatial_res,
                    filter_name     = filter_name,
                    filter          = filter,
                    wave_res        = 2.7,
                    lsf_fwhm        = 2.7,
                    signal_to_noise = signal_to_noise,
                    sbin            = floor(fov/spatial_res))

    }

    if(stringr::str_to_upper(type)  == "IFU"){

      if (missing(fov)){fov = 15} # setting to the default parameter expected
      if (missing(spatial_res)){spatial_res = 0.5}

      output = list(type            = "IFU",
                    fov             = fov,
                    method          = method,
                    aperture_shape  = stringr::str_to_lower(aperture_shape),
                    wave_range      = wave_range,
                    wave_centre     = wave_centre,
                    wave_res        = wave_res,
                    spatial_res     = spatial_res,
                    filter_name     = filter_name,
                    filter          = filter,
                    lsf_fwhm        = lsf_fwhm,
                    signal_to_noise = signal_to_noise,
                    sbin            = floor(fov / spatial_res))
    }
  }

  if( min(output$filter$wave) > max(output$wave_range) | max(output$filter$wave) < min(output$wave_range) ){
    stop("Error: Requested filter will not overlap with the telescope wavelength range. \n
         Please select a different filter or extend your telescope wavelength range.")
  }

  return(output)
}
kateharborne/SimSpin documentation built on April 28, 2024, 2 p.m.