This document shows how to use the endoR.R
function of
NicheMapR to compute endotherm heat and mass balances. This function
collates all the different steps in Endotherm Components
Tutorial into a single function, ‘endoR’, that can be applied to
vectors of data. The latter calls a FORTRAN routine call ‘SOLVENDO’
(high speed calculation). An R equivalent of this, ‘endoR_devel’ (~ 9x
slower), can be used for the development of algorithms for
organism-specific sequences of thermoregulatory responses and then, if
faster processing is required, a version of SOLVENDO can be modified
accordingly. All the underlying theory, equations and subroutines are
described in Endotherm Theory
Tutorial.
Here is how you run the calculation with all default values, specifying a local air temperature of 0 \(^{\circ}\text{C}\).
library(NicheMapR)
library(knitr)
<- endoR(TA = 0)
endo.out
<- as.data.frame(endo.out$treg)
treg <- as.data.frame(endo.out$morph)
morph <- as.data.frame(endo.out$enbal)
enbal <- as.data.frame(endo.out$masbal) masbal
value | description and units | |
---|---|---|
TC | 37 | core temperature (°C) |
TLUNG | 28.5658 | lung temperature (°C) |
TSKIN_D | 20.1168 | dorsal skin temperature (°C) |
TSKIN_V | 20.1466 | ventral skin temperature (°C) |
TFA_D | 13.3719 | dorsal fur/feather-air interface temperature (°C) |
TFA_V | 13.3515 | ventral fur-air interface temperature (°C) |
SHAPE_B | 1.1 | current ratio between long and short axis due to postural change (-) |
PANT | 1 | breathing rate multiplier (-) |
PCTWET | 0.5 | part of the skin surface that is wet (%) |
K_FLESH | 0.9 | thermal conductivity of flesh (W/mC) |
K_FUR_EFF | 0.034 | effective thermal conductivity of fur/feathers (W/mC) |
K_FUR_D | 0.0379 | thermal conductivity of dorsal fur/feathers (W/mC) |
K_FUR_V | 0.0379 | thermal conductivity of ventral fur/feathers (W/mC) |
K_COMPFUR | 0.034 | thermal conductivity of compressed fur/feathers (W/mC) |
Q10 | 1 | Q10 multiplier on metabolic rate (-) |
value | description and units | |
---|---|---|
AREA | 0.7956 | total outer surface area (m2) |
VOLUME | 0.065 | total volume (m3) |
CHAR_DIM | 0.4873 | characteristic dimension for convection (m) |
MASS_FAT | 13 | fat mass (kg) |
FAT_THICK | 0 | thickness of fat layer (m) |
FLESH_VOL | 0.065 | flesh volume (m3) |
LENGTH | 0.5316 | length (m) |
WIDTH | 0.4833 | width (m) |
HEIGHT | 0.4833 | height (m) |
DIAM_FLESH | 0.2416 | diameter, core to skin (m) |
DIAM_FUR | 0.2436 | diameter, core to fur/feathers (m) |
AREA_SIL | 0.1957 | silhouette area (m2) |
AREA_SILN | 0.205 | silhouette area normal to sun’s rays (m2) |
AREA_ASILP | 0.1865 | silhouette area parallel to sun’s rays (m2) |
AREA_SKIN | 0.783 | total skin area (m2) |
AREA_SKIN_EVAP | 0.7664 | skin area available for evaporation (m2) |
AREA_CONV | 0.7956 | area for convection (m2) |
AREA_COND | 0 | area for conduction (m2) |
F_SKY | 0.5 | configuration factor to sky (-) |
F_GROUND | 0.5 | configuration factor to ground (-) |
value | description and units | |
---|---|---|
QSOL | 0 | solar radiation absorbed (W) |
QIRIN | 272.8724 | longwave (infra-red) radiation absorbed (W) |
QGEN | 101.95 | metabolic heat generation (W) |
QEVAP | 6.7581 | evaporation (W) |
QIROUT | 325.1759 | longwave (infra-red) radiation lost (W) |
QCONV | 42.7205 | convection (W) |
QCOND | 0 | conduction (W) |
ENB | 0.168 | energy balance (W) |
NTRY | 1 | iterations required for a solution (-) |
SUCCESS | 1 | was a solution found (0=no, 1=yes) |
value | description and units | |
---|---|---|
AIR_L | 465.2182 | breating rate (L/h) |
O2_L | 19.4886 | oxgyen consumption rate (L/h) |
H2OResp_g | 2.1338 | respiratory water loss (g/h) |
H2OCut_g | 0.7508 | cutaneous water loss (g/h) |
O2_mol_in | 4.3474 | oxygen inhaled (mol/h) |
O2_mol_out | 3.4779 | oxygen expelled (mol/h) |
N2_mol_in | 16.4066 | nitrogen inhaled (mol/h) |
N2_mol_out | 16.4066 | nitrogen expelled (mol/h) |
AIR_mol_in | 20.7557 | air inhaled (mol/h) |
AIR_mol_out | 20.5818 | air expelled (mol/h) |
Now try a sequence of air temperatures for a specified core temperature, mass, fur/feather depth and base skin wetness, with the option to sweat at 0.25 % increments to cool down if needed. Note that the default settings make the environment a black-body one (all surface and air temperatures the same) with low (5%) relative humidity and low wind speed (0.1 m/s), as is often the case in metabolic chamber experiments. This example uses parameters for the Australian budgerigar Melopsittacus undulatus and compares it against data from Weathers & Schoenbaechler (1976).
Weathers, W.W. & Schoenbaechler, D.C. (1976) Regulation of body temperature in the Budgerygah, Melopsittacus undulatus. Australian Journal of Zoology, 24, 39–47.
library(NicheMapR)
# environment
<- seq(0, 50, 1) # air temperature (°C)
TAs <- 0.1 # wind speed (m/s)
VEL <- WETAIR(rh = 30, db = 40)$vd # Weathers and Schoenbaechler had 16.7 mm Hg
vd # above 40 °C = 30% RH at 40 °C
<- WETAIR(rh = 100, db = TAs)$vd # Weathers and Schoenbaechler had 16.7 mm Hg
vd_sat # above 40 °C = 30% RH at 40 °C
<- vd/vd_sat * 100
exp_rh > 100] <- 100
exp_rh[exp_rh < 30] <- 15
exp_rh[TAs <- exp_rh
hum
# core temperature
<- 38 # core temperature (°C)
TC <- 43 # maximum core temperature (°C)
TC_MAX <- 0.25 # increment by which TC is elevated (°C)
TC_INC
# size and shape
<- 0.0337 # mass (kg)
AMASS <- 1.1 # start off near to a sphere (-)
SHAPE_B <- 5 # maximum ratio of length to width/depth
SHAPE_B_MAX <- 0.1 # allows the animal to uncurl to SHAPE_B_MAX, the value being the increment
UNCURL # SHAPE_B is increased per iteration
<- 4 # use ellipsoid geometry
SHAPE <- 1 # use bird surface area relations (2 is mammal, 0 is based on shape specified
SAMODE # in GEOM)
# feather properties
<- 3e-05 # hair diameter, dorsal (m)
DHAIRD <- 3e-05 # hair diameter, ventral (m)
DHAIRV <- 0.0231 # hair length, dorsal (m)
LHAIRD <- 0.0227 # hair length, ventral (m)
LHAIRV <- 0.0059 # fur depth, dorsal (m)
ZFURD <- 0.0057 # fur depth, ventral (m)
ZFURV <- 5e+07 # hair density, dorsal (1/m2)
RHOD <- 5e+07 # hair density, ventral (1/m2)
RHOV <- 0.248 # fur reflectivity dorsal (fractional, 0-1)
REFLD <- 0.351 # fur reflectivity ventral (fractional, 0-1)
REFLV
# physiological responses
<- 0.5 # base skin wetness (%)
PCTWET <- 5 # maximum skin wetness (%)
PCTWET_MAX <- 0.25 # intervals by which skin wetness is increased (%)
PCTWET_INC <- rep(1, length(TAs))
Q10s >= TC_MAX] <- 2 # assuming Q10 effect kicks in only after air temp rises above TC_MAX
Q10s[TAs <- 10^(-1.461 + 0.669 * log10(AMASS * 1000)) # basal heat generation (W)
QBASAL <- 5 # offset between air temperature and breath (°C)
DELTAR <- 25 # O2 extraction efficiency (%)
EXTREF <- 0.1 # turns on panting, the value being the increment by which the panting multiplier
PANT_INC # is increased up to the maximum value, PANT_MAX
<- 15 # maximum panting rate - multiplier on air flow through the lungs above
PANT_MAX # that determined by metabolic rate
<- 1 # multiplier on basal metabolic rate at maximum panting level
PANT_MULT
<- proc.time() # start timing
ptm <- lapply(1:length(TAs), function(x) {
endo.out endoR(TA = TAs[x], VEL = VEL, TC = TC, TC_MAX = TC_MAX, RH = hum[x],
AMASS = AMASS, SHAPE = SHAPE, SHAPE_B = SHAPE_B, SHAPE_B_MAX = SHAPE_B_MAX,
PCTWET = PCTWET, PCTWET_INC = PCTWET_INC, PCTWET_MAX = PCTWET_MAX,
Q10 = Q10s[x], QBASAL = QBASAL, DELTAR = DELTAR, DHAIRD = DHAIRD,
DHAIRV = DHAIRV, LHAIRD = LHAIRD, LHAIRV = LHAIRV, ZFURD = ZFURD,
ZFURV = ZFURV, RHOD = RHOD, RHOV = RHOV, REFLD = REFLD,
TC_INC = TC_INC, PANT_INC = PANT_INC, PANT_MAX = PANT_MAX,
EXTREF = EXTREF, UNCURL = UNCURL, SAMODE = SAMODE, PANT_MULT = PANT_MULT)
# run endoR across environments
}) proc.time() - ptm # stop timing
## user system elapsed
## 0.18 0.00 0.20
# extract the output
<- do.call("rbind", lapply(endo.out, data.frame))
endo.out1
# thermoregulation output
<- endo.out1[, grep(pattern = "treg", colnames(endo.out1))]
treg colnames(treg) <- gsub(colnames(treg), pattern = "treg.", replacement = "")
# morphometric output
<- endo.out1[, grep(pattern = "morph", colnames(endo.out1))]
morph colnames(morph) <- gsub(colnames(morph), pattern = "morph.",
replacement = "")
# heat balance
<- endo.out1[, grep(pattern = "enbal", colnames(endo.out1))]
enbal colnames(enbal) <- gsub(colnames(enbal), pattern = "enbal.",
replacement = "")
# mass aspects
<- endo.out1[, grep(pattern = "masbal", colnames(endo.out1))]
masbal colnames(masbal) <- gsub(colnames(masbal), pattern = "masbal.",
replacement = "")
<- enbal$QGEN # metabolic rate (W)
QGEN <- masbal$H2OResp_g + masbal$H2OCut_g # g/h water evaporated
H2O <- treg$TFA_D # dorsal fur surface temperature
TFA_D <- treg$TFA_V # ventral fur surface temperature
TFA_V <- treg$TSKIN_D # dorsal skin temperature
TskinD <- treg$TSKIN_V # ventral skin temperature
TskinV <- treg$TC # core temperature
TCs
par(mfrow = c(2, 2))
par(oma = c(2, 1, 2, 2) + 0.1)
par(mar = c(3, 3, 1.5, 1) + 0.1)
par(mgp = c(2, 1, 0))
plot(QGEN ~ TAs, type = "l", ylab = "metabolic rate, W", xlab = expression("air temperature, " *
~degree * C * ""), ylim = c(0.2, 1.2))
points(Weathers1976Fig1$Tair, Weathers1976Fig1$mlO2gh * 20.1/3600 *
* 1000), pch = 16, col = 2)
(AMASS legend(x = 30, y = 1.2, legend = c("observed", "predicted"),
col = c("red", "black"), lty = c(NA, 1), bty = "n", pch = c(16,
NA))
plot(H2O ~ TAs, type = "l", ylab = "water loss, g/h", xlab = expression("air temperature, " *
~degree * C * ""), ylim = c(0, 1.5))
points(masbal$H2OResp_g ~ TAs, type = "l", lty = 2)
points(masbal$H2OCut_g ~ TAs, type = "l", lty = 2, col = "blue")
legend(x = 3, y = 1.5, legend = c("total (obs)", "total (pred)",
"respiratory", "cutaneous"), col = c("red", "black", "black",
"blue"), lty = c(NA, 1, 2, 2), bty = "n", pch = c(16, NA,
NA, NA))
points(Weathers1976Fig3$Tair, Weathers1976Fig3$mgH2Ogh * AMASS,
pch = 16, col = 2)
plot(TFA_D ~ TAs, type = "l", col = "grey", ylab = expression("feather, skin and core temperature, " *
~degree * C * ""), xlab = expression("air temperature, " *
~degree * C * ""), ylim = c(10, 50))
points(TFA_V ~ TAs, type = "l", col = "grey", lty = 2)
points(TskinD ~ TAs, type = "l", col = "orange")
points(TskinV ~ TAs, type = "l", col = "orange", lty = 2)
points(TCs ~ TAs, type = "l", col = "red")
legend(x = 30, y = 33, legend = c("core (obs)", "core (pred)",
"skin dorsal", "skin ventral", "feathers dorsal", "feathers ventral"),
col = c("red", "red", "orange", "orange", "grey", "grey"),
lty = c(NA, 1, 1, 2, 1, 2), bty = "n", pch = c(16, NA, NA,
NA, NA, NA))
points(Weathers1976Fig2$Tair, Weathers1976Fig2$Tb, pch = 16,
col = 2)
plot(masbal$AIR_L * 1000/60 ~ TAs, ylim = c(0, 250), lty = 1,
xlim = c(-5, 50), ylab = "ml air / min", xlab = expression("air temperature, " *
~degree * C * ""), type = "l")
legend(x = 0, y = 250, legend = c("observed", "predicted"), col = c("red",
"black"), lty = c(NA, 1), bty = "n", pch = c(16, NA))
points(Weathers1976Fig5$breaths_min * (13.2 * AMASS^1.08) * ((Weathers1976Fig5$Tair +
273.15)/273.15) ~ Weathers1976Fig5$Tair, col = 2, pch = 16) # tidal volume allometry from Lasiewski, R. C., and W. A. Calder. 1971, correcting volume according to PV = nRT equation, where V_2 = T_2 * V_1 / T_2, and T_1 is at STP, so 0 °C
In this final example, the microclimate model is run for a location in central Australia, under unshaded conditions, and the then the relevant outputs are sent into the endotherm model along with the same animal parameters as above.
library(NicheMapR)
<- c(131.05, -22.75)
loc <- 0.07
Usrhyt <- 100
maxshade <- micro_global(loc = loc, Usrhyt = Usrhyt, maxshade = maxshade)
micro
<- as.data.frame(micro$metout) # unshaded above-ground conditions
metout <- as.data.frame(micro$soil) # unshaded below-ground soil temperatures
soil <- as.data.frame(micro$shadmet) # shaded above-ground conditions
shadmet <- as.data.frame(micro$shadsoil) # shaded below-ground soil temperatures
shadsoil <- micro$dates
dates
<- metout$TALOC # air temperatures at height of animal (°C)
TAs <- metout$TAREF # air temperatures at reference height (°C)
TAREFs <- metout$TSKYC # sky temperatures (°C)
TSKYs <- soil$D0cm # surface temperatures (°C)
TGRDs <- metout$VLOC # wind speeds at animal height (m/s)
VELs <- metout$RHLOC # relative humidity at animal height (%)
RHs <- metout$SOLR # solar radiation (W/m2)
QSOLRs <- metout$ZEN # zenith angle of the sun (degrees)
Zs <- micro$elev # elevation (m)
ELEV <- 1 - micro$REFL # substrate solar absorptivity (%)
ABSSB
# core temperature
<- 38 # core temperature (°C)
TC <- 43 # maximum core temperature (°C)
TC_MAX <- 0.25 # increment by which TC is elevated (°C)
TC_INC
# size and shape
<- 0.0337 # mass (kg)
AMASS <- 4 # use ellipsoid geometry
SHAPE <- 1.1 # start off near to a sphere (-)
SHAPE_B <- 5 # maximum ratio of length to width/depth
SHAPE_B_MAX <- 0.1 # allows the animal to uncurl to SHAPE_B_MAX, the value being the increment
UNCURL # SHAPE_B is increased per iteration
# feather properties
<- 3e-05 # hair diameter, dorsal (m)
DHAIRD <- 3e-05 # hair diameter, ventral (m)
DHAIRV <- 0.0231 # hair length, dorsal (m)
LHAIRD <- 0.0227 # hair length, ventral (m)
LHAIRV <- 0.0059 # fur depth, dorsal (m)
ZFURD <- 0.0057 # fur depth, ventral (m)
ZFURV <- 5e+07 # hair density, dorsal (1/m2)
RHOD <- 5e+07 # hair density, ventral (1/m2)
RHOV <- 0.248 # fur reflectivity dorsal (fractional, 0-1)
REFLD <- 0.351 # fur reflectivity ventral (fractional, 0-1)
REFLV
# physiological responses
<- 0.1 # base skin wetness (%)
PCTWET <- 0.1 # maximum skin wetness (%)
PCTWET_MAX <- 0.25 # intervals by which skin wetness is increased (%)
PCTWET_INC <- 1 # Q10 effect of body temperature on metabolic rate (-)
Q10 <- 10^(-1.461 + 0.669 * log10(AMASS * 1000)) # basal heat generation (W)
QBASAL <- 5 # offset between air temperature and breath (°C)
DELTAR <- 25 # O2 extraction efficiency (%)
EXTREF <- 0.1 # turns on panting, the value being the increment by which the panting
PANT_INC # multiplier is increased up to the maximum value, PANT_MAX
<- 15 # maximum panting rate - multiplier on air flow through the lungs above
PANT_MAX # that determined by metabolic rate
<- 1 # multiplier on basal metabolic rate at maximum panting level
PANT_MULT
# run the model
<- proc.time() # start timing
ptm <- lapply(1:length(TAs), function(x) {
endo.out endoR(TA = TAs[x], TAREF = TAREFs[x], TSKY = TSKYs[x], TGRD = TGRDs[x],
VEL = VELs[x], RH = RHs[x], QSOLR = QSOLRs[x], Z = Zs[x],
ELEV = ELEV, ABSSB = ABSSB, TC = TC, TC_MAX = TC_MAX,
AMASS = AMASS, SHAPE = SHAPE, SHAPE_B = SHAPE_B, SHAPE_B_MAX = SHAPE_B_MAX,
PCTWET = PCTWET, PCTWET_INC = PCTWET_INC, Q10 = Q10,
QBASAL = QBASAL, DELTAR = DELTAR, DHAIRD = DHAIRD, DHAIRV = DHAIRV,
LHAIRD = LHAIRD, LHAIRV = LHAIRV, ZFURD = ZFURD, ZFURV = ZFURV,
RHOD = RHOD, RHOV = RHOV, REFLD = REFLD, TC_INC = TC_INC,
PANT_INC = PANT_INC, PANT_MAX = PANT_MAX, EXTREF = EXTREF,
UNCURL = UNCURL, SAMODE = SAMODE, SHADE = 0, PANT_MULT = PANT_MULT)
})proc.time() - ptm # end timing
## user system elapsed
## 0.73 0.02 0.96
# extract the output
<- do.call("rbind", lapply(endo.out, data.frame))
endo.out1
# thermoregulation output
<- endo.out1[, grep(pattern = "treg", colnames(endo.out1))]
treg colnames(treg) <- gsub(colnames(treg), pattern = "treg.", replacement = "")
# morphometric output
<- endo.out1[, grep(pattern = "morph", colnames(endo.out1))]
morph colnames(morph) <- gsub(colnames(morph), pattern = "morph.",
replacement = "")
# heat balance
<- endo.out1[, grep(pattern = "enbal", colnames(endo.out1))]
enbal colnames(enbal) <- gsub(colnames(enbal), pattern = "enbal.",
replacement = "")
# mass aspects
<- endo.out1[, grep(pattern = "masbal", colnames(endo.out1))]
masbal colnames(masbal) <- gsub(colnames(masbal), pattern = "masbal.",
replacement = "")
# extract variables for plotting
<- enbal$QGEN # metabolic rate (W)
QGEN <- masbal$H2OResp_g + masbal$H2OCut_g # g/h water evaporated
H2O <- treg$TFA_D # dorsal fur surface temperature
TFA_D <- treg$TFA_V # ventral fur surface temperature
TFA_V <- treg$TSKIN_D # dorsal skin temperature
TskinD <- treg$TSKIN_V # ventral skin temperature
TskinV <- treg$TC # core temperature
TCs <- treg$SKINWET # skin wetness (%)
SkinW <- treg$PANT # panting multiplier (-)
Pant
# plot the results
par(mfrow = c(2, 2))
par(oma = c(2, 1, 2, 2) + 0.1)
par(mar = c(3, 3, 1.5, 1) + 0.1)
par(mgp = c(2, 1, 0))
plot(QGEN ~ dates, type = "l", ylab = "metabolic rate, W", xlab = "time",
ylim = c(0, QBASAL * 5))
plot(H2O ~ dates, type = "l", ylab = "water loss, g / h", xlab = "time",
ylim = c(0, 2))
points(masbal$H2OResp_g ~ dates, type = "l", lty = 2)
points(masbal$H2OCut_g ~ dates, type = "l", lty = 2, col = "blue")
legend(x = 4, y = 2, legend = c("total", "respiratory", "cutaneous"),
col = c("black", "black", "blue"), lty = c(1, 2, 2), bty = "n")
plot(TFA_D ~ dates, type = "l", col = "grey", ylab = "temperature, °C",
xlab = "time", ylim = c(0, 60))
points(TFA_V ~ dates, type = "l", col = "grey", lty = 2)
points(TskinD ~ dates, type = "l", col = "orange")
points(TskinV ~ dates, type = "l", col = "orange", lty = 2)
points(TCs ~ dates, type = "l", col = "red")
legend(x = 1, y = 65, legend = c("core", "skin dorsal", "skin ventral",
"feathers dorsal", "feathers ventral"), col = c("red", "orange",
"orange", "grey", "grey"), lty = c(1, 1, 2, 1, 2), bty = "n",
ncol = 2)
plot((H2O/(AMASS * 1000)) * 100 ~ dates, type = "l", ylab = "H2O loss, % body mass / h",
xlab = "time", ylim = c(0, 5))