stochLAB is a tool to run stochastic (and deterministic) Collision Risk Models (CRM) for seabirds on offshore wind farms.
The main functions of stochLAB are:
stoch_crm()
: Stochastic Collision Risk Model,band_crm()
: Deterministic Collision Risk Model,mig_stoch_crm()
: Stochastic Migration Collision risk Model
Overview
The {stochLAB}
package is an adaptation of the R code
developed by Masden (2015)
to incorporate variability and uncertainty in the avian collision risk model
originally developed by Band (2012).
Code developed under {stochLAB}
substantially re-factored and re-structured
Masden's (heavily script-based) implementation into a user-friendly,
streamlined, well documented and easily distributed tool. Furthermore, this
package lays down the code infrastructure for easier incorporation of new
functionality, e.g. extra parameter sampling features, model expansions,
etc.
Previous code underpinning key calculations for the extended model has been
replaced by an alternative approach, resulting in significant gains in
computational speed over Masden's code. This optimization
is particularly beneficial under a stochastic context, when Band calculations
are computed repeatedly. See generate_rotor_grids()
for further details.
Function stoch_crm()
stoch_crm()
is essentially a replacement function for script BandModel.r
in Masden's approach. Main changes in terms of user interface include:
Collision model runs for one single scenario (i.e. one species for one turbine scenario) at each
stoch_crm()
call. Apart from gains in development code structure, this unit-based approach was considered to offer greater end user flexibility for setting up and managing multiple scenarios (including parallel computation).Input parameters now entered explicitly into feature-specific arguments, instead of bundled together into wide-column tables. This improves code readability and reduces the quantity of hard-coded parameter names, therefore making referencing errors less likely.
Outputs no longer saved automatically to external files.
Seasonal Outputs
stoch_crm()
now provides an option for user-defined seasonal outputs, allowing
for country/region specific seasonal definitions.
Currently implemented CRM calculations produce collision estimates on a monthly basis to reflect changing bird abundance within the windfarm area. Seasonal estimates are obtained by aggregating monthly estimates over each season definition, with uncertainty in collision estimates being suitably propagated to seasonal outputs.
Sampling distributions
Masden's implementation used Normal and Truncated Normal distributions to generate random parameter values. However, the Normal distribution is unbounded, and so there was the risk of randomly drawing inappropriate values in some cases.
stoch_crm()
extends the use of bounded probability distributions to all model
parameters. Strictly positive features (e.g. bird densities, body length,
turbine downtime, etc.) are sampled from Truncated Normal distributions, while
features constrained between 0 and 1 (e.g. nocturnal activity, proportion
of flights at collision risk height, etc) are assumed to follow Beta
distributions.
In addition, new functionality has been incorporated to allow the use of bird density resamples (e.g. bootstrap samples) or quantile estimates from density estimation models in the simulations.
Function band_crm()
band_crm()
performs the core CRM calculations required to estimate the
number of collisions, as per Band (2012).
While being the computing workhorse of the stoch_crm()
function, it can
also be used alone, providing backward compatibility with the original Band
spreadsheet outputs.
Examples
# ------------------------------------------------------
# Run with arbitrary parameter values, for illustration
# ------------------------------------------------------
# Setting a dataframe of parameters to draw from
params <- data.frame(
flight_speed = 13.1, # Flight speed in m/s
body_lt = 0.85, # Body length in m
wing_span = 1.01, # Wing span in m
flight_type = "flapping", # flapping or gliding flight
avoid_rt_basic = 0.989, # avoidance rate for option 1 and 2
avoid_rt_ext = 0.981, # extended avoidance rate for option 3 and 4
noct_activity = 0.5, # proportion of day birds are inactive
prop_crh_surv = 0.13, # proportion of birds at collision risk height (option 1 only)
prop_upwind = 0.5, # proportion of flights that are upwind
rotor_speed = 15, # rotor speed in m/s
rotor_radius = 120, # radius of turbine in m
blade_width = 5, # width of turbine blades at thickest point in m
blade_pitch = 15, # mean radius pitch in Radians
n_blades = 3, # total number of blades per turbine
hub_height = 150, # height of hub in m above HAT
n_turbines = 100, # number of turbines in the wind farm
wf_width = 52, # width across longest section of wind farm
wf_latitude = 56, # latitude of centroid of wind farm
tidal_offset = 2.5, # mean tidal offset from HAT of the wind farm
lrg_arr_corr = TRUE # apply a large array correction?
)
# Monthly bird densities
b_dens <- data.frame(
month = month.abb,
dens = runif(12, 0.8, 1.5)
)
# flight height distribution from Johnston et al
gen_fhd_dat <- Johnston_Flight_heights_SOSS %>%
dplyr::filter(variable=="Gannet.est") %>%
dplyr::select(height,prop)
# monthly operational time of the wind farm
turb_oper <- data.frame(
month = month.abb,
prop_oper = runif(12,0.5,0.8)
)
band_crm(
model_options = c(1,2,3),
flight_speed = params$flight_speed,
body_lt = params$body_lt,
wing_span = params$wing_span,
flight_type = params$flight_type,
avoid_rt_basic = params$avoid_rt_basic,
avoid_rt_ext = params$avoid_rt_ext,
noct_activity = params$noct_activity,
prop_crh_surv = params$prop_crh_surv,
dens_month = b_dens,
prop_upwind = params$prop_upwind,
gen_fhd = gen_fhd_dat,
site_fhd = NULL, # Option 4 only
rotor_speed = params$rotor_speed,
rotor_radius = params$rotor_radius,
blade_width = params$blade_width,
blade_pitch = params$blade_pitch,
n_blades = params$n_blades,
hub_height = params$hub_height,
chord_prof = chord_prof_5MW,
n_turbines = params$n_turbines,
turb_oper_month = turb_oper,
wf_width = params$wf_width,
wf_latitude = params$wf_latitude,
tidal_offset = params$tidal_offset,
lrg_arr_corr = params$lrg_arr_corr
)
#> # A tibble: 12 × 4
#> month opt1 opt2 opt3
#> <chr> <dbl> <dbl> <dbl>
#> 1 Jan 63.0 16.3 6.65
#> 2 Feb 63.9 16.5 6.74
#> 3 Mar 74.0 19.1 7.81
#> 4 Apr 110. 28.4 11.6
#> 5 May 98.4 25.4 10.4
#> 6 Jun 113. 29.2 11.9
#> 7 Jul 73.3 18.9 7.73
#> 8 Aug 52.6 13.6 5.54
#> 9 Sep 91.3 23.5 9.63
#> 10 Oct 70.5 18.2 7.43
#> 11 Nov 67.9 17.5 7.16
#> 12 Dec 70.2 18.1 7.40