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.