-
Notifications
You must be signed in to change notification settings - Fork 8
/
offGridWeights.R
148 lines (133 loc) · 4.98 KB
/
offGridWeights.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
offGridWeights<-function(s, gridList, np=2,
mKrigObject=NULL,
Covariance=NULL, covArgs=NULL,
aRange=NULL, sigma2=NULL,
giveWarnings=FALSE
){
#
# function assumes the grid is
# integer locations and 1:m by 1:n
# grid and off grid locations need to be transformed to that scale
#
# also assumes the grid extends two cells beyond any off
# e.g. s coordinates should be between
# 2 and m-3 and 2 and n-3
#
# If mKrigObject (result of fitting model) is given
# extract all the covariance information from it.
# For the Matern family besides aRange and sigma2 is the
# smoothness
if( !is.null( mKrigObject)){
sigma2<- mKrigObject$summary["sigma2"]
aRange<- mKrigObject$summary["aRange"]
Covariance<- mKrigObject$args$Covariance
if( is.null(Covariance)){
Covariance<- "Exponential"
}
covArgs<-mKrigObject$args
# some R arcania -- strip out all arguments used by say stationary.cov
# but not used by the Covariance function
# Do not want to call the covariance function with these extra args.
if( !is.null( covArgs) ){
argNames<- names( as.list( get(Covariance)))
argNames<- argNames[ -length(argNames)]
ind<- match( names(covArgs), argNames)
covArgs[is.na( ind)] <- NULL
}
}
m<- length( gridList$x)
n<- length( gridList$y)
dx<- gridList$x[2]- gridList$x[1]
dy<- gridList$y[2]- gridList$y[1]
M<- nrow( s)
# lower left corner of grid box containing the points
s0<- cbind(
trunc( (s[,1]- gridList$x[1] )/dx) + 1 ,
trunc( (s[,2]- gridList$y[1] )/dy) + 1
)
# index of locations when 2D array is unrolled
s0Index<- as.integer( s0[,1] + (s0[,2]-1)*m)
# check for more than one obs in a grid box
tableLoc<- table( s0Index)
ind<- (tableLoc > 1)
if( any( ind)){
cat("Found", sum(ind),
"grid box(es) containing more than 1 obs location", fill=TRUE)
cat("row/column indices and count", fill=TRUE)
print( cbind( rbind(s0[ind,]), tableLoc[ind]) )
#In most cases want this to stop the computation
if( !giveWarnings){
stop("Need the grid to separate observations")
}
else{
warning( "grid boxes include more than one off grid location.")
}
}
# np=2
# specific to 2nd degree neighborhood
# (2*np)^2 = 16 points total
#xshift<- rep( c(0,1,2,3), 4)
#yshift<- rep( c(0,1,2,3), each=4 )
theShift<- (0:(2*np-1)) - (np-1)
xshift<- rep( theShift, 2*np)
yshift<- rep( theShift, each=2*np )
nnXY<- cbind( xshift, yshift)
nnXYCoords<- cbind( xshift*dx, yshift*dy)
#
# sX and sY are M by (2*np)^2 matrices where each row is
# the unrolled row and column indices for np=2
# yield 16 nearest neighbors
sX<- s0[,1] + matrix( rep( xshift,M),
nrow=M, ncol=(2*np)^2, byrow=TRUE)
sY<- s0[,2] + matrix( rep( yshift,M),
nrow=M, ncol=(2*np)^2, byrow=TRUE)
if( any( (sX < 1)| (sX>m)) ) {
stop( "sX outside range for grid")
}
if( any( (sY < 1)| (sY>n)) ) {
stop( "sY outside range for grid")
}
# indices of all nearest neighbors for unrolled vector.
# this is an M by (2*np)^2 matrix where indices go from 1 to m*n
# these work for the unrolled 2D array
#
sIndex<- sX + (sY-1)*m
# differences between nn and the off grid locations
# for both coordinates
# convert from integer grid to actual units.
differenceX<- (sX-1)*dx + gridList$x[1] - s[,1]
differenceY<- (sY-1)*dy + gridList$y[1] - s[,2]
# all pairwise distances between each off grid and
# (2*np)^2 ( np=2 has 16) nearest neighbors
dAll<- sqrt(differenceX^2 + differenceY^2)
# pairwise distance among nearest neighbors.
dNN<- rdist(nnXYCoords, nnXYCoords )
# cross covariances
Sigma21Star<- sigma2* do.call(Covariance,
c(list(d = dAll/aRange),
covArgs))
# covariance among nearest neighbors
Sigma11 <- sigma2* do.call(Covariance,
c(list(d = dNN/aRange),
covArgs))
Sigma11Inv <- solve( Sigma11)
# each row of B are the weights used to predict off grid point
B <- Sigma21Star%*%Sigma11Inv
# prediction variances
# use cholesky for more stable numerics
cholSigma11Inv<- chol(Sigma11Inv)
# sigma2 - diag(Sigma21Star%*%Sigma11Inv%*%t(Sigma21Star) )
w <- Sigma21Star%*%t(cholSigma11Inv)
predictionVariance <- sigma2 - rowSums(w^2)
# create spind sparse matrix
# note need to use unrolled indices to refer to grid points
ind<- cbind( rep(1:M, each= (2*np)^2 ), c( t( sIndex)))
ra<- c( t( B))
da<- c( M, m*n )
spindBigB<- list(ind=ind, ra=ra, da=da )
# now convert to the more efficient spam format
BigB<- spind2spam( spindBigB)
return(
list( B= BigB, predictionVariance = predictionVariance)
)
}