TITLE: Using `any()` with `ifelse()` and `group_by()`
DATE: 2022-08-14
AUTHOR: John L. Godlee
====================================================================


I am doing some more work to update the SEOSAW database. When we
measure the growth and mortality of trees to monitor biomass
dynamics, it is important to have a consistent way of recording
mortality. For trees, especially trees with multiple stems, the
concept of "death" is not as simple as for animals. We generally
classify a tree as dead if all the above-ground tissue on the tree
appears to be dead, i.e. has no living leaves or buds, and no sap
below the bark. Sometimes though, a single stem on a multi-stemmed
tree will die, but the rest of the tree continues to live.
Sometimes a stem or tree may appear dead, but comes back to life
later. In savanna systems especially, it's fairly common for trees
to partially die, or to resurrect after a disturbance event like a
drought or a fire.

 [SEOSAW database]: https://seosaw.github.io

In SEOSAW we previously classified stems as either "alive",
"topkilled", "resprouting" or "dead". I first heard the term
topkill used in a paper by Bill Hoffmann (Hoffmann et al. 2009),
where they define it as "the complete death of aerial biomass". In
SEOSAW we tried to tighten up the term a bit by defining it as a
stem where there is no living tissue above the point of DBH
measurement. A resprouting stem is defined as a topkilled stem
where there is new material sprouting from the stem. The difficulty
with this old system was that it was very subjective to decide
whether a stem was topkilled or dead, and whether a stem was
resprouting or top-killed. How do you define whether living tissue
on a stem is the result of resprouting? Does resprouting tissue
have to be growing directly from the above-ground parts of the
topkilled stem to be classed as resprouting?

 [Hoffmann et al. 2009]: https://doi.org/10.1890/08-0741.1

We recently came up with a revised mortality classification. This
classification only has "alive", "resprouting", and "dead". A stem
is classified as resprouting if it doesn't appear to have any
living tissue above the DBH measurement, but there are signs of
life elsewhere on the tree. Other signs of life can come from other
stems on the tree, from resprouting material at the base of the
tree, or from resprouting material on the stem of interest below
the DBH measurement. A stem can only be classified as dead if all
stems on the tree are dead and there is no sign of life anywhere
else on the above-ground parts of the organism. It follows then
that on a multi-stemmed tree, a stem cannot be classified as dead
unless all other stems on the tree are dead. Additionally however,
even if all stems on a tree are lacking living tissue this still
doesn't mean that the stems will be classified as dead if there is
living material somewhere else on the tree, i.e. from the base of
the stool on a heavily coppiced individual.

In light of this new classification, I had to adjust the mortality
data in some old censuses. I wrote a check that would flag stems
classified as dead when other stems on the tree were classified as
alive or resprouting.

   # Split data by plot ID, tree ID, and census date
   x_split <- split(x, list(x$plot_id, x$tree_id, x$census_date),
       drop = TRUE)

   # Only check trees with more than one stem
   x_split_fil <- x_split[unlist(lapply(x_split, nrow)) > 1]

   # If there are some trees with multiple stems, check each one
   if (length(x_split_fil) > 0) {
     # For each tree
     x_zomb <- unlist(lapply(x_split_fil, function(i) {
       # Flag if any stems are dead and any other stems are alive
or resprouting
       status <- i$stem_status[!is.na(i$stem_status)]
       any(status == "d") & any(status %in% c("a", "r"))
     }))
     names(x_zomb[x_zomb])
   }

I also concocted a little snippet using {dplyr} that I could use to
adjust the values of stems that had been classified as dead to
resprouting.

   x %>%
     group_by(plot_id, tree_id, census_date) %>%
     mutate(
       stem_status = case_when(
         # If any stems on the tree are alive or resprouting
         # change dead stems to resprouting
         any(stem_status %in% c("a", "r")) & stem_status == "d" ~
"r",
         TRUE ~ stem_status)
     )