inst/doc/rad_aero_22.R

## ----setup, echo=FALSE, message=FALSE-----------------------------------------
SHOW_ANSWERS <- FALSE
if (Sys.info()["sysname"] == "Linux") prefix <- "/home/adriaan/" else prefix <- "/Users/amd427/"
if (SHOW_ANSWERS) knitr::opts_knit$set(root.dir = normalizePath(paste(prefix, "git/training/colorado2022/", sep = "")))
# knitr::opts_chunk$set(eval=FALSE)
Sys.setenv(TZ = "UTC")
library(bioRad)

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # make sure you start with a fresh R session
# # load the bioRad package
# library(bioRad)
# # check the package version
# packageVersion("bioRad")

## ----eval=FALSE---------------------------------------------------------------
# # bring up the package general help page:
# ?bioRad

## ----eval=FALSE---------------------------------------------------------------
# # make a new local directory on your machine for this practical
# # replace the string below with the path of that directory:
# HOME <- "your/personal/working/directory/"
# # check that the directory exists. If the next statement evaluates to FALSE, something went wrong: the directory does not exist or you didn't specify its path correctly
# file.exists(HOME)
# # we will make HOME our work directory, the default folder in which R will look
# # for files, and where it will output newly generated files.
# setwd(HOME)
# # next, we will create two directories where we will be storing data:
# dir.create("./data_vpts") # here we will store vertical profile time series (vpts data)
# dir.create("./data_pvol") # here we will store polar volumes (pvol data)
# # Finally, we set the local time zone to UTC, so all plotted time axes will be in UTC
# Sys.setenv(TZ = "UTC")

## ----eval=SHOW_ANSWERS, results='hide'----------------------------------------
# # Let's first download the NEXRAD polar volume files for the KHGX radar (Houston)
# # for a 15 minute period in 2017:
# download_pvolfiles(date_min=as.POSIXct("2017-05-04 01:25:00"), date_max=as.POSIXct("2017-05-04 01:40:00"), radar="KHGX", directory="./data_pvol")
# # store the filenames in my_pvolfiles
# my_pvolfiles <- list.files("./data_pvol", recursive = TRUE, full.names = TRUE, pattern="KHGX")
# # print to console our files:
# my_pvolfiles
# # let's load the first of our downloaded files:
# my_pvol <- read_pvolfile(my_pvolfiles[1])

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS-------------------------------------
# # The default summary information of a `pvol` object contains information
# # on the scans (sweeps) and their moments:
# my_pvol

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS-------------------------------------
# # We can also extract the elevation angles from the polar volume as follows:
# get_elevation_angles(my_pvol)

## ----eval=SHOW_ANSWERS, warning=FALSE-----------------------------------------
# # let's extract the scan collected at 1.5 degree elevation from our polar volume:
# my_scan <- get_scan(my_pvol, 0.5)
# # print some information about this scan:
# my_scan
# # let's plot the reflectivity factor parameter of the scan in a range - azimuth coordinate system:
# plot(my_scan, param = "DBZH")

## ----eval=SHOW_ANSWERS, warning=FALSE-----------------------------------------
# # before we can plot the scan, we need to project it on a Cartesian grid,
# # i.e. we need to make a Plan Position Indicator (PPI)
# my_ppi <- project_as_ppi(my_scan)
# # print some information about this ppi:
# my_ppi
# # you can see we projected it on a 500 meter grid
# # (check the manual of the project_as_ppi function to see how you can
# # change the grid size (argument grid_size) and the maximum distance
# # from the radar up to where to plot data (argument range_max))
# #
# # Now we are ready to plot the ppi, for example let's plot reflectivity factor DBZH:
# plot(my_ppi, param = "DBZH")

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS, warning=FALSE----------------------
# # Plot the correlation coefficient (RHOHV):
# plot(my_ppi, param = "RHOHV")

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS, warning=FALSE----------------------
# # Plot the radial velocity (VRADH):
# plot(my_ppi, param = "VRADH")

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS, warning=FALSE----------------------
# # Answer:
# # * Precipitation areas are characterized by high correlation coefficients (typically > 0.95),
# #   i.e. the top left corner of the image is precipitation
# # * The blue radial velocity of the precipitation indicates it is moving towards the radar.
# # * The radial velocity field of the biology shows areas south-west of the radar moving
# #   towards the radar (blue), and areas north-east of the radar moving away from it (red).
# #   The biology is therefore moving towards the north-east

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS, warning=FALSE----------------------
# # Answer:
# # * Precipitation moves with the wind field. Since the biology moves into a different direction
# #   than the wind and a very different speed, we can be sure these are birds.
# #   The biological scatterers have a high self-propelled speed, which is
# #   typical for birds, not for insects.
# # * Note: This is an S-band radar. In C-band radars you will typically see that the texture
# #   (spatial variability) of the radial velocity is considerably smoother in areas with
# #   precipitation than in areas with biology.

## ----eval=SHOW_ANSWERS, warning=FALSE-----------------------------------------
# # It is often informative to plot radar data on a base layer.
# # First choose a base layer from the list of rosm::osm.types()
# basemap = "osm"
# # then overlay the PPI on the basemap, restricting the color scale from -20 to 40 dBZ:
# map(my_ppi, map = basemap, param = "DBZH", zlim = c(-20, 40))

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # Screen out the reflectivity areas with RHOHV < 0.95
# my_ppi_clean <- calculate_param(my_ppi, DBZH = ifelse(RHOHV > 0.95, NA, DBZH))
# # plot the original and cleaned up reflectivity:
# map(my_ppi, map = basemap, param = "DBZH", zlim = c(-20, 40))
# map(my_ppi_clean, map = basemap, param = "DBZH", zlim = c(-20, 40))

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # apply the MistNet model to the polar volume file and load it as a polar volume (pvol):
# my_pvol <- apply_mistnet(my_pvolfiles[1])
# # mistnet will add additional parameters to the
# # elevation scans at 0.5, 1.5, 2.5, 3.5 and 4.5 degrees
# # let's extract the scan closest to 0.5 degrees:
# my_scan <- get_scan(my_pvol, 0.5)
# # plot some summary info about the scan to the console:
# my_scan

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # let's add depolarization ratio (DR) as a parameter (following Kilambi 2018):
# my_ppi <- calculate_param(my_ppi, DR = 10 * log10((1+ ZDR - 2 * (ZDR^0.5) * RHOHV) /
#   (1 + ZDR+ 2 * (ZDR^0.5) * RHOHV)))

## ----eval=SHOW_ANSWERS--------------------------------------------------------
#   # plot the depolarization ratio, using a viridis color palette:
# map(my_ppi, map = basemap, param = "DR", zlim=c(-25,-5), palette = viridis::viridis(100))

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS-------------------------------------
# # Now let us screen out the reflectivity areas with DR < -12 dB:
# my_ppi_clean <- calculate_param(my_ppi, DBZH = ifelse(DR < -12, NA, DBZH))
# # plot the original and cleaned up reflectivity:
# map(my_ppi, map = basemap, param = "DBZH", zlim = c(-20, 40))
# map(my_ppi_clean, map = basemap, param = "DBZH", zlim = c(-20, 40))

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # as before, project the scan as a ppi:
# my_ppi <- project_as_ppi(my_scan)
# # plot the probability for the WEATHER class
# plot(my_ppi, param = 'WEATHER')
# # plot the final segmentation result:
# # plot the probability for the WEATHER class
# plot(my_ppi, param = 'CELL')
# # let's remove the identified precipitation area (and additional fringe) from the ppi, and plot it:
# my_ppi_clean <- calculate_param(my_ppi, DBZH = ifelse(CELL >= 1, NA, DBZH))
# map(my_ppi_clean, map=basemap, param = 'DBZH')

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS-------------------------------------
# # To remove the additional fringe around the rain segmentation by MistNet
# # we want to screen out CELL values equal to 2 only.
# my_ppi_clean <- calculate_param(my_ppi, VRADH = ifelse(CELL >= 2, NA, VRADH))
# map(my_ppi_clean, map=basemap, param = 'VRADH')

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # Usually we would load processed vertical profiles (vp files) by:
# # my_vplist <- read_vpfiles("./your/directory/with/processed/profiles/goes/here")
# # my_vplist contains after running the command a list of vertical profile (vp) objects
# # To save time, we load these data directly from file
# my_vplist <- readRDS("data_vpts/KBRO20170514.rds")
# # print the length of the vplist object. It should contain 95 profiles
# length(my_vplist)

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # let's extract a profile from the list, in this example the 41st profile:
# my_vp <- my_vplist[[41]]
# # print some info for this profile to the console
# my_vp
# # test whether this profile was collected at day time:
# check_night(my_vp)
# # plot the vertical profile, in terms of reflectivity factor
# plot(my_vp, quantity = "dbz")
# # plot the vertical profile, in terms of (linear) reflectivity
# plot(my_vp, quantity = "eta")

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # let's plot the vertical profile, in terms of bird density
# plot(my_vp, quantity = "dens")
# # print the currently assumed radar cross section (RCS) per bird:
# rcs(my_vp)

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS, warning=FALSE----------------------
# # Answer:
# # All bird densities will be a factor 10 times lower.

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # let's change the RCS to 110 cm^2
# rcs(my_vp) <- 110

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS, warning=FALSE----------------------
# # After changing the RCS above, we simply plot the vertical profile again
# plot(my_vp)
# # Indeed the densities are scaled down by a factor 10

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # convert the list of vertical profiles into a time series:
# my_vpts <- bind_into_vpts(my_vplist)
# # time series objects can be subsetted, just as you may be used to with vectors
# # here we subset the first 50 timesteps:
# my_vpts[1:50]
# # here we extract a single timestep, which gives you back a vertical profile class object:
# my_vpts[100]
# # to plot the full time series:
# plot(my_vpts)
# # check the help file for the plotting function of profile time series
# # Because profile timeseries are of class 'vpts', it's associated plotting function
# # is called plot.vpts:
# ?plot.vpts

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # filter our vpts for night time
# my_vpts_night <- filter_vpts(my_vpts, night=TRUE)
# # plot this smaller time series:
# plot(my_vpts_night)

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS, warning=FALSE----------------------
# # Answer:
# #
# # At 1500 meter 6 UTC the wind barbs have 2 full flags and one half flag.
# # Therefore the ground speed is approximately 2x5 + 2.5 = 12.5 m/s.

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS, warning=FALSE----------------------
# # First extract the profile at 6 UTC:
# vp_6UTC <- filter_vpts(my_vpts_night, nearest = "2017-05-14 06:00")
# plot(vp_6UTC, quantity = "ff")

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS, warning=FALSE----------------------
# # Plot the ground speed (ff):
# plot(vp_6UTC, quantity = "ff")
# # Speeds at 1500 metre is approximately 12 m/s, confirming our earlier reading above of 12.5 m/s.

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # Let's continue with the vpts object created in the previous example.
# # The vertically integrated quantities are calculated as follows:
# my_vpi <- integrate_profile(my_vpts)
# # The my_vpi object you created is a vpi class object, which is an acronym for "vertical profile integrated". It has its own plot method, which by default plots migration traffic rate (MTR):
# plot(my_vpi)
# # you can also plot vertically integrated densities (VID):
# plot(my_vpi, quantity = "vid")
# # the gray and white shading indicates day and night, which is calculated
# # from the date and the radar position. You can also turn this off:
# plot(my_vpi, night_shade = FALSE)
# # plot the cumulative number of birds passing the radar, i.e. migration traffic (mt):
# plot(my_vpi, quantity = "mt")
# # execute `?plot.vpi` to open the help page listing all the options.
# ?plot.vpi

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS, warning=FALSE----------------------
# # Answer:
# #
# # VID = (200 birds / km^3) * (1 km) + (100 birds / km^3) * (0.5 km)
# #     = 250 birds / km^2

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS, warning=FALSE----------------------
# # Answer:
# #
# # MTR = (200 birds / km^3) * (50 km / hour) * (1 km) + (100 birds / km^3) * (100 km / hour) * (0.5 km)
# #     = 10000 birds / km / hour + 5000 birds / km / hour
# #     = 15000 birds / km / hour

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS, warning=FALSE----------------------
# # Answer:
# #
# # MT = MTR * (3 hour) = (15000 birds / km / hour) * (3 hour)
# #    = 45000 birds / km
# # for a 10 kilometer transect:
# # Number_of_birds = 10 km * 45000 birds / km = 450000 birds

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # instead of vertically integrated density (VID), you can use vertically integrated reflectivity (VIR):
# plot(my_vpi, quantity = "vir")
# # instead of migration traffic rate (MTR), you can use the reflectivity traffic rate (RTR):
# plot(my_vpi, quantity = "rtr")
# # instead of migration traffic (MT), you can use the reflectivity traffic (RT):
# plot(my_vpi, quantity = "rt")

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # load a time series for the KBGM radar in Binghamton, NY
# my_vpts <- readRDS("data_vpts/KBGM20170527-20170602.rds")
# # print the loaded vpts time series for this radar:
# my_vpts
# # plot the bird density over time:
# plot(my_vpts, quantity = "dens")

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS, warning=FALSE----------------------
# # also show meteorological signals:
# plot(my_vpts, quantity = "DBZH")
# 
# # Periods with high reflectivities extending to high altitudes indicate precipitation,
# # i.e. second half of the second night, and on and off during the fourth night.

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # define ranges from 0 to 2500000 meter (250 km), in steps of 100 m:
# range <- seq(0, 250000, 100)
# 
# # plot the beam height of the 0.5 degree elevation beam:
# plot(range, beam_height(range, 0.5), ylab = "beam height [m]", xlab = "range [m]", type='l')
# 
# # let's add the lower and upper altitude of the beam, as determined by the beam width:
# points(range, beam_height(range, 0.5)-beam_width(range)/2, type='l',lty=3)
# points(range, beam_height(range, 0.5)+beam_width(range)/2, type='l',lty=3)

## ----eval=SHOW_ANSWERS, warning=FALSE, results='hide'-------------------------
# # download a polar volume for the KBRO radar in Brownsville, TX
# download_pvolfiles(date_min=as.POSIXct("2017-05-14 05:50:00"), date_max=as.POSIXct("2017-05-14 06:00:00"), radar="KBRO", directory="./data_pvol")
# # Load all the polar volume filenames downloaded so far for the KBRO radar:
# my_pvolfiles <- list.files("./data_pvol", recursive = TRUE, full.names = TRUE, pattern="KBRO")
# # we will process the first one into a vp:
# my_pvolfile <- my_pvolfiles[1]
# # calculate the profile, using MistNet to remove precipitation:
# # we calculate 60 layers of 50 meter width, so up to 30*100=3000 m.
# my_vp <- calculate_vp(my_pvolfile, n_layer=60, h_layer=50, sd_vvp_threshold = 1)

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS, warning=FALSE----------------------
# # plot the profile
# plot(my_vp)
# 
# # Answer:
# # * The vertical profile shows altitude bands of about 300 meter width
# #   We therefore expect the radar to start having difficulty to resolve this profile
# #   when the beam shape becomes broader, so less than 50 km
# #   (this is why we typically use 35 km as the maximum range to use in vertical profile estimation.)
# # * the birds fly up to about 2km in this profile.
# #   At about 200000 m (200 km) the lower end of the beam no longer overlaps with the migration layer
# #   Therefore, if we birds are flying according to the same altitude distribution everywhere,
# #   we expect the radar to become fully blind for birds beyond 200 km

## ----eval=SHOW_ANSWERS,warning=FALSE------------------------------------------
# # We will use the piping operator %>% of magrittr package to
# # execute multiple operations in one statement:
# library(magrittr)
# # first, load the polar volume:
# my_pvolfile %>% read_pvolfile() -> my_pvol
# # Next, let's calculate a PPI for the 1.5 degree elevation scan
# # Finally, we calculated the vertically integrated PPI
# my_ppi_integrated <- integrate_to_ppi(pvol=my_pvol,vp=my_vp, res=1000)

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS,warning=FALSE-----------------------
# #
# my_pvol %>%
#   get_scan(elev = 1.0) %>%
#   project_as_ppi(raster=raster::raster(my_ppi_integrated$data)) ->
#   my_ppi
# # let's take the logarithm of the vertically integrated density, so
# # we can compare it more directly to DBZH, which is also a logarithmic quantity:
# my_ppi_integrated <- calculate_param(my_ppi_integrated, logVID=log(VID))
# # plot both ppi's:
# plot(my_ppi)
# plot(my_ppi_integrated, param="logVID", zlim=c(-10,10))

## ----echo=SHOW_ANSWERS, eval=SHOW_ANSWERS-------------------------------------
# # The altitude distribution in this case shows two migration layers.
# # In the 1.5 PPI scan these show up as two concentric rings of density.
# # Since in a conventional PPI a larger distance from the radar also
# # implies a higher altitude, we see the rings showing up at the
# # ranges where the beam intersects each of the migration layers.
# #
# # The vertically integrated PPI is more straightforward to interpret
# # Here we correct for aforementioned beam effects and integrate the
# # density over altitude, giving a more realistic reconstruction of the
# # spatial distribution of migrants.

## ----eval=SHOW_ANSWERS,results='hide',warning=FALSE---------------------------
# # First we download more data, for a total of one additional hour for the same radar:
# download_pvolfiles(date_min=as.POSIXct("2017-05-04 01:40:00"), date_max=as.POSIXct("2017-05-04 02:40:00"), radar="KHGX", directory="./data_pvol")
# # We will process all the polar volume files downloaded so far:
# my_pvolfiles <- list.files("./data_pvol", recursive = TRUE, full.names = TRUE, pattern="KHGX")
# my_pvolfiles
# # create output directory for processed profiles
# outputdir <- "./data_vp"
# dir.create(outputdir)

## ----eval=FALSE, echo=FALSE---------------------------------------------------
# # let's loop over the files and generate profiles
# start=Sys.time()
# for (file_in in my_pvolfiles) {
#   # generate the output filename for the input file
#   file_out <- paste(outputdir, "/", basename(file_in), "_vp.h5", sep = "")
#   # generate the profile, and write it as a hdf5 file (for later reference)
#   # we enclose the calculate_vp statement in tryCatch to keep going after errors with specific files
#   vp <- tryCatch(calculate_vp(file_in, file_out, mistnet = TRUE, h_layer=50, n_layer=60), error = function(e) NULL)
# }
# end=Sys.time()
# # calculate the processing time that has passed:
# end-start

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # we assume outputdir contains the path to the directory with processed profiles
# my_vpfiles <- list.files(outputdir, full.names = TRUE, pattern="KHGX")
# # print them
# my_vpfiles
# # read them
# my_vplist <- read_vpfiles(my_vpfiles)

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# # make a time series of profiles:
# my_vpts <- bind_into_vpts(my_vplist)
# # plot them between 0 - 3 km altitude:
# plot(my_vpts, ylim = c(0, 3000))
# # because of the rain moving in, our ability to estimate bird profiles slowly drops:
# # let's visualize rain by plotting all aerial reflectivity:
# plot(my_vpts, ylim = c(0, 3000), quantity="DBZH")
# 

## ----eval=SHOW_ANSWERS--------------------------------------------------------
# process_file <- function(file_in){
#   # construct output filename from input filename
#   file_out <- paste(outputdir, "/", basename(file_in), "_vp.h5", sep = "")
#   # run calculate_vp()
#   vp <- tryCatch(calculate_vp(file_in, file_out, mistnet = FALSE, h_layer=50, n_layer=60), error = function(e) NULL)
#   if(is.vp(vp)){
#     # return TRUE if we calculated a profile
#     return(TRUE)
#   } else{
#     # return FALSE if we did not
#     return(FALSE)
#   }
# }
# 
# # To process a file, we can now run
# process_file(my_pvolfiles[1])

## ----eval=FALSE---------------------------------------------------------------
# # load the parallel library
# library(parallel)
# # detect how many cores we can use. We will keep 2 cores for other tasks and use the rest for processing.
# number_of_cores = detectCores() - 2
# # Available cores:
# number_of_cores
# # let's loop over the files and generate profiles
# start=Sys.time()
# mclapply(my_pvolfiles, process_file, mc.cores = number_of_cores)
# end=Sys.time()
# # calculate the processing time that has passed:
# end-start

Try the bioRad package in your browser

Any scripts or data that you put into this service are public.

bioRad documentation built on June 17, 2025, 1:07 a.m.