Fits a hydromad model using R's optim or nlminb functions. Has
multi-start and pre-sampling options.
fitByOptim(
MODEL,
objective = hydromad.getOption("objective"),
method = hydromad.getOption("optim.method"),
control = list(),
samples = hydromad.getOption("fit.samples"),
sampletype = c("latin.hypercube", "random", "all.combinations"),
initpars = NULL,
multistart = FALSE,
vcov = FALSE,
hessian = vcov
)a model specification created by hydromad. It
should not be fully specified, i.e one or more parameters should be defined
by ranges of values rather than exact values.
objective function to maximise, given as a
function(Q, X, ...). See objFunVal.
optimisation algorithm and settings. See
optim. The default is "Nelder-Mead" (a simplex
algorithm). An additional method "PORT" can be given, which calls
nlminb.
number of parameter sets to test.
sampling scheme -- see parameterSets.
initial parameter set.
if this is TRUE, then each of the initial parameter
samples (based on samples and sampletype) are used as a
starting value for a separate optimisation run, and the best result is kept.
if vcov = TRUE, the parameter variance-covariance
matrix will be estimated as the inverse of the hessian matrix returned by
optim(). This may be a very poor estimate! It can be extract using
vcov. Does not work with method = "PORT".
the best model from those sampled, according to the given
objective function. Also, these extra elements are inserted:
the result from optim.
the objective function used.
total number of evaluations of the model simulation function.
timing
vector as returned by system.time.
See optim for a brief description of the available algorithms,
including references to literature.
fitByOptim1 handles a single free parameter using
optimize; it is called by fitByOptim, with a warning,
in that case.
data(Cotter)
x <- Cotter[1:1000]
## IHACRES CWI model with power law unit hydrograph
modx <- hydromad(x, sma = "cwi", routing = "powuh")
modx
#>
#> Hydromad model with "cwi" SMA and "powuh" routing:
#> Start = 1966-05-01, End = 1969-01-24
#>
#> SMA Parameters:
#> lower upper
#> tw 0 100
#> f 0 8
#> scale NA NA
#> l 0 0 (==)
#> p 1 1 (==)
#> t_ref 20 20 (==)
#> Routing Parameters:
#> lower upper
#> a 0.01 60
#> b 0.50 3
#> c 0.50 2
set.seed(0)
foo <- fitByOptim(modx, samples = 100)
summary(foo)
#>
#> Call:
#> hydromad(DATA = x, sma = "cwi", routing = "powuh", a = 7.87367,
#> b = 1.41609, c = 2, tw = 100, f = 4.77557, scale = 0.00128754)
#>
#> Time steps: 900 (0 missing).
#> Runoff ratio (Q/P): (0.7028 / 2.285) = 0.3075
#> rel bias: -2.036e-16
#> r squared: 0.7508
#> r sq sqrt: 0.8364
#> r sq log: 0.8341
#>
#> For definitions see ?hydromad.stats
#>
## return value from optim (with 'objseq' added):
str(foo$fit.result)
#> List of 7
#> $ par : Named num [1:5] 7.87 1.42 2 100 4.78
#> ..- attr(*, "names")= chr [1:5] "a" "b" "c" "tw" ...
#> $ objective : num -0.855
#> $ convergence: int 0
#> $ iterations : int 25
#> $ evaluations: Named int [1:2] 26 149
#> ..- attr(*, "names")= chr [1:2] "function" "gradient"
#> $ message : chr "relative convergence (4)"
#> $ objseq : num [1:276] 0.705 0.773 0.782 -1.302 0.706 ...
## plot objective function value convergence over time
xyplot(optimtrace(foo),
type = "b",
xlab = "function evaluations", ylab = "objective fn. value"
)
## repeat optimisation with single random starting points
fooreps <-
replicate(4,
fitByOptim(modx,
samples = 1, sampletype = "random",
objective = hmadstat("r.squared"),
method = "Nelder-Mead"
),
simplify = FALSE
)
#> Warning: optim() reached maximum iterations
#> Warning: optim() reached maximum iterations
#> Warning: optim() reached maximum iterations
#> Warning: optim() reached maximum iterations
names(fooreps) <- paste("rep.", seq_along(fooreps))
## extract and plot the optimisation traces
traces <- lapply(fooreps, optimtrace)
tracesraw <- lapply(fooreps, optimtrace, raw = TRUE)
xyplot(do.call("merge", traces),
superpose = TRUE,
sub = 'method = "Nelder-Mead"',
xlab = "Fn. evaluations", ylab = "Objective value",
auto.key = list(corner = c(1, 0))
) +
xyplot(do.call("merge", tracesraw),
superpose = TRUE,
type = "p", cex = 0.5
)
## if you try it again with method = "PORT" you will find that all
## replicates converge to the optimum regardless of starting point.