Skip to content
Merged

Ci #16

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
175ca78
take savefig from example to setup block
progtw Oct 23, 2021
a6d8ed8
replace \code{...} in R docu
progtw Oct 23, 2021
b9d535c
replacing constant$key from R files
progtw Oct 23, 2021
d1f8194
implement global ratiation tests and help
progtw Oct 23, 2021
48cfcfb
reformatting evapotranspiration.jl
progtw Oct 23, 2021
e1de84a
return NamedTuple instead of SLVector
progtw Oct 24, 2021
a8b9982
implement DataFrame variants of potential_ET
progtw Oct 25, 2021
b85c328
modify handling of G and S defaults
progtw Oct 26, 2021
970a375
test and docu equilibrium_imposed_ET
bgctw Oct 26, 2021
c0cfa0f
revert to old syntax of adding broadcasted columns
bgctw Oct 26, 2021
446cfe2
add tests for potential radiation
bgctw Oct 26, 2021
7fb133c
Merge branch 'main' into ci
bgctw Oct 26, 2021
7c1768f
remove suppress_err in setup block
bgctw Oct 26, 2021
41a234b
remove suppress_err in example blocks
bgctw Oct 26, 2021
d266685
work on GPPd filter
progtw Oct 26, 2021
2b5eb7c
Merge branch 'main' into ci
progtw Oct 27, 2021
93159e8
implement filter_growing_season
progtw Oct 27, 2021
ddc1a6b
filter_growing_seasonthrow error too few GPP data
bgctw Oct 27, 2021
42f964e
work on filtering methods
bgctw Oct 27, 2021
0fe8b4d
update compat
bgctw Nov 1, 2021
d725052
revert @. with && to .&&
bgctw Nov 1, 2021
7b2f8d5
remove .&& - does not work with julia 1.6
progtw Nov 1, 2021
579fd21
readability of sun-position plot in walkthrough
bgctw Nov 1, 2021
d243758
implement setinvalid_afterprecip!
bgctw Nov 1, 2021
2321dae
remove surface_conductance from first help page
bgctw Nov 1, 2021
012b69f
update README
progtw Nov 1, 2021
4dbce59
remove non-mutating variant of potential_ET
progtw Nov 1, 2021
805656f
add test for setinvalid_qualityflag!
bgctw Nov 2, 2021
8b7afe5
working on wind profile
bgctw Nov 2, 2021
65cedda
work on wind_profile
bgctw Nov 3, 2021
f8a87ee
allo providing precomputed psi_m to wind_profile
bgctw Nov 3, 2021
c6d339b
estimate z0m in wind_profile
bgctw Nov 3, 2021
db0276d
docstrings of surface_roughness
bgctw Nov 3, 2021
c506251
docstrings of stability_correction
bgctw Nov 4, 2021
fd3875d
test fixing DocTest error
bgctw Nov 4, 2021
1ea0ce8
implement Gs_Choudhury and Gs_Su
bgctw Nov 4, 2021
c5efe54
document boundary_layer_conductance
bgctw Nov 4, 2021
a996167
commenting out aerodynami_conductance for now
bgctw Nov 4, 2021
293ee69
implement Gb_constant_kB1
bgctw Nov 5, 2021
e4abc54
implement add_Ga
bgctw Nov 8, 2021
0799b84
implement and document aerodynamic_conductance!
bgctw Nov 8, 2021
888056d
subset for valid data in walkthrough
bgctw Nov 8, 2021
d006e72
adapt tests to updated wind_profile
bgctw Nov 8, 2021
2295bab
adapt NamedTuple indexing by Symbol Vector to 1.6
bgctw Nov 8, 2021
d991cb6
add test for roughness_z0h
bgctw Nov 9, 2021
d06dd48
Merge branch 'main' into ci
bgctw Nov 9, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
using Bigleaf
using Documenter, Latexify
using Documenter, Latexify, DataFrames

# allow plot to work without display
# https://discourse.julialang.org/t/generation-of-documentation-fails-qt-qpa-xcb-could-not-connect-to-display/60988/2
ENV["GKSwstype"] = "100"

DocMeta.setdocmeta!(Bigleaf, :DocTestSetup, :(using Bigleaf, Latexify); recursive=true, warn=false)
DocMeta.setdocmeta!(Bigleaf, :DocTestSetup, :(using Bigleaf, Latexify, DataFrames);
recursive=true, warn=false)
doctest(Bigleaf, manual = false)

