37 lines
2.4 KiB
JavaScript
37 lines
2.4 KiB
JavaScript
|
|
const MODE = Object.freeze({
|
||
|
|
// Hirt et al. time-dependent maximum-speed form:
|
||
|
|
// v = a * M^b * (1 - exp(-h * M^i)), v in km/h, M in kg.
|
||
|
|
// Flying, running and swimming coefficients are the published Supplementary
|
||
|
|
// Table 4 fits for the time-dependent maximum-speed model.
|
||
|
|
running:{a:25.5,b:.26,h:22,i:-.60,routineFraction:.34,homeRangeFactor:1,calibration:'Hirt-2017'},
|
||
|
|
swimming:{a:11.2,b:.36,h:19.5,i:-.56,routineFraction:.30,homeRangeFactor:1.25,calibration:'Hirt-2017'},
|
||
|
|
flying:{a:142.8,b:.24,h:2.4,i:-.72,routineFraction:.42,homeRangeFactor:1.8,calibration:'Hirt-2017'},
|
||
|
|
});
|
||
|
|
export const locomotionModes=Object.freeze(Object.keys(MODE));
|
||
|
|
export const normalizeLocomotionMode=mode=>MODE[mode]?mode:'running';
|
||
|
|
export const locomotionCalibration=mode=>({...MODE[normalizeLocomotionMode(mode)]});
|
||
|
|
export function maximumSpeedMPerDay(massKg,mode='running'){
|
||
|
|
const c=MODE[normalizeLocomotionMode(mode)],m=Math.max(massKg,1e-6),kmh=c.a*Math.pow(m,c.b)*(1-Math.exp(-c.h*Math.pow(m,c.i)));
|
||
|
|
return Math.max(1,kmh*24000); // km/h -> m/day
|
||
|
|
}
|
||
|
|
export const maximumSpeedMultiplier=massKg=>maximumSpeedMPerDay(massKg,'running')/maximumSpeedMPerDay(3,'running');
|
||
|
|
export function routineTravelSpeedMPerDay(massKg,dailyMovementBudgetM,mode='running'){
|
||
|
|
const c=MODE[normalizeLocomotionMode(mode)],budgetSpeed=Math.max(0,dailyMovementBudgetM)*c.routineFraction;
|
||
|
|
return Math.min(maximumSpeedMPerDay(massKg,mode)*.22,Math.max(1,budgetSpeed));
|
||
|
|
}
|
||
|
|
export function foragingSpeedMPerDay(massKg,dailyMovementBudgetM,mode='running'){
|
||
|
|
return Math.min(maximumSpeedMPerDay(massKg,mode)*.42,routineTravelSpeedMPerDay(massKg,dailyMovementBudgetM,mode)*1.35);
|
||
|
|
}
|
||
|
|
export function escapeSpeedMPerDay(massKg,dailyMovementBudgetM,mode='running'){
|
||
|
|
return Math.min(maximumSpeedMPerDay(massKg,mode),routineTravelSpeedMPerDay(massKg,dailyMovementBudgetM,mode)*2.4);
|
||
|
|
}
|
||
|
|
export function dailyMovementBudgetM(massKg,geneBudgetM,mode='running'){
|
||
|
|
const c=MODE[normalizeLocomotionMode(mode)];
|
||
|
|
return Math.max(25,geneBudgetM)*(0.75+0.25*Math.pow(Math.max(massKg,.01)/3,.08))*(.9+.1*c.homeRangeFactor);
|
||
|
|
}
|
||
|
|
export function homeRangeRadiusM(massKg,mode='running'){
|
||
|
|
const c=MODE[normalizeLocomotionMode(mode)];return Math.min(1500,Math.max(90,170*Math.pow(Math.max(massKg,.01),.22)*c.homeRangeFactor));
|
||
|
|
}
|
||
|
|
export function sampleDispersalDistanceM(random,massKg,mode='running'){
|
||
|
|
const scale=homeRangeRadiusM(massKg,mode)*.55;return Math.min(scale*3,-Math.log(Math.max(1e-9,1-random()))*scale);
|
||
|
|
}
|