Additional Collaborators:
Tim LaRow (FSU-COAPS)
Michael Wehner (NCAR-CAM)
Ming Zhao (GFDL-HiRAM)
Hiroyuki Murakami (MRI-AGCM)
file:///C:/Users/Sarah/Dropbox/SpatialExtremes/Sarah/allModels.html
We know that tropical cyclones (TCs – including hurricanes, tropical storms, typhoons, and cyclones) can devastate coastal communities:
Given the destruction caused by hurricanes, many people are asking how climate change (e.g., warming sea surface waters) might affect TC activity.
Note that many of these studies use global climate models (GCMs) to make predictions about the effects of climate change on TC activity.
My question:
How well do climate models simulate the statistical relationship between TC intensity and sea surface temperatures (SST)?
If we want to use climate models to understand the future impacts of rising SSTs on TC intensity, we must first make sure that these models are able to reproduce the historical relationship between TC intensity and SST.
Here I examine the relationship between SST and TC intensity using observed and climate model data from the 1979–2010 time period.
date()
## [1] "Wed Apr 08 09:57:32 2015"
Set the working directory and make the required packages available. I also work from several R scripts to speed things up in certain places. In the future I should make these accessible via my website for transparency and reproducibility purposes!
# Set "eval=TRUE" when using PC
setwd("C:/Users/Sarah/Dropbox/SpatialExtremes")
require(ggplot2); require(rgdal); require(ismev); require(ncdf)
library(mapproj); library(mapdata); library(maptools); library(maps); library(grid); require(plyr)
library(colorRamps); library(RColorBrewer); require(spdep); require(psych); require(boot); require(wesanderson)
source("C:/Users/Sarah/Dropbox/SpatialExtremes/selectData.R")
source("C:/Users/Sarah/Dropbox/SpatialExtremes/ismevplus.R")
source("C:/Users/Sarah/Dropbox/SpatialExtremes/Kerrycanes/sensPoly.R")
source("C:/Users/Sarah/Dropbox/spatialextremes/ohcFunctions.R")
source("C:/Users/Sarah/Dropbox/SpatialExtremes/sensitivityUncertainty.R")
Load Observed (best-track) and GCM data. Climate model data come from the following 4 models:
Subset on tropical storms and hurricanes and convert the wind speeds from knots to m/s. Finally, subtract 60% of the forward motion from the wind speed to approximate the rotational velocity (as per Emanuel (2008))
# Note: End in 2009 rather than 2010 (MRI only goes through 8/2010)
# load("~/Dropbox/SpatialExtremes/best.use.RData")
load("C:/Users/Sarah/Dropbox/SpatialExtremes/best.use.RData")
begin = 1979; end = 2010
Wind.df = best.use[best.use$Yr >= begin & best.use$Yr <= end, ]
Wind.df = subset(Wind.df, Type=="TS" | Type=="HU")
Wind.df$WmaxS = Wind.df$WmaxS * .5144
Wind.df$maguv = Wind.df$maguv * .5144
Wind.df$WmaxS = Wind.df$WmaxS - Wind.df$maguv * .6
#CAM
#load("~/Dropbox/GCMTrackData/CAMTracks_NAtl.RData")
load("C:/Users/Sarah/Dropbox/GCMTrackData/CAMTracks_NAtl.RData")
beginC = 1979; endC=2005
CAM.df = na.df1[na.df1$Yr >= beginC & na.df1$Yr <= endC, ]
CAM.df$WmaxS = CAM.df$WmaxS - CAM.df$maguv * .6
#GFDL-HiRAM (r1)
#load("~/Dropbox/SpatialExtremes/gfdlTracks_r1.df.RData")
load("C:/Users/Sarah/Dropbox/SpatialExtremes/gfdlTracks_r1.df.RData")
beginG = 1981; endG = 2009
GFDL.df = natltracks.df1[natltracks.df1$Yr >= beginG &
natltracks.df1$Yr <= endG, ]
GFDL.df$WmaxS = GFDL.df$WmaxS - GFDL.df$maguv * .6
# FSU-COAPS (r1)
#load("~/Dropbox/SpatialExtremes/fsu_r1i1p1_ATL.RData")
load("C:/Users/Sarah/Dropbox/SpatialExtremes/fsu_r1i1p1_ATL.RData")
beginF = 1982; endF = 2009
FSU.df = fsuTracks.df[fsuTracks.df$Yr >= beginF &
fsuTracks.df$Yr <= endF, ]
FSU.df$WmaxS = FSU.df$WmaxS - FSU.df$maguv * .6
# MRI
#load("~/Dropbox/SpatialExtremes/mriTracks.df.RData")
load("C:/Users/Sarah/Dropbox/SpatialExtremes/mriTracks.df.RData")
MRI.df = mriTracks.df[mriTracks.df$Yr >= begin &
mriTracks.df$Yr <= end, ]
MRI.df$WmaxS = MRI.df$WmaxS - MRI.df$maguv * .6
WindC.df = subset(Wind.df, Yr >= beginC & Yr <= endC) # Obs TCs: 1979--2005
WindG.df = subset(Wind.df, Yr >= beginG & Yr <= endG) # Obs TCs: 1981--2009
WindF.df = subset(Wind.df, Yr >= beginF & Yr <= endF) # Obs TCs: 1982--2008
o.TCs = length(unique(Wind.df$Sid)) #372 (Obs)
m.TCs = length(unique(MRI.df$Sid)) #338 (MRI)
c.TCs = length(unique(CAM.df$Sid)) #387 (CAM)
g.TCs = length(unique(GFDL.df$Sid)) #418 (GFDL)
f.TCs = length(unique(FSU.df$Sid)) #392 (FSU)
Figure 1: Comparison of wind speed densities (top) and cumulative distributions (bottom) for best-track and GCM-generated TCs. Top: Frequency of hourly TC records. Rotational intensity shown in m/s. Bottom: Cumulative Distribution of hourly hurricane records
Calculate the mean and skewness for each wind speed distribution.
mC = mean(CAM.df$WmaxS) # 24.24
mM = mean(MRI.df$WmaxS) # 27.35
mG = mean(GFDL.df$WmaxS) # 18.02
mF = mean(FSU.df$WmaxS) # 19.33
mO = mean(Wind.df$WmaxS) # 28.83
sC = skew(CAM.df$WmaxS) # 0.699
sM = skew(MRI.df$WmaxS) # 0.479
sG = skew(GFDL.df$WmaxS) # 0.225
sF = skew(FSU.df$WmaxS) # -0.0809
sO = skew(Wind.df$WmaxS) # 1.02
Load NOAA’s extended reconstructed SST data set and calculate average SSTs for each of the model time periods. Assign a Lambert conformal conic projection to the SST data (+proj) to create a spatial data frame of SST data.
#nc = open.ncdf("~/Dropbox/SpatialExtremes/sst.mnmean.nc")
nc = open.ncdf("C:/Users/Sarah/Dropbox/SpatialExtremes/sst.mnmean.nc")
avgsstM = reformat.SST(nc, begin, end, 8, 9, 10)
avgsstC = reformat.SST(nc, beginC, endC, 8, 9, 10)
avgsstG = reformat.SST(nc, beginG, endG, 8, 9, 10)
avgsstF = reformat.SST(nc, beginF, endF, 8, 9, 10)
rm(nc)
ll = "+proj=longlat +datum=WGS84"
lcc = "+proj=lcc +lat_1=60 +lat_2=30 +lon_0=-60"
coordinates(avgsstM) = c("lon", "lat")
proj4string(avgsstM) = CRS(ll)
sstM.sdf = spTransform(avgsstM, CRS(lcc))
coordinates(avgsstC) = c("lon", "lat")
proj4string(avgsstC) = CRS(ll)
sstC.sdf = spTransform(avgsstC, CRS(lcc))
coordinates(avgsstG) = c("lon", "lat")
proj4string(avgsstG) = CRS(ll)
sstG.sdf = spTransform(avgsstG, CRS(lcc))
coordinates(avgsstF) = c("lon", "lat")
proj4string(avgsstF) = CRS(ll)
sstF.sdf = spTransform(avgsstF, CRS(lcc))
As with the SST data, assign a Lambert Conformal Conic projection to the TC track data to create spatial data frames.
WindM.sdf = Wind.df
coordinates(WindM.sdf) = c("lon", "lat")
proj4string(WindM.sdf) = CRS(ll)
WindM.sdf = spTransform(WindM.sdf, CRS(lcc))
WindC.sdf = WindC.df
coordinates(WindC.sdf) = c("lon", "lat")
proj4string(WindC.sdf) = CRS(ll)
WindC.sdf = spTransform(WindC.sdf, CRS(lcc))
WindG.sdf = WindG.df
coordinates(WindG.sdf) = c("lon", "lat")
proj4string(WindG.sdf) = CRS(ll)
WindG.sdf = spTransform(WindG.sdf, CRS(lcc))
WindF.sdf = WindF.df
coordinates(WindF.sdf) = c("lon", "lat")
proj4string(WindF.sdf) = CRS(ll)
WindF.sdf = spTransform(WindF.sdf, CRS(lcc))
CAM.sdf = CAM.df
coordinates(CAM.sdf) = c("lon", "lat")
proj4string(CAM.sdf) = CRS(ll)
CAM.sdf = spTransform(CAM.sdf, CRS(lcc))
MRI.sdf = MRI.df
coordinates(MRI.sdf) = c("lon", "lat")
proj4string(MRI.sdf) = CRS(ll)
MRI.sdf = spTransform(MRI.sdf, CRS(lcc))
GFDL.sdf = GFDL.df
coordinates(GFDL.sdf) = c("lon", "lat")
proj4string(GFDL.sdf) = CRS(ll)
GFDL.sdf = spTransform(GFDL.sdf, CRS(lcc))
FSU.sdf = FSU.df
coordinates(FSU.sdf) = c("lon", "lat")
proj4string(FSU.sdf) = CRS(ll)
FSU.sdf = spTransform(FSU.sdf, CRS(lcc))
Define a set of equal area hexagons that cover all sets of track data. Set the random seed for a quasi-random starting location for the tessellation (useful for future testing).
set.seed(1025)
bb = matrix(0, nrow=2, ncol=2)
bb[2,1] = bbox(FSU.sdf)[2,1]*.8
bb[1,1] = bbox(MRI.sdf)[1,1]*1.35
bb[1,2] = bbox(CAM.sdf)[1,2]*1.08
bb[2,2] = bbox(GFDL.sdf)[2,2]*1.08
hpt = spsample(CAM.sdf, type="hexagonal", n=150, bb=bb)
hpg = HexPoints2SpatialPolygons(hpt)
plot(hpg)
plot(WindM.sdf, add=TRUE, pch=".", col="red")
plot(CAM.sdf, add=TRUE, pch=".", col="blue")
plot(GFDL.sdf, add=TRUE, pch=".", col="green")
plot(FSU.sdf, add=TRUE, pch=".", col="gray")
plot(MRI.sdf, add=TRUE, pch=".", col="magenta")
np = length(hpg@polygons) # 122
area = hpg@polygons[[1]]@area * 10^-6
These hexagons are 816,355.3 km^2 – bigger than Texas but not quite as big as Alaska.
Next, use the “over” function to find out which hexagon each track point occurs in (do this for all five TC data sets). Add a “hexid” column to each of the track spatial data frames.
hexidOBSm = over(x=WindM.sdf, y=hpg)
WindM.sdf$hexid = hexidOBSm
hexidOBSc = over(x=WindC.sdf, y=hpg)
WindC.sdf$hexid = hexidOBSc
hexidOBSg = over(x=WindG.sdf, y=hpg)
WindG.sdf$hexid = hexidOBSg
hexidOBSf = over(x=WindF.sdf, y=hpg)
WindF.sdf$hexid = hexidOBSf
hexidCAM = over(x=CAM.sdf, y=hpg)
CAM.sdf$hexid = hexidCAM
hexidMRI = over(x=MRI.sdf, y=hpg)
MRI.sdf$hexid = hexidMRI
hexidGFDL = over(x=GFDL.sdf, y=hpg)
GFDL.sdf$hexid = hexidGFDL
hexidFSU = over(x=FSU.sdf, y=hpg)
FSU.sdf$hexid = hexidFSU
Use the “ddply” function to create data frames for each set of track data that consist of three columns: 1 column indicating the hexagon ID, another column indicating the number of TCs for that hexagon, and a third column indicating the maximum TC wind speed for that hexagon. Thus, the number of rows corresponds to the number of hexagons.
OBSstatsM = ddply(WindM.sdf@data, .(hexid, Sid), summarize,
nhr = length(Sid),
WmaxS = max(WmaxS)
)
OBSstatsM2 = ddply(OBSstatsM, .(hexid), summarize,
countOBS = length(Sid),
WmaxOBS = max(WmaxS)
)
OBSstatsC = ddply(WindC.sdf@data, .(hexid, Sid), summarize,
nhr = length(Sid),
WmaxS = max(WmaxS)
)
OBSstatsC2 = ddply(OBSstatsC, .(hexid), summarize,
countOBS = length(Sid),
WmaxOBS = max(WmaxS)
)
OBSstatsG = ddply(WindG.sdf@data, .(hexid, Sid), summarize,
nhr = length(Sid),
WmaxS = max(WmaxS)
)
OBSstatsG2 = ddply(OBSstatsG, .(hexid), summarize,
countOBS = length(Sid),
WmaxOBS = max(WmaxS)
)
OBSstatsF = ddply(WindF.sdf@data, .(hexid, Sid), summarize,
nhr = length(Sid),
WmaxS = max(WmaxS)
)
OBSstatsF2 = ddply(OBSstatsF, .(hexid), summarize,
countOBS = length(Sid),
WmaxOBS = max(WmaxS)
)
######################################################
CAMstats = ddply(CAM.sdf@data, .(hexid, Sid), summarize,
nhr = length(Sid),
WmaxS = max(WmaxS)
)
CAMstats2 = ddply(CAMstats, .(hexid), summarize,
countMOD = length(Sid),
WmaxMOD = max(WmaxS)
)
#########################################################
MRIstats = ddply(MRI.sdf@data, .(hexid, Sid), summarize,
nhr = length(Sid),
WmaxS = max(WmaxS)
)
MRIstats2 = ddply(MRIstats, .(hexid), summarize,
countMOD = length(Sid),
WmaxMOD = max(WmaxS)
)
#########################################################
GFDLstats = ddply(GFDL.sdf@data, .(hexid, Sid), summarize,
nhr = length(Sid),
WmaxS = max(WmaxS)
)
GFDLstats2 = ddply(GFDLstats, .(hexid), summarize,
countMOD = length(Sid),
WmaxMOD = max(WmaxS)
)
#########################################################
FSUstats = ddply(FSU.sdf@data, .(hexid, Sid), summarize,
nhr = length(Sid),
WmaxS = max(WmaxS)
)
FSUstats2 = ddply(FSUstats, .(hexid), summarize,
countMOD = length(Sid),
WmaxMOD = max(WmaxS)
)
Note: I’m not going to look at limiting intensity since it is underestimated over the time period of interest here. Instead, my goal is to understand the relationship between per hexagon maximum intensity and per hexagon average August–October SST.
Set up a data frame with counts, wind speeds, and hexid. Subset on only those hexagons with at least 15 TCs with maximum wind speeds >= 17 m/s. Also, remove any hexagons over land or over the East Pacific.
hexDataM.obs = subset(OBSstatsM2, WmaxOBS >= 17) # 54 by 3
hexDataM.obs = subset(hexDataM.obs, countOBS >= 15) # 32 by 3
hexDataM.mod = subset(MRIstats2, WmaxMOD >= 17) # 53 by 3
hexDataM.mod = subset(hexDataM.mod, countMOD >= 15) # 33 by 3
hexDataM.mod = subset(hexDataM.mod, hexid != 30)
row.names(hexDataM.obs) = paste("ID", hexDataM.obs$hexid, sep="")
row.names(hexDataM.mod) = paste("ID", hexDataM.mod$hexid, sep="")
##################################################################
hexDataC.obs = subset(OBSstatsC2, WmaxOBS >= 17) # 52 by 3
hexDataC.obs = subset(hexDataC.obs, countOBS >= 15) # 32 by 3
hexDataC.mod = subset(CAMstats2, WmaxMOD >= 17) # 65 by 3
hexDataC.mod = subset(hexDataC.mod, countMOD >= 15) # 47 by 3
hexDataC.mod = subset(hexDataC.mod, hexid != 16)
hexDataC.mod = subset(hexDataC.mod, hexid != 17)
hexDataC.mod = subset(hexDataC.mod, hexid != 18)
hexDataC.mod = subset(hexDataC.mod, hexid != 30)
hexDataC.mod = subset(hexDataC.mod, hexid != 31)
row.names(hexDataC.obs) = paste("ID", hexDataC.obs$hexid, sep="")
row.names(hexDataC.mod) = paste("ID", hexDataC.mod$hexid, sep="")
##################################################################
hexDataG.obs = subset(OBSstatsG2, WmaxOBS >= 17) # 52 by 3
hexDataG.obs = subset(hexDataG.obs, countOBS >= 15) # 32 by 3
hexDataG.mod = subset(GFDLstats2, WmaxMOD >= 17) # 51 by 3
hexDataG.mod = subset(hexDataG.mod, countMOD >= 15) # 39 by 3
hexDataG.mod = subset(hexDataG.mod, hexid != 17)
hexDataG.mod = subset(hexDataG.mod, hexid != 30)
hexDataG.mod = subset(hexDataG.mod, hexid != 31)
row.names(hexDataG.obs) = paste("ID", hexDataG.obs$hexid, sep="")
row.names(hexDataG.mod) = paste("ID", hexDataG.mod$hexid, sep="")
##################################################################
hexDataF.obs = subset(OBSstatsF2, WmaxOBS >= 17) # 52 by 3
hexDataF.obs = subset(hexDataF.obs, countOBS >= 15) # 32 by 3
hexDataF.mod = subset(FSUstats2, WmaxMOD >= 17) # 55 by 3
hexDataF.mod = subset(hexDataF.mod, countMOD >= 15) # 31 by 3
row.names(hexDataF.obs) = paste("ID", hexDataF.obs$hexid, sep="")
row.names(hexDataF.mod) = paste("ID", hexDataF.mod$hexid, sep="")
Make spatial polygons data frames for plotting purposes. Also, calculate the per hexagon average August-October SST.
hspdfM.obs = SpatialPolygonsDataFrame(hpg[row.names(hexDataM.obs)],
hexDataM.obs)
hspdfM.mod = SpatialPolygonsDataFrame(hpg[row.names(hexDataM.mod)],
hexDataM.mod)
avgsstM.obs = over(x=hpg[row.names(hexDataM.obs)], y=sstM.sdf, fn=mean)
avgsstM.mod = over(x=hpg[row.names(hexDataM.mod)], y=sstM.sdf, fn=mean)
hspdfM.obs$avgsst = avgsstM.obs$avgsst
hspdfM.mod$avgsst = avgsstM.mod$avgsst
hspdf.sst = subset(hspdfM.obs@data, avgsst >= 25)
hspdf.sst = SpatialPolygonsDataFrame(hpg[row.names(hspdf.sst)], hspdf.sst)
##################################################################
hspdfC.obs = SpatialPolygonsDataFrame(hpg[row.names(hexDataC.obs)],
hexDataC.obs)
hspdfC.mod = SpatialPolygonsDataFrame(hpg[row.names(hexDataC.mod)],
hexDataC.mod)
avgsstC.obs = over(x=hpg[row.names(hexDataC.obs)], y=sstC.sdf, fn=mean)
avgsstC.mod = over(x=hpg[row.names(hexDataC.mod)], y=sstC.sdf, fn=mean)
hspdfC.obs$avgsst = avgsstC.obs$avgsst
hspdfC.mod$avgsst = avgsstC.mod$avgsst
##################################################################
hspdfG.obs = SpatialPolygonsDataFrame(hpg[row.names(hexDataG.obs)],
hexDataG.obs)
hspdfG.mod = SpatialPolygonsDataFrame(hpg[row.names(hexDataG.mod)],
hexDataG.mod)
avgsstG.obs = over(x=hpg[row.names(hexDataG.obs)], y=sstG.sdf, fn=mean)
avgsstG.mod = over(x=hpg[row.names(hexDataG.mod)], y=sstG.sdf, fn=mean)
hspdfG.obs$avgsst = avgsstG.obs$avgsst
hspdfG.mod$avgsst = avgsstG.mod$avgsst
##################################################################
hspdfF.obs = SpatialPolygonsDataFrame(hpg[row.names(hexDataF.obs)],
hexDataF.obs)
hspdfF.mod = SpatialPolygonsDataFrame(hpg[row.names(hexDataF.mod)],
hexDataF.mod)
avgsstF.obs = over(x=hpg[row.names(hexDataF.obs)], y=sstF.sdf, fn=mean)
avgsstF.mod = over(x=hpg[row.names(hexDataF.mod)], y=sstF.sdf, fn=mean)
hspdfF.obs$avgsst = avgsstF.obs$avgsst
hspdfF.mod$avgsst = avgsstF.mod$avgsst
Set up map borders
cl = map("worldHires", xlim=c(-120, 20), ylim=c(-10, 70), plot=TRUE, resolution=.7)
clp = map2SpatialLines(cl, proj4string=CRS(ll))
clp = spTransform(clp, CRS(lcc))
l1 = list("sp.lines", clp, col="gray")
Figure 2: Per hexagon frequency and intensity maps for observed hexagons over the 1979-2010 (MRI) period).
Figure 3: Frequency maps for grids with at least 15 observed AND modeled TCs. Red text indicates per hexagon observed TC counts
Figure 4: Per hexagon maximum intensity maps for grids with at least 15 modeled TCs. Blue text indicates per hexagon observed maximum TC intensity
Subset on only those hexagons with SST >= 25CC and regress per hexagon maximum intensity onto SST to obtain an estimate of the sensitivity of TC maximum intensity to SST (the slope coefficient). This first is done for the MRI model:
datM.obs = as.data.frame(hspdfM.obs)
datM.obs = subset(datM.obs, avgsst >= 25)
#datM.obs2 = as.data.frame(hspdfM.obs2)
#datM.obs2 = subset(datM.obs2, avgsst >= 25)
datM.mod = as.data.frame(hspdfM.mod)
datM.mod = subset(datM.mod, avgsst >= 25)
lmM.obs = lm(WmaxOBS ~ avgsst, data=datM.obs)
resM.obs = residuals(lmM.obs)
ciM.obs = confint(lmM.obs) # 4.54, 8.69
## 6.6 +/- 1.01
## t-val = 6.57
## R^2 = 0.6329
#lmM.obs2 = lm(WmaxOBS ~ avgsst, data=datM.obs2)
#ciM.obs2 = confint(lmM.obs2) # 3.51, 8.74
## 6.1 +/- 1.25
## t-val = 4.91
## R^2 = 0.5591
lmM.mod = lm(WmaxMOD ~ avgsst, data=datM.mod)
resM.mod = residuals(lmM.mod)
ciM.mod = confint(lmM.mod) #-2.67, 2.66
## -7.9e-4 +/- 1.29
## t-val = -0.001
## R^2 = 1.651e-8
r2.M.obs = summary(lmM.obs)$r.squared
r2.M.mod = summary(lmM.mod)$r.squared
Same as previus chunk, but this time for the CAM:
datC.obs = as.data.frame(hspdfC.obs)
datC.obs = subset(datC.obs, avgsst >= 25)
datC.mod = as.data.frame(hspdfC.mod)
datC.mod = subset(datC.mod, avgsst >= 25)
lmC.obs = lm(WmaxOBS ~ avgsst, data=datC.obs)
resC.obs = residuals(lmC.obs)
ciC.obs = confint(lmC.obs) # 4.78, 9.12
## 6.9 +/- 1.05
## t-val = 6.60
## R^2 = 0.6353
lmC.mod = lm(WmaxMOD ~ avgsst, data=datC.mod)
resC.mod = residuals(lmC.mod)
ciC.mod = confint(lmC.mod) # -0.79, 5.07
## 2.1 +/- 1.43
## t-val = 1.49
## R^2 = 0.07134
r2.C.obs = summary(lmC.obs)$r.squared
r2.C.mod = summary(lmC.mod)$r.squared
Same as previus chunk, but this time for the GFDL:
datG.obs = as.data.frame(hspdfG.obs)
datG.obs = subset(datG.obs, avgsst >= 25)
datG.mod = as.data.frame(hspdfG.mod)
datG.mod = subset(datG.mod, avgsst >= 25)
lmG.obs = lm(WmaxOBS ~ avgsst, data=datG.obs)
resG.obs = residuals(lmG.obs)
ciG.obs = confint(lmG.obs) #3.94, 8.45
## 6.2 +/- 1.10
## t-val = 5.65
## R^2 = 0.5611
lmG.mod = lm(WmaxMOD ~ avgsst, data=datG.mod)
resG.mod = residuals(lmG.mod)
ciG.mod = confint(lmG.mod) # -0.635, 2.21
## 7.9e-1 +/- 6.93e-1
## t-val = 1.14
## R^2 = 0.04555
r2.G.obs = summary(lmG.obs)$r.squared
r2.G.mod = summary(lmG.mod)$r.squared
Same as previus chunk, but this time for the FSU:
datF.obs = as.data.frame(hspdfF.obs)
datF.obs = subset(datF.obs, avgsst >= 25)
datF.mod = as.data.frame(hspdfF.mod)
datF.mod = subset(datF.mod, avgsst >= 25)
lmF.obs = lm(WmaxOBS ~ avgsst, data=datF.obs)
resF.obs = residuals(lmF.obs)
ciF.obs = confint(lmF.obs) # 3.95, 8.49
## 6.2 +/- 1.10
## t-val = 5.64
## R^2 = 0.5601
lmF.mod = lm(WmaxMOD ~ avgsst, data=datF.mod)
resF.mod = residuals(lmF.mod)
ciF.mod = confint(lmF.mod) # -3.01, 1.68
## -6.63e-1 +/- 1.13
## t-val = -0.585
## R^2 = 0.01464
r2.F.obs = summary(lmF.obs)$r.squared
r2.F.mod = summary(lmF.mod)$r.squared
Figure 5: Comparing the sensitivity of LI to SST.
Obtain the regression residuals
MRI.25.obs = subset(hspdfM.obs@data, avgsst >= 25)
MRI.25.mod = subset(hspdfM.mod@data, avgsst >= 25)
MRI.25.obs$res = resM.obs
MRI.25.mod$res = resM.mod
MRI.25.obs = SpatialPolygonsDataFrame(hpg[rownames(MRI.25.obs)], MRI.25.obs)
MRI.25.mod = SpatialPolygonsDataFrame(hpg[rownames(MRI.25.mod)], MRI.25.mod)
CAM.25.obs = subset(hspdfC.obs@data, avgsst >= 25)
CAM.25.mod = subset(hspdfC.mod@data, avgsst >= 25)
CAM.25.obs$res = resC.obs
CAM.25.mod$res = resC.mod
CAM.25.obs = SpatialPolygonsDataFrame(hpg[rownames(CAM.25.obs)], CAM.25.obs)
CAM.25.mod = SpatialPolygonsDataFrame(hpg[rownames(CAM.25.mod)], CAM.25.mod)
GFD.25.obs = subset(hspdfG.obs@data, avgsst >= 25)
GFD.25.mod = subset(hspdfG.mod@data, avgsst >= 25)
GFD.25.obs$res = resG.obs
GFD.25.mod$res = resG.mod
GFD.25.obs = SpatialPolygonsDataFrame(hpg[rownames(GFD.25.obs)], GFD.25.obs)
GFD.25.mod = SpatialPolygonsDataFrame(hpg[rownames(GFD.25.mod)], GFD.25.mod)
FSU.25.obs = subset(hspdfF.obs@data, avgsst >= 25)
FSU.25.mod = subset(hspdfF.mod@data, avgsst >= 25)
FSU.25.obs$res = resF.obs
FSU.25.mod$res = resF.mod
FSU.25.obs = SpatialPolygonsDataFrame(hpg[rownames(FSU.25.obs)], FSU.25.obs)
FSU.25.mod = SpatialPolygonsDataFrame(hpg[rownames(FSU.25.mod)], FSU.25.mod)
Calculate the pattern correlation of the residuals for the MRI vs. observed regressions:
mri.25.o = cbind(MRI.25.obs$hexid,
MRI.25.obs$res)
colnames(mri.25.o) = c("hexid", "res.o")
mri.25.o = data.frame(mri.25.o)
mri.25.m = cbind(MRI.25.mod$hexid,
MRI.25.mod$res)
colnames(mri.25.m) = c("hexid", "res.m")
mri.25.m = data.frame(mri.25.m)
mri.25.all = merge(mri.25.o, mri.25.m, by="hexid")
cor.test(mri.25.all$res.o, mri.25.all$res.m)
##
## Pearson's product-moment correlation
##
## data: mri.25.all$res.o and mri.25.all$res.m
## t = 3.454, df = 19, p-value = 0.00266
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.2587 0.8302
## sample estimates:
## cor
## 0.621
# 0.259, 0.830 (0.621)
Same as previous chunk, but for the CAM:
cam.25.o = cbind(CAM.25.obs$hexid,
CAM.25.obs$res)
colnames(cam.25.o) = c("hexid", "res.o")
cam.25.o = data.frame(cam.25.o)
cam.25.m = cbind(CAM.25.mod$hexid,
CAM.25.mod$res)
colnames(cam.25.m) = c("hexid", "res.m")
cam.25.m = data.frame(cam.25.m)
cam.25.all = merge(cam.25.o, cam.25.m, by="hexid")
cor.test(cam.25.all$res.o, cam.25.all$res.m)
##
## Pearson's product-moment correlation
##
## data: cam.25.all$res.o and cam.25.all$res.m
## t = 1.982, df = 24, p-value = 0.059
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.01434 0.66572
## sample estimates:
## cor
## 0.3751
# -0.0143, 0.666 (0.375)
Same as previous chunk, but for the GFDL:
gfd.25.o = cbind(GFD.25.obs$hexid,
GFD.25.obs$res)
colnames(gfd.25.o) = c("hexid", "res.o")
gfd.25.o = data.frame(gfd.25.o)
gfd.25.m = cbind(GFD.25.mod$hexid,
GFD.25.mod$res)
colnames(gfd.25.m) = c("hexid", "res.m")
gfd.25.m = data.frame(gfd.25.m)
gfd.25.all = merge(gfd.25.o, gfd.25.m, by="hexid")
cor.test(gfd.25.all$res.o, gfd.25.all$res.m)
##
## Pearson's product-moment correlation
##
## data: gfd.25.all$res.o and gfd.25.all$res.m
## t = 2.817, df = 23, p-value = 0.009781
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.1392 0.7513
## sample estimates:
## cor
## 0.5065
# 0.139, 0.751 (0.506)
Same as previous chunk, but for the FSU:
fsu.25.o = cbind(FSU.25.obs$hexid,
FSU.25.obs$res)
colnames(fsu.25.o) = c("hexid", "res.o")
fsu.25.o = data.frame(fsu.25.o)
fsu.25.m = cbind(FSU.25.mod$hexid,
FSU.25.mod$res)
colnames(fsu.25.m) = c("hexid", "res.m")
fsu.25.m = data.frame(fsu.25.m)
fsu.25.all = merge(fsu.25.o, fsu.25.m, by="hexid")
cor.test(fsu.25.all$res.o, fsu.25.all$res.m)
##
## Pearson's product-moment correlation
##
## data: fsu.25.all$res.o and fsu.25.all$res.m
## t = 3.116, df = 20, p-value = 0.005447
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.1977 0.8004
## sample estimates:
## cor
## 0.5716
# 0.198, 0.800 (0.572)
Fig. 6 The spatial distribution of the residuals for the regression of PI onto SSTs > 25. The top panel shows residuals for MERRA data while the bottom panel shows residuals for FSU/COAPS data
Does latitude describe any of the variability in per hexagon maximum TC intensity?
Add hexagon center latitudes to data frames
datM.obs$lat = coordinates(MRI.25.obs)[,2]
datM.mod$lat = coordinates(MRI.25.mod)[,2]
datC.obs$lat = coordinates(CAM.25.obs)[,2]
datC.mod$lat = coordinates(CAM.25.mod)[,2]
datG.obs$lat = coordinates(GFD.25.obs)[,2]
datG.mod$lat = coordinates(GFD.25.mod)[,2]
datF.obs$lat = coordinates(FSU.25.obs)[,2]
datF.mod$lat = coordinates(FSU.25.mod)[,2]
Regress Wmax ~ avgsst + lat (MRI)
cor.test(datM.obs$avgsst, datM.obs$lat)
##
## Pearson's product-moment correlation
##
## data: datM.obs$avgsst and datM.obs$lat
## t = -3.406, df = 25, p-value = 0.002231
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.7768 -0.2328
## sample estimates:
## cor
## -0.563
# -0.23, -0.78
lmM.lat.obs = lm(WmaxOBS ~ avgsst + lat, data=datM.obs)
# avgsst: 7.4 +/1 1.21 *** t-val = 6.11
# lat: 1.9e-6 +/-1.68e-6 t-val = 1.15
# R^2 = 0.652
cor.test(datM.mod$avgsst, datM.mod$lat)
##
## Pearson's product-moment correlation
##
## data: datM.mod$avgsst and datM.mod$lat
## t = -5.393, df = 23, p-value = 1.77e-05
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.8820 -0.4997
## sample estimates:
## cor
## -0.7473
# -0.50, -0.88
lmM.lat.mod = lm(WmaxMOD ~ avgsst + lat, data=datM.mod)
# avgsst: 3.9 +/- 1.64 * t-val = 2.37
# lat: 7.6e-6 +/-2.43e-6 ** t-val = 3.17
# R^2 = 0.3132
r2.latM.obs = summary(lmM.lat.obs)$r.squared
r2.latM.mod = summary(lmM.lat.mod)$r.squared
Regress Wmax ~ avgsst + lat (CAM)
cor.test(datC.obs$avgsst, datC.obs$lat)
# -0.23, -0.78
lmC.lat.obs = lm(WmaxOBS ~ avgsst + lat, data=datC.obs)
# avgsst: 8.0 +/- 1.23 *** t-val = 6.51
# lat: 2.7e-6 +/- 1.70e-6 t-val = 1.58
# R^2 = 0.6695
cor.test(datC.mod$avgsst, datC.mod$lat)
# -0.25, -0.76
lmC.lat.mod = lm(WmaxMOD ~ avgsst + lat, data=datC.mod)
# avgsst: 4.2 +/- 1.62 * t-val = 2.58
# lat: 4.9e-6 +/- 2.19e-6 * t-val = 2.25
# R^2 = 0.2131
r2.latC.obs = summary(lmC.lat.obs)$r.squared
r2.latC.mod = summary(lmC.lat.mod)$r.squared
Regress Wmax ~ avgsst + lat (GFDL)
cor.test(datG.obs$avgsst, datG.obs$lat)
# -0.23, -0.78
lmG.lat.obs = lm(WmaxOBS ~ avgsst + lat, data=datG.obs)
# avgsst: 7.1 +/- 1.31 *** t-val = 5.43
# lat: 2.2e-6 +/- 1.81e-6 t-val = 1.23
# R^2 = 0.5872
cor.test(datG.mod$avgsst, datG.mod$lat)
# -0.26, -0.78
lmG.lat.mod = lm(WmaxMOD ~ avgsst + lat, data=datG.mod)
# avgsst: 2.3 +/- 6.92e-1 ** t-val = 3.32
# lat: 3.8e-6 +/- 9.93e-7 *** t-val = 3.80
# R^2 = 0.3862
r2.latG.obs = summary(lmG.lat.obs)$r.squared
r2.latG.mod = summary(lmG.lat.mod)$r.squared
Regress Wmax ~ avgsst + lat (FSU)
cor.test(datF.obs$avgsst, datF.obs$lat)
# -0.23, -0.77
lmF.lat.obs = lm(WmaxOBS ~ avgsst + lat, data=datF.obs)
# avgsst: 7.1 +/- 1.32 *** t-val = 5.41
# lat: 2.2e-6 +/- 1.81e-6 t-val = 1.23
# R^2 = 0.5860
cor.test(datF.mod$avgsst, datF.mod$lat)
# -0.35, -0.83
lmF.lat.mod = lm(WmaxMOD ~ avgsst + lat, data=datF.mod)
# avgsst: 2.8 +/- 1.01 * t-val = 2.80
# lat: 6.0e-6 +/- 1.13e-6 *** t-val = 5.30
# R^2 = 0.5673
r2.latF.obs = summary(lmF.lat.obs)$r.squared
r2.latF.mod = summary(lmF.lat.mod)$r.squared
Improvements in explained variability by adding latitude as a predictor:
(R2Full - R2SSTonly)/R2SSTonly * 100%
## MRI
MRI.p.obs = r2.latM.obs*100 - r2.M.obs*100 # 1.91 %
MRI.p.mod = r2.latM.mod*100 - r2.M.mod*100 # 31.3 %
## CAM
CAM.p.obs = r2.latC.obs*100 - r2.C.obs*100 # 3.42 %
CAM.p.mod = r2.latC.mod*100 - r2.C.mod*100 # 14.2 %
## GFDL
GFD.p.obs = r2.latG.obs*100 - r2.G.obs*100 # 2.61 %
GFD.p.mod = r2.latG.mod*100 - r2.G.mod*100 # 34.1 %
## FSU
FSU.p.obs = r2.latF.obs*100 - r2.F.obs*100 # 2.59 %
FSU.p.mod = r2.latF.mod*100 - r2.F.mod*100 # 55.3 %
How does the specific starting point of the hexagon structure affect the results?
Generate 100 different tesselations, each slightly offset in space, and calculate the sensitivity for each. First, the CAM:
allSensCAM = matrix(0, ncol=2, nrow=100)
allSensCAM = data.frame(allSensCAM)
set.seed(1025)
bb = matrix(0, nrow=2, ncol=2)
bb[2,1] = bbox(FSU.sdf)[2,1]*.8
bb[1,1] = bbox(MRI.sdf)[1,1]*1.35
bb[1,2] = bbox(CAM.sdf)[1,2]*1.08
bb[2,2] = bbox(GFDL.sdf)[2,2]*1.08
for(i in 1:100){
print(i)
hpts = spsample(CAM.sdf, type="hexagonal", n=150, bb=bb)
hpg = HexPoints2SpatialPolygons(hpts)
allSensCAM[i,] = get.sensitivity3(WindC.sdf, CAM.sdf, hpg, sstC.sdf, 1979, 2005)
}
colnames(allSensCAM) = c("OBS", "CAM")
range(allSensCAM$OBS) ## 5.38, 11.3
range(allSensCAM$CAM) ## -0.131, 5.04
median(allSensCAM$OBS) ## 7.88
median(allSensCAM$CAM) ## 1.59
save(allSensCAM, file="allSensCAM.RData")
Same as previous chunk, but for the MRI:
allSensMRI = matrix(0, ncol=2, nrow=100)
allSensMRI = data.frame(allSensMRI)
set.seed(1025)
bb = matrix(0, nrow=2, ncol=2)
bb[2,1] = bbox(FSU.sdf)[2,1]*.8
bb[1,1] = bbox(MRI.sdf)[1,1]*1.35
bb[1,2] = bbox(CAM.sdf)[1,2]*1.08
bb[2,2] = bbox(GFDL.sdf)[2,2]*1.08
for(i in 1:100){
print(i)
hpts = spsample(MRI.sdf, type="hexagonal", n=150, bb=bb)
hpg = HexPoints2SpatialPolygons(hpts)
allSensMRI[i,] = get.sensitivity3(WindM.sdf, MRI.sdf, hpg, sstM.sdf, 1979, 2010)
}
colnames(allSensMRI) = c("OBS", "MRI")
range(allSensMRI$OBS) # 5.30, 10.43
range(allSensMRI$MRI) # -1.43, 3.30
median(allSensMRI$OBS) # 7.41
median(allSensMRI$MRI) # 0.223
save(allSensMRI, file="allSensMRI.RData")
Same as previous chunk, but for the GFDL:
allSensGFDL = matrix(0, ncol=2, nrow=100)
allSensGFDL = data.frame(allSensGFDL)
set.seed(1025)
bb = matrix(0, nrow=2, ncol=2)
bb[2,1] = bbox(FSU.sdf)[2,1]*.8
bb[1,1] = bbox(MRI.sdf)[1,1]*1.35
bb[1,2] = bbox(CAM.sdf)[1,2]*1.08
bb[2,2] = bbox(GFDL.sdf)[2,2]*1.08
for(i in 1:100){
print(i)
hpts = spsample(GFDL.sdf, type="hexagonal", n=150, bb=bb)
hpg = HexPoints2SpatialPolygons(hpts)
allSensGFDL[i,] = get.sensitivity3(WindG.sdf, GFDL.sdf, hpg, sstG.sdf, 1981, 2009)
}
colnames(allSensGFDL) = c("OBS", "GFDL")
range(allSensGFDL$OBS) ## 5.22, 10.44
range(allSensGFDL$GFDL) ## 0.191, 2.75
median(allSensGFDL$OBS) # 7.07
median(allSensGFDL$GFDL) # 1.06
save(allSensGFDL, file="allSensGFDL.RData")
Same as previous chunk, but for the FSU:
allSensFSU = matrix(0, ncol=2, nrow=100)
allSensFSU = data.frame(allSensFSU)
set.seed(1025)
bb = matrix(0, nrow=2, ncol=2)
bb[2,1] = bbox(FSU.sdf)[2,1]*.8
bb[1,1] = bbox(MRI.sdf)[1,1]*1.35
bb[1,2] = bbox(CAM.sdf)[1,2]*1.08
bb[2,2] = bbox(GFDL.sdf)[2,2]*1.08
for(i in 1:100){
print(i)
hpts = spsample(FSU.sdf, type="hexagonal", n=150, bb=bb)
hpg = HexPoints2SpatialPolygons(hpts)
allSensFSU[i,] = get.sensitivity3(WindF.sdf, FSU.sdf, hpg, sstF.sdf, 1982, 2009)
}
colnames(allSensFSU) = c("OBS", "FSU")
range(allSensFSU$OBS) # 5.12, 10.46
range(allSensFSU$FSU) # -2.00, 0.590
median(allSensFSU$OBS) # 7.10
median(allSensFSU$FSU) # -0.632
save(allSensFSU, file="allSensFSU.RData")
Fig. 8: Estimating uncertainty on sensitivity resulting from the specific configuration of the hexagon grid. We use per hexagon maximum intensity in place of the theoretical LI
#load("~/Dropbox/SpatialExtremes/allSensCAM.RData")
#load("~/Dropbox/SpatialExtremes/allSensMRI.RData")
#load("~/Dropbox/SpatialExtremes/allSensGFDL.RData")
#load("~/Dropbox/SpatialExtremes/allSensFSU.RData")
load("C:/Users/Sarah/Dropbox/SpatialExtremes/allSensCAM.RData")
load("C:/Users/Sarah/Dropbox/SpatialExtremes/allSensMRI.RData")
load("C:/Users/Sarah/Dropbox/SpatialExtremes/allSensGFDL.RData")
load("C:/Users/Sarah/Dropbox/SpatialExtremes/allSensFSU.RData")
SC = c(allSensCAM$OBS, allSensCAM$CAM)
Label = c(rep("Best-track", 100), rep("GCM", 100))
SC.df = data.frame(Label = Label, Sens = SC)
SC.df$type = rep("(b) CAM", 200)
SC.df = data.frame(SC.df)
SM = c(allSensMRI$OBS, allSensMRI$MRI)
Label = c(rep("Best-track", 100), rep("GCM", 100))
SM.df = data.frame(Label = Label, Sens = SM)
SM.df$type = rep("(a) MRI", 200)
SM.df = data.frame(SM.df)
SG = c(allSensGFDL$OBS, allSensGFDL$GFDL)
Label = c(rep("Best-track", 100), rep("GCM", 100))
SG.df = data.frame(Label = Label, Sens = SG)
SG.df$type = rep("(c) GFDL", 200)
SG.df = data.frame(SG.df)
SF = c(allSensFSU$OBS, allSensFSU$FSU)
Label = c(rep("Best-track", 100), rep("GCM", 100))
SF.df = data.frame(Label = Label, Sens = SF)
SF.df$type = rep("(d) FSU", 200)
SF.df = data.frame(SF.df)
sens.df = rbind(SC.df, SM.df, SG.df, SF.df)
sens.df = data.frame(sens.df)
p = ggplot(sens.df, aes(Sens, fill = Label)) + theme_bw()
p = p + geom_density(alpha=0.2) + facet_grid(~type)
p = p + xlab(expression(paste("Sensitivity of maximum intensity to SST [m s",{}^-1, " K", {}^-1,"]"))) +
ylab("Relative Frequency")
p = p + ggtitle('a') + theme(plot.title=element_text(hjust=2))
p = p + scale_fill_manual( values = c("blue","red"))
p = p + theme(axis.text=element_text(size=14),
axis.title=element_text(size=16,face="bold"))
p = p + theme(legend.text=element_text(size=14),
legend.title=element_text(size=14, face="bold"))
p = p + theme(strip.text.x = element_text(size = 12, face="bold"))
p = p + theme(legend.title=element_blank())
p