makedocs(;
modules=[Bigleaf],
authors="Thomas Wutzler <twutz@bgc-jena.mpg.de>. Jürgen Knauer <Juergen.Knauer@csiro.au> and contributors",
authors="Thomas Wutzler <twutz@bgc-jena.mpg.de>, Jürgen Knauer <Juergen.Knauer@csiro.au> and contributors",
repo="https://github.com/bgctw/Bigleaf.jl/blob/{commit}{path}#{line}",
sitename="Bigleaf.jl",
doctestfilters=[r".*Info.*"],
Expand All @@ -25,6 +26,11 @@ makedocs(;
#"Unit conversions" => "unit_conversions.md",
"Walkthrough" => "walkthrough.md",
hide("metorological_variables.md"),
hide("stability_correction.md"),
hide("surface_roughness.md"),
hide("boundary_layer_conductance.md"),
hide("surface_conductance.md"),
hide("aerodynamic_conductance.md"),
hide("evapotranspiration.md"),
hide("surface_conductance.md"),
hide("global_radiation.md"),
Expand Down
11 changes: 11 additions & 0 deletions docs/src/aerodynamic_conductance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## Aerodynamic Conductance
```@index
Pages = ["aerodynamic_conductance.md",]
```

```@docs
aerodynamic_conductance!
compute_Ram
roughness_z0h
add_Ga!
```
12 changes: 12 additions & 0 deletions docs/src/boundary_layer_conductance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## Boundary Layer Conductance
```@index
Pages = ["boundary_layer_conductance.md",]
```

```@docs
compute_Gb!
add_Gb!
Gb_Thom
Gb_Choudhury
Gb_Su
```
21 changes: 21 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,32 @@ Pages = ["index.md",]
Pages = ["metorological_variables.md",]
```

## Stability correction
```@index
Pages = ["stability_correction.md",]
```

## Surface roughness
```@index
Pages = ["surface_roughness.md",]
```

## Boundary Layer Conductance
```@index
Pages = ["boundary_layer_conductance.md",]
```

## Aerodynamic Conductance
```@index
Pages = ["aerodynamic_conductance.md",]
```

## Evapotranspiration
```@index
Pages = ["evapotranspiration.md",]
```


## Global radiation
```@index
Pages = ["global_radiation.md",]
Expand Down
10 changes: 10 additions & 0 deletions docs/src/stability_correction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## Stability correction
```@index
Pages = ["stability_correction.md",]
```

```@docs
Monin_Obukhov_length
stability_parameter
stability_correction
```
1 change: 0 additions & 1 deletion docs/src/surface_conductance.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@ Pages = ["surface_conductance.md",]
```@docs
decoupling
surface_conductance
aerodynamic_conductance
```
10 changes: 10 additions & 0 deletions docs/src/surface_roughness.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## Surface roughness
```@index
Pages = ["surface_roughness.md",]
```

```@docs
Reynolds_Number
roughness_parameters
wind_profile
```
135 changes: 125 additions & 10 deletions docs/src/walkthrough.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,12 @@ For more information on the site see e.g. Grünwald & Bernhofer 2007.
In addition, we will need some ancillary data for this site throughout this tutorial. To ensure consistency, we define them here at the beginning:

```@example doc
LAI = 7.6 # leaf area index
zh = 26.5 # average vegetation height (m)
zr = 42 # sensor height (m)
Dl = 0.01 # leaf characteristic dimension (m)
thal = (
LAI = 7.6, # leaf area index
zh = 26.5, # average vegetation height (m)
zr = 42, # sensor height (m)
Dl = 0.01, # leaf characteristic dimension (m)
)
nothing # hide
```

Expand Down Expand Up @@ -175,7 +177,7 @@ below which the quality control to be considered as acceptable quality
all `LE` values whose `LE_qc` variable is larger than 1 are set to `missing`.
The variable `missing_qc_as_bad` is required to decide what to do in
case of missing values in the quality control variable. By default this is (conservatively)
set to `TRUE`, i.e. all entries where the qc variable is missing is set invalid.
set to `true`, i.e. all entries where the qc variable is missing is set invalid.

### `setinvalid_range!`

Expand Down Expand Up @@ -249,6 +251,11 @@ setinvalid_afterprecip!(thaf; min_precip=0.02, hours_after=24)
sum(.!thaf.valid) # some more invalids
```

In this walkthrough we use the data as filtered above:
```@example doc
thas = subset(thaf, :valid)
```


## Meteorological variables

Expand Down Expand Up @@ -316,18 +323,125 @@ The following figure compares them at absole scale and as difference to the

![](fig/Esat_rel.svg)

## Aerodynamic conductance

An important metric for many calculations in the `Bigleaf.jl` package is the aerodynamic
conductance ($G_a$) between the land surface and the measurement height. $G_a$
characterizes how efficiently mass and energy is transferred between the land surface
and the atmosphere. $G_a$ consists of two parts: $G_{a_m}$, the aerodynamic conductance
for momentum, and $G_b$, the canopy boundary layer (or quasi-laminar) conductance.
$G_a$ can be defined as

$G_a = 1/(1/G_{a_m} + 1/G_b)$.

In this tutorial we will focus on
how to use the function [`aerodynamic_conductance!`](@ref).
For further details on the equations,
the reader is directed to the publication of the Bigleaf package (Knauer et al. 2018) and
the references therein. A good overview is provided by e.g. Verma 1989.

$G_a$ and in particular $G_b$ can be calculated with varying degrees of complexity.
We start with the simplest version, in which $G_b$ is calculated empirically based on
the friction velocity ($u_*$) according to Thom 1972:

```@example doc
aerodynamic_conductance!(thas)
thas[1:3, Cols(:datetime,Between(:zeta,:Ga_CO2))]
```

Note that by not providing additional arguments, the default values are taken.
We also do not need most of the arguments that can be provided to the function in this case
(i.e. with `Gb_model=Val(:Thom_1972)`). These are only required if we use a more complex
formulation of $G_b$.
The output of the function is another DataFrame which contains separate columns for
conductances and resistances of different scalars (momentum, heat, and $CO_2$ by default).

For comparison, we now calculate a second estimate of $G_a$, where the calculation of
$G_b$ is more physically-based (Su et al. 2001), and which requires more input variables
compared to the first version. In particular, we now need LAI, the leaf characteristic
dimension ($D_l$, assumed to be 1cm here), and information on sensor and canopy height
($z_r$ and $z_h$), as well as the displacement height (assumed to be 0.7*$z_h$):


```@example doc
aerodynamic_conductance!(thas;Gb_model=Val(:Su_2001),
LAI=thal.zh, zh=thal.zh, d=0.7*thal.zh, zr=thal.zr,Dl=thal.Dl)
thas[1:3, Cols(:datetime,Between(:zeta,:Ga_CO2))]
```

We see that the values are different compared to the first, empirical estimate.
This is because this formulation takes additional aerodynamically relevant properties
(LAI, $D_l$) into account that were not considered by the simple empirical formulation.


## Boundary layer conductance for trace gases

By default, the function `aerodynamic_conductance` (calling `compute_Gb!`) returns the
(quasi-laminar) canopy boundary layer ($G_{b}$) for heat and water vapor
(which are assumed to be equal in the `Bigleaf.jl`), as well as for CO$_2$.
Functin `add_Gb` calculates $G_b$ for other trace gases, provided that the respective Schmidt
number is known.

```@example doc
compute_Gb!(thas, Val(:Thom_1972)) # adds/modifies column Gb_h and Gb_CO2
add_Gb!(thas, :Gb_O2 => 0.84, :Gb_CH4 => 0.99) # adds Gb_O2 and Gb_CH4
select(first(thas,3), r"Gb_")
```

## Wind profile

The 'big-leaf' framework assumes that wind speed is zero at height d + $z_{0m}$
(where $z_{0m}$ is the roughness length for momentum) and then increases exponentially with
height. The shape of the wind profile further depends on the stability conditions of the
air above the canopy.
In `Bigleaf.jl`, a wind profile can be calculated assuming an exponential increase with
height, which is affected by atmospheric stability. Here, we calculate wind speed at
heights of 22-60m in steps of 2m. As expected, the gradient in wind speed is strongest
close to the surface and weaker at greater heights:

```@example doc
using Statistics
wind_heights = 22:2:60.0
d = 0.7 * thal.zh
z0m = roughness_parameters(Val(:wind_profile), thas, thal.zh, thal.zr).z0m
wp = map(wind_heights) do z
wind_profile(thas,z,d, z0m; zh=thal.zh, zr=thal.zr)
end
nothing # hide
```
```@setup doc
wp_means = map(x -> mean(skipmissing(x)), wp)
wp_sd = map(x -> std(skipmissing(x)), wp)
wr_mean = mean(skipmissing(thas.wind)) # measurements at reference height
wr_sd = std(skipmissing(thas.wind))
using Plots # plot wind profiles for the three rows in df
plot(wp_means, wind_heights, ylab = "height (m)", xlab = "wind speed (m/s)", xerror=wp_sd,
label=nothing)
scatter!(wp_means, wind_heights, label = nothing)
```
```@example doc
scatter!([wr_mean], [thal.zr], xerror = [wr_sd], markerstrokecolor=:blue, #hide
markerstrokewidth=2, label = nothing) # hide
```

Here, the points denote the mean wind speed and the bars denote the standard deviation
across time. The blue point/bar represent the values that were measured at zr = 42m.
In this case we see that the wind speed as "back-calculated" from the wind profile agrees
well with the actual measurements.


## Potential evapotranspiration

For many hydrological applications, it is relevant to get an estimate on the potential
evapotranspiration (PET). At the moment, the `Bigleaf.jl` contains two formulations
for the estimate of PET: the Priestley-Taylor equation, and the Penman-Monteith equation:

```@example doc
potential_ET!(thaf, Val(:PriestleyTaylor); G = thaf.G, infoGS = false)
potential_ET!(thas, Val(:PriestleyTaylor); G = thas.G, infoGS = false)
# TODO need aerodynamci and surface conductance to compute Ga and Gs_mol before
# potential_ET!(thaf, Val(:PenmanMonteith); G = thaf.G,
# Gs_pot=quantile(skipmissing(thaf.Gs_mol),0.95))
select(thaf[24:26,:], :datetime, :ET_pot, :LE_pot)
# potential_ET!(thas, Val(:PenmanMonteith); G = thas.G,
# Gs_pot=quantile(skipmissing(thas.Gs_mol),0.95))
select(thas[24:26,:], :datetime, :ET_pot, :LE_pot)
```

In the second calculation it is important to provide an estimate of aerodynamic
Expand All @@ -354,7 +468,8 @@ lat,long = 51.0, 13.6 # Dresden Germany
doy = 160
datetimes = DateTime(2021) .+Day(doy-1) .+ Hour.(hours) #.- Second(round(long*deg2second))
res3 = @pipe calc_sun_position_hor.(datetimes, lat, long) |> DataFrame(_)
@df res3 scatter(datetimes, cols([:altitude,:azimuth]), legend = :topleft, xlab="Date and Time", ylab = "rad", xrotation=6)
@df res3 scatter(datetimes, cols([:altitude,:azimuth]), legend = :topleft, # hide
xlab="Date and Time", ylab = "rad", xrotation=6) # hide
```

The hour-angle at noon represents the difference to
Expand Down
18 changes: 9 additions & 9 deletions inst/fromR/WUE_metrics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#'
#' Calculation of various water use efficiency (WUE) metrics.
#'
#' - data Data_frame or matrix containing all required variables
#' - data DataFrame or matrix containing all required variables
#' - GPP Gross primary productivity (umol CO2 m-2 s-1)
#' - NEE Net ecosystem exchange (umol CO2 m-2 s-1)
#' - LE Latent heat flux (W m-2)
Expand Down Expand Up @@ -36,7 +36,7 @@
#' ``uWUE= (GPP * sqrt(VPD)) / ET``
#'
#' All metrics are calculated based on the median of all values. E_g.
#' WUE = median(GPP/ET,na_rm=TRUE)
#' WUE = median(GPP/ET,na_rm=true)
#'
#' # Value
a named vector with the following elements:
Expand Down Expand Up @@ -64,12 +64,12 @@
#' ## filter data for dry periods and daytime at DE-Tha in June 2014
#' DE_Tha_Jun_2014_2 = filter_data(DE_Tha_Jun_2014,quality_control=false,
#' vars_qc=c("Tair","precip","VPD","H","LE"),
#' filter_growseas=false,filter_precip=TRUE,
#' filter_growseas=false,filter_precip=true,
#' filter_vars=c("Tair","PPFD","ustar"),
#' filter_vals_min=c(5,200,0.2),
#' filter_vals_max=c(NA,NA,NA),NA_as_invalid=TRUE,
#' filter_vals_max=c(missing,missing,missing),NA_as_invalid=true,
#' quality_ext="_qc",good_quality=c(0,1),
#' missing_qc_as_bad=TRUE,GPP="GPP",doy="doy",
#' missing_qc_as_bad=true,GPP="GPP",doy="doy",
#' year="year",tGPP=0.5,ws=15,min_int=5,precip="precip",
#' tprecip=0.1,precip_hours=24,records_per_hour=2)
#'
Expand All @@ -88,10 +88,10 @@ function WUE_metrics(data,GPP="GPP",NEE="NEE",LE="LE",VPD="VPD",Tair="Tair",
GPP = (GPP * constants[:umol2mol] * constants[:Cmol]) * constants[:kg2g] # gC m-2 s-1
NEE = (NEE * constants[:umol2mol] * constants[:Cmol]) * constants[:kg2g] # gC m-2 s-1

WUE = median(GPP/ET,na_rm=TRUE)
WUE_NEE = median(abs(NEE)/ET,na_rm=TRUE)
IWUE = median((GPP*VPD)/ET,na_rm=TRUE)
uWUE = median((GPP*sqrt(VPD))/ET,na_rm=TRUE)
WUE = median(GPP/ET,na_rm=true)
WUE_NEE = median(abs(NEE)/ET,na_rm=true)
IWUE = median((GPP*VPD)/ET,na_rm=true)
uWUE = median((GPP*sqrt(VPD))/ET,na_rm=true)

return(c(WUE=WUE,WUE_NEE=WUE_NEE,IWUE=IWUE,uWUE=uWUE))
end
Loading