R’s compatibility to easily use fast Cpp code (Rcpp) and spatial processing (e.g. terra) makes it an attractive opensource environment to study tropical cyclones, aka TCs, hurricanes and typhoons. This package estimates TC vortex wind and pressure fields using parametric equations originally coded up in python by TCRM and in Cuda Cpp by TCwindgen.
TC wind fields can be computed using three model inputs of the: 1) TC Track, 2) Model Parameters and 3) Model Spatial Domain. The TCHazaRds package can be used with other visualization and spatial analysis packages to analyse the impacts of TCs.
suppressPackageStartupMessages(require(TCHazaRds)) # this package :)
suppressPackageStartupMessages(require(terra)) # spatial analysis
suppressPackageStartupMessages(require(rasterVis)) # enhanced raster visualization https://oscarperpinan.github.io/rastervis/
suppressPackageStartupMessages(require(sp)) # spatial methods and plotting
suppressPackageStartupMessages(require(knitr)) # formatted table
suppressPackageStartupMessages(require(raster)) # convert for raster plots
The first thing that is required to model near- and far-field TC winds is the TC track/path. The functions in TCHazaRds require that the tracks have a “shape-file” like spatial-vector format and have attributes of pressure, date/time, location and forward speed and direction.
TCi = vect(cbind(c(154,154),c(-26.1,-26)),"lines",crs="epsg:4283") #track line segment
TCi$PRES = 950 #central pressure in hPa
#TCi$RMW = 40 #radius of maximum winds in km
TCi$ISO_TIME = "2022-10-04 20:00:00" #"%Y-%m-%d %H:%M:%S", tz = "UTC"
TCi$LON = geom(TCi)[1,3] #longitude
TCi$LAT = geom(TCi)[1,4] #latitude
TCi$STORM_SPD = perim(TCi)/(3*3600) #speed of the forward motion of the TC m/s
TCi$thetaFm = 90-returnBearing(TCi) #direction of the heading of the TC (Cartesian, clockwise from x axis)
In the above code chunk a simple track segment is defined, but historical TC tracks, e.g. from IBTRACs, can provide the input into the model. A few tracks are provided with the package, below TC Yasi is read in.
TC <- vect(system.file("extdata/YASI/YASI.shp", package="TCHazaRds"))
TC$PRES <- TC$BOM_PRES #different agencies each provide a PRES, you need to chose one.
TC$STORM_SPD = TC$STORM_SPD/1.94 #provided as knots, convert to m/s
TC$thetaFm = 90-returnBearing(TC) #direction of the heading of the TC (Cartesian, clockwise from x axis)
TCi = TC[46]
The second thing required to run the model is a list of parameters, which are provided for the default settings with the package and shown below.
paramsTable = read.csv(system.file("extdata/tuningParams/defult_params.csv",package = "TCHazaRds"))
#paramsTable$value[6:7] = c(0,0)
knitr::kable(paramsTable,caption = "Parameter file")
param | value | description |
---|---|---|
eP | 1010.0000 | “environmental pressure [hPa]” |
rMaxModel | 1.0000 | “TC radius of maximum winds model c(‘AP21’=0,‘MK14’=1,‘WR04’=2,‘VW08’=3,‘TW08’=4), or NA to use input TC\(RMW, see function rMax_modelsR()" | |vMaxModel | 1.0000|"TC maximum velocity model c('AP21'=0,'MK14'=1,'WR04'=2,'VW08'=3,'AH77'=4), or NA to use input TC\)VMAX, see function vMax_modelsR()” |
betaModel | 1.0000 | “TC beta model c(‘AP21’=0,‘MK14’=1,‘WR04’=2,‘VW08’=3,‘AH77’=4), or NA to use input TC$B, see function beta_modelsR()” |
pressureProfileModel | 0.0000 | “TC pressure profile c(‘Holland’=0,‘McConochie’=2)” |
windProfileModel | 2.0000 | “TC wind profile c(‘Holland’=0,‘McConochie’=2)” |
windVortexModel | 2.0000 | “TC wind vortex model c(‘Kepert’=0,‘Hubbert’=1,‘McConochie’=2,‘Jelesnianski’=4)” |
g | 9.8100 | “acceleration due to gravity [m/s2]” |
rhoa | 1.1400 | “air density [kg/m3]” |
surface | 1.0000 | “equals one if winds are reduced from the gradient level to the surface, otherwise gradient winds are returned.[-]” |
Decay_a1 | 0.6150 | “exponential surface wind decay inland constant [-]” |
Decay_a2 | 0.9450 | “exponential surface wind decay over water constant [-]” |
Decay_a3 | 0.5125 | “exponential surface wind decay inland exponent [-]” |
Wave_a | 0.2900 | “O’Grady 2024 eq.1 a parameter” |
Wave_x | 1.0600 | “O’Grady 2024 eq.1 x parameter” |
Wave_b | -0.0157 | “O’Grady 2024 eq.1 b parameter” |
Wave_c | -0.0294 | “O’Grady 2024 eq.1 c parameter” |
finally, the domain and geometry for the model output needs to be
defined. The domain size and coordinates are calculated with the
land_geometry
function. A domain can simply be defined with
terra::rast
. Further to this a coastline polygon can be
rasterize
’d to define land, and the inland distance can be
calculated with the terra::costDistance
function to reduce
winds overland due to terrestrial roughness (under development and
commented out for now).
r = rast(xmin = 145,xmax=149,ymin = -19,ymax = -16.5,resolution=.01)
values(r) = 0
#GEO_land = land_geometry(r,r)
#
land_v <- vect(system.file("extdata/OSM_500m_QLD/OSM_500m_QLD.shp", package="TCHazaRds"))
land_r = rasterize(land_v,r,touches=TRUE,background=0)
inland_proximity = terra::costDist(land_r,target = 0,scale=1)
GEO_land = land_geometry(land_r,inland_proximity)
#plot(inland_proximity,main = "Inland Distance (m)")
#plot(TC,add=TRUE)
Now that we have the three inputs (tracks, parameters and model
output geometry) we can compute and plot the spatial wind hazard. See Making maps in R for
plotting method. Ocean Wave parameters can be returned with
returnWaves = TRUE
ats = seq(0, 65, length=14)
HAZi = TCHazaRdsWindField(GEO_land = GEO_land,TC = TCi,paramsTable=paramsTable,returnWaves = TRUE)
library(raster) # convert for raster plots
dummy = raster::raster()
TC_sp = list("sp.lines",as(TC,"Spatial"),col="black")
sp::spplot(HAZi,"Sw",at=ats,sp.layout = TC_sp,main = "Surface wind speed [m/s]")
ats = seq(0, 16, length=9)
sp::spplot(HAZi,"Hs0",at=ats,sp.layout = TC_sp,main = "Deep water significant wave height [m]")
The package rasterVis::
allows pretty spatial vector
plots of the wind field via the vectorplot
function (tested
on MS-Windows machine).
ats = seq(0, 65, length=14)
if (.Platform$OS.type == "windows"){
UV = as(c(HAZi["Uw"],HAZi["Vw"]),"Raster") #need to convert back to raster
rasterVis::vectorplot(UV, isField='dXY', col.arrows='white', aspX=0.002,aspY=0.002,at=ats ,
colorkey=list(at=ats), par.settings=viridisTheme)+latticeExtra::layer(sp.lines(as(TC,"Spatial"),col="red"))
}
The hazard can be also calculated for the entire track too (by adding
a s
to the end of TCHazaRdsWindField
to make
it plural), and then the maximum wind speed at each grid cell can be
plotted.
HAZ = TCHazaRdsWindFields(GEO_land=GEO_land,TC=TC,paramsTable=paramsTable)
sp::spplot(max(HAZ$Sw),at=ats,sp.layout = TC_sp)
The track can be interpolate to say, hourly intervals by defining an
outdate
from the start to the end date of the TC, stepping
by 3600 seconds. The output from these functions can be written to a
netcdf file for input to force hydrodynamic or wave modelling by
including outfile
filename in the function call (not shown
here, see ?TCHazaRdsWindFields
).
outdate = seq(strptime(TC$ISO_TIME[1],"%Y-%m-%d %H:%M:%S",tz="UTC"),
strptime(rev(TC$ISO_TIME)[1],"%Y-%m-%d %H:%M:%S",tz="UTC"),
3600)
HAZI = TCHazaRdsWindFields(outdate=outdate,GEO_land=GEO_land,TC=TC,paramsTable=paramsTable)
sp::spplot(max(HAZI$Sw),at=ats,sp.layout = TC_sp)
Time series data can be computed for a single location. Below is a comparison of the raw IBTrACS time step and the track interpolated to 10 minute intervals.(tested on MS-Windows machine)
outdate = seq(strptime(TC$ISO_TIME[1],"%Y-%m-%d %H:%M:%S",tz="UTC"),
strptime(rev(TC$ISO_TIME)[1],"%Y-%m-%d %H:%M:%S",tz="UTC"),
600)
GEO_landp = data.frame(dem=0,lons = 147,lats=-18,f=-4e-4,inlandD = 0)
HAZts = TCHazaRdsWindTimeSereies(GEO_land=GEO_landp,TC=TC,paramsTable = paramsTable)
HAZtsi = TCHazaRdsWindTimeSereies(outdate = outdate,GEO_land=GEO_landp,TC=TC,paramsTable = paramsTable)
main = paste(TCi$NAME[1],TCi$SEASON[1],"at",GEO_landp$lons,GEO_landp$lats)
if (.Platform$OS.type == "windows"){
suppressWarnings(with(HAZts,plot(date,Sw,format = "%b-%d %HZ",type="l",main = main,ylab = "Wind speed [m/s]")))
with(HAZtsi,lines(date,Sw,col=2))
legend("topleft",c("6 hrly","10 min interpolated"),col = c(1,2),lty=1)
}
Wind profiles can be calculated for a single time step. Here we estimate the wind speed values along the profile that is 90 degrees clockwise (at right angles) from the TC heading/bearing direction.
TCi$thetaFm = 90-returnBearing(TCi)
pp <- TCProfilePts(TC_line = TCi,bear=TCi$thetaFm+90,length =150,step=1)
#extract the GEO_land
GEO_land_v = extract(GEO_land,pp,bind=TRUE,method = "bilinear")
HAZp = TCHazaRdsWindProfile(GEO_land_v,TCi,paramsTable)
HAZie = extract(HAZi,pp,bind=TRUE)#,method = "bilinear")
wcol = colorRampPalette(c("white","lightblue","blue","violet","purple"))
#see ?terra::plot
plot(HAZi,"Sw",levels=ats,col = wcol(13),range = range(ats),type="continuous",all_levels=TRUE)
#plot(HAZp,add=TRUE,cex=1.2)
plot(HAZp,"Sw",levels=ats,col = wcol(13),range = range(ats),type="continuous",border="grey")#,all_levels=TRUE)
lines(TC)
Positive radial distance values are to the right of the forward motion (90 deg clockwise).
plot(HAZp$radialdist,HAZp$Sw,type="l",xlab = "Radial distance [km]",ylab = "Wind speed [m/s]");grid()
Julian O’Grady is a @csiro.au climate scientist investigating coastal hazards and impacts.