A corrections release. Twelve cost functions are brought into line with their
published equations; no feature is added or removed, and the interface is
unchanged. Results change for the functions listed below (correctly), so
analyses run with these functions in earlier versions should be re-run. Each
point is documented, with its source, in the help page of
mc_cost_functions(), which also states and justifies the few places where
movecost deliberately departs from a source.
The 3.0.0 review had checked the branch tests and coefficients of each cost function against its source, but not the sign of the slope inside each formula. Several functions applied the absolute value to a slope that the source defines as signed (negative downhill), which made descents as costly as ascents of the same gradient. Every function below has now been checked against its primary source.
icmonp, icfonp, icmoffp, icfoffp): the
percent slope is signed, as in equations 2-5 of Irmischer and Clarke (2018),
so that speed peaks on a -5% (on-path) or -2% (off-path) descent.r): signed slope (Rees 2004, eq. 1). Small effect.trp): signed slope in degrees, so that speed peaks on a
-4.1 degree descent, as in the asymmetrical Cauchy function fitted by
Tripcevich (2008); the reference is completed with the poster's details and
URL.m): signed gradient (Minetti et al. 2002); at -10% the
cost is now 1.13 instead of 4.90 J/(kg*m). Below -0.45, the lower end of the
measured range, where the polynomial decreases and then turns negative, the
gradient is held at -0.45, and mc_surface() reports how many edges are
affected (documented departure from the source).hrz): signed slope (Herzog 2016, 2020).ls): signed slope (Llobera and Sluckin 2007, eq. 16).a): signed gradient, and coefficient 45.72 instead of 45.71
(Ardigo et al. 2003, eq. 1).pcf): the grade is signed in both
the Pandolf rate and the Yokota et al. correction, and the terrain factor
multiplies the whole correction (Yokota et al. 2004, p. 4). Versions 3.0.0-3.1.0 used the absolute grade, so that a
descent cost more than an ascent of the same gradient (e.g., 543 W instead
of 195 W at -10%, with W = 70, L = 0, V = 1.2).vl): the grade term is abs(G + 10), with G signed, placing the
axis of cost symmetry at -10% as stated by Van Leusen (2002); 3.1.0 used
abs(G) + 10, which equals it uphill but not downhill. The printed formula of
the source reads abs(G + 6); the reasons for following the stated axis are
given in the help page (documented departure from the source).p), Pandolf with correction (pcf), Van Leusen (vl): these
equations give a metabolic rate (W). Earlier versions accumulated
rate x distance (W*m, labelled "Megawatts"); the cost per metre is now
rate / speed (J/m), so that the accumulated value is energy, reported in kJ.
With V = 0 (speed derived from Tobler's function cell by cell) the
least-cost paths of earlier versions did not minimise energy; they now do.h): the function gives kcal per km; the accumulated value is now
divided by 1000 and reported in kcal (earlier versions reported the raw sum
under the label "cal/km").cost_unit column of mc_cost_functions(), the printed surfaces, and
the plot legends now give the unit of the accumulated value (kJ, J/kg, kcal)
rather than the per-metre unit (J/(kg*m), kJ/m).p) keeps the absolute grade, the symmetric form reported by
Herzog (2020, Table 18.2): the original equation covers level and uphill
walking only (Yokota et al. 2004) and, with a negative grade, turns negative
on steep descents. The help page says so and points to pcf for descents.ug), Garmy et al. (gkrs), Bellavia (b), Eastman
(e), the wheeled-vehicle function (wcs), and the relative energetic
expenditure (ree) are symmetric in their sources; the help page now states
this where it was not stated, and that ree costs nothing on level ground.pcf: the help page notes the small step in cost between level and slightly
downhill movement that comes from the source equation, and that Looney et al.
(2019) print the last term of the correction differently from Yokota et al.
(2004), whom movecost follows.tests/testthat/test-sources.R: each corrected function is checked
against its published equation, written out independently of the package
code; anisotropic functions must distinguish ascent from descent and
symmetric ones must not; energy functions must accumulate in the declared
unit; every function must stay positive over slopes from -1 to 1.inst/validation/ notes and the Python core replica updated accordingly.mc_surface() gains two arguments, terrain and terrain.table, so that
the terrain factor N no longer has to be a single value for the whole study
area. terrain takes a raster (SpatRaster, RasterLayer, or file path) in
either of two forms: a numeric raster whose cells hold terrain factors
directly, or a categorical raster of terrain classes (integer codes, or a
terra factor raster with category labels) translated into terrain factors
by the lookup table terrain.table (columns class and N).N keeps its meaning and default, and now acts as the fallback
value: cells with no terrain value (NA cells, cells outside the raster's
extent, classes missing from the table) take N. A raster can therefore map
only the terrain types of interest and leave the rest to a single general
value. A message reports how many cells were filled; a warning lists any
class missing from the table. Inf makes a cell impassable.p), Pandolf with correction (pcf), and
Van Leusen (vl) functions, where N multiplies only the terrain-dependent
term of the metabolic equation, the two would differ.terrain); print() reports their range, the cost-function label
carried by every downstream result reads e.g. "terrain factor
N=raster (1.03 to 2.5)", plot(surface, type = "terrain") maps them, and
mc_export() writes them to terrain_N_<funct>.tif. mc_save() /
mc_load() preserve them.mc_terrain_factors() returns, as a data frame, the reference list of
terrain factors already documented in mc_cost_functions() (from Herzog
2020, for time-based functions and for functions measuring other costs),
as a starting point for building terrain.table.mc_comp() accepts terrain and terrain.table through ...; the raster
is aligned to the DTM once and shared by all the compared functions.mc_accum(), mc_paths(), mc_corridor(),
mc_boundary(), mc_alloc(), mc_network(), mc_rank()) work unchanged on
surfaces built with a terrain raster.mc_surface() now validates N, which must be a single positive number
(previously any value was accepted silently).N other than 1, or terrain), which they ignore; previously N
was ignored silently. The warning gives the reason: the off-path functions
(tofp, icmoffp, icfoffp) already embed off-path walking, and the
warning points to their on-path versions (t, icmonp, icfonp), which do
take N; Alberti's function (alb) models the walking pace of a flock, to
which a terrain factor does not apply.print() of a cost surface reports the terrain factor in use.mc_surface() help: new Details section on the terrain raster, and a worked
example. mc_cost_functions(), mc_comp(), mc_export(),
plot.movecost_surface() and the package help page updated accordingly.mc_comp() with
a terrain raster, the export section mentions the terrain raster written
by mc_export(), and Task 2 explains what happens when a terrain factor is
passed to a function that does not take one. The vignette title now reads
"movecost 3.x: a task-based guide".mc_cost_functions() help: the exceptions to the terrain factor are now
described accurately. Alberti's function (alb) was said to "natively
embed" a terrain factor; its 0.25 coefficient is in fact the ratio between
flock and human walking speed, and the function does not take N because it
models a flock's pace. Each of the four functions concerned now states that
it does not take N, and the off-path ones name their on-path version.inst/CITATION: the package version in the citation is now read from
DESCRIPTION, so it can no longer fall out of date.inst/CITATION) and in the vignette reference: the title of the 2019
SoftwareX paper is "movecost" (the name carries no capital letters), not
"MovEcost" or "Movecost".mc_cost_functions() help: completed and corrected the literature references
for several cost functions. The Eastman function ("e") now cites the
original source, Eastman (1999: 61, the IDRISI32 guide), with Barge and
Chataigner (2004) and Vaissie (2021) added as the secondary sources from
which the equation was drawn; previously only Vaissie (2021) was given. The
Bellavia function ("b") now cites the primary Bellavia (2002) reference
alongside Herzog (2020). The gkrs function now cites the primary Garmy,
Kaddouri, Rozenblat and Schneider (2005) reference alongside Herzog (2020).
The Tripcevich ("trp") and Van Leusen ("vl") references were completed
with their previously missing publication venues. The Alberti function
("alb") reference was corrected and completed to the full Alberti, Grima
and Vella (2020) book-chapter citation (Temple Landscapes volume), replacing
the incomplete and mis-dated "Alberti (2019)". No cost-function formula,
result, or argument is affected.A ground-up redesign of the package's architecture, while retaining all the analytical capabilities (and the 26 cost functions) of the previous releases. The baseline for the comparisons below is the last version published on CRAN, movecost 2.2.
mc_surface() builds the cost graph once; every analysis function
(mc_accum(), mc_paths(), mc_corridor(), mc_boundary(), mc_alloc(),
mc_network(), mc_rank()) reuses it. In the 2.x series each call to
movecost(), movecorr(), movealloc(), movebound(), movenetw(),
moverank() rebuilt the conductance matrix from scratch (an n-location
network implied O(n) redundant constructions); that redundancy is gone.mc_dtm().mc_volc(), mc_malta_dtm(), mc_volc_loc(), mc_destin_loc(),
mc_springs(), mc_etna_start(), mc_etna_end(), mc_etna_boundary()),
removing the last data-level dependency on raster/sp.plot() / autoplot() methods returning ggplot
objects, which can be stored, customised with standard ggplot2 syntax, and
re-drawn at will - without re-running any analysis (in 2.x, obtaining a new
visualisation required re-running the computation).iso.col, default white, iso.lwd), least-cost-path width (lcp.lwd),
and label sizes (cex.breaks for isoline labels, cex.lcp.lab for
destination labels, cex.node.lab / cex.origin.lab for network and
allocation labels).node.lab, origin.lab), matching cost.matrix and the
allocation zones respectively, reproducing the 2.x numbering.These are fixes to mistakes present in the last CRAN release (movecost 2.2), verified against the source publications. Analyses using the affected functions will give different (correct) results.
ks), Marin Arroyo (ma), and Pandolf-with-correction
(pcf): the slope-sign tests are now applied to the signed slope, as the
original publications intend. In 2.2 those tests were applied to the
absolute slope, so the downhill branches (the gentler ks decay, the
gentler ma divisor, the Yokota et al. downhill correction in pcf)
could never be selected. Results on downhill gradients therefore differ -
correctly - from 2.2.p, vl): the terrain factor N is now applied
once, as the coefficient eta of Pandolf et al. (1977), multiplying the
velocity-dependent term; 2.2 additionally multiplied the whole expression
by N, counting terrain twice and inflating the basal-metabolism terms.
With the default N = 1 results are unchanged; for N != 1 they differ
(correctly) from 2.2.funct = "h"): the 2.2 code contained a
double-reciprocal that reduced algebraically to 1 / ((48 + 30 * v) * N)
rather than the intended 1 / ((48 + 30 / v) * N), where v is the
cell-by-cell on-path Tobler walking speed. The corrected formula reproduces
the body-mass-anchored approximation of Ralston (1958) cited by Hare (2004),
agreeing with it to within ~5% across 2-6 km/h (the 2.2 code diverged by a
factor of three or more). The plotted cost-unit label is corrected from
"cal/km" to "kcal/km" to match.funct = "vl", "p", "pcf",
"a" with V = 0): in 2.2 the value substituted for the velocity was the
reciprocal of Tobler's on-path speed rather than the speed itself,
mis-stating the metabolic rate (about half the canonical value on flat
ground, a multiple on steep terrain). Version 3.0 substitutes Tobler's speed
in m/s directly. Results obtained with V = 0 therefore differ from 2.2;
analyses using a non-zero V (including the default 1.2) are unaffected.These are deliberate refinements of how a result is produced. Where 2.x followed a specific published method, the 2.x behaviour is preserved as the default and the refinement is offered as an option.
mc_corridor()): the classic definition of the 2.x
series, the sum of two accumulated cost surfaces spread outward from the two
locations after Mitchell (2012), is kept as the default
(method = "reach"), is symmetric, and reproduces 2.x. A new
method = "through" option adds a directional alternative,
cost(A->x) + cost(x->B) (the second term on the reversed graph), whose
minimum equals the A-to-B least-cost-path cost; it is intended for one-way
journey analysis under anisotropic cost functions. The two coincide for
isotropic functions. For the two-location case the least-cost paths A-to-B
and B-to-A are computed, returned, and overlaid on the plot, as in 2.x.mc_boundary()): the boundary is now obtained by
polygonising the reachable area directly (cells at or below the limit),
yielding closed polygons with exact area and perimeter; 2.x derived it from
contour lines of the accumulated surface. The result is a more rigorous,
measurable catchment polygon.mc_rank()): same iterative-penalisation idea as
2.x's moverank(), but operating directly on the graph edge weights, so any
number of ranks can be requested (2.x was capped at 6) and the avoidance
strength is exposed through a tunable penalty parameter.irregular.dtm workaround (and parameter) of 2.x is no longer needed.mc_network()): the path-density rasters are computed
exactly from the graph vertices of each path (no rasterisation
approximation), and the network nodes are numbered on the plot and in the
returned nodes object, matching the row/column indices of cost.matrix,
as in 2.x.mc_export() handles every result class.mc_save()/mc_load() provide reliable on-disk persistence of result
objects (SpatRaster components cannot survive a bare saveRDS()).mc_cost_functions() returns the full annotated registry of the 26 cost
functions (codes, families, units, parameter usage), which is also the
single internal source of cost-function definitions (in 2.x the
definitions were duplicated across functions).inst/validation/.| movecost 2.x | movecost 3.0 |
|-------------------------------|---------------------------------------------|
| movecost() (accumulated) | mc_surface() + mc_accum() |
| movecost() (LCPs) | mc_surface() + mc_paths() |
| movecorr() | mc_corridor() |
| movebound() | mc_boundary() |
| movealloc() | mc_alloc() |
| movenetw() | mc_network() |
| moverank() | mc_rank() |
| movecomp() | mc_comp() |
| studyplot= (download DTM) | mc_dtm() (or studyplot= in mc_surface()) |
| export=TRUE | mc_export() |
topo.dist parameter to movecost(): when TRUE, accumulated cost
uses topographic (surface) distance rather than planar distance, accounting
for the extra distance over sloped terrain (surface = planar * sqrt(1 +
slope^2); about +4.4% on a 30% slope, +11.8% on a 50% slope). Particularly
recommended for time-based hiking functions; to be used with caution for
metabolic functions, which were derived against planar distance.topo.dist to all wrapper functions (movealloc(),
movebound(), movecomp(), movecorr(), movenetw(), moverank()); the
default FALSE preserves backward compatibility.\itemize sections across several Rd files.create_barrier_cs documentation (missing fields argument
in \usage).create_barrier_cs (from an earlier version of the
'leastcostpath' package) as an internal function; dependency on
'leastcostpath' dropped; dependency on 'Matrix' added.netw.type parameter to movenetw().origin/destination parameters.moverank() function.irregular.dtm) to prevent LCPs crossing NoData
(sea) areas.movecomp() (via add.chart); the
returned LCPs now store the cost.movenetw().malta_dtm_40 and springs
datasets.movealloc().movecost() returns the conductance transitional layer (used to optimise
movenetw()).movenetw() also computes LCP networks between neighbouring locations and
returns a pairwise cost matrix; internal optimisation (~3x faster than 1.6);
oneplot dropped; export fix.volc dataset.movenetw().movenetw(): fixed exported-GeoTiff naming; documentation tweaks.volc RasterLayer to the sample datasets.movecomp() and movenetw().movebound().movealloc().V = 0.movecorr() plots point locations on top of the multi-origin corridor.movebound().transp).cost_hms
variable to the returned destination layer; that layer is now exportable.movecorr() can produce a corridor between two locations or among multiple
locations; added the 0-1 rescaling option.movecost() and movecorr().movecorr().movecorr(); the accumulated rasters are now
returned.movecost() now returns (without plotting) the cost surface.movecorr(); added the graph.out option to movecost(); renamed the
Marquez-Perez function code from mt to mp.icmonp, icmoffp, icfonp, icfoffp; documentation layout improvements.move parameter (number of directions in which cells connect).