diff prosail-master/R/Lib_PROSAIL.R @ 0:a8dabbf47e15 draft

planemo upload for repository https://github.com/Marie59/Sentinel_2A/srs_tools commit b32737c1642aa02cc672534e42c5cb4abe0cd3e7
author ecology
date Mon, 09 Jan 2023 13:39:08 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/prosail-master/R/Lib_PROSAIL.R	Mon Jan 09 13:39:08 2023 +0000
@@ -0,0 +1,1233 @@
+# ============================================================================= =
+# prosail
+# Lib_PROSAIL.R
+# ============================================================================= =
+# PROGRAMMERS:
+# Jean-Baptiste FERET <jb.feret@teledetection.fr >
+# Florian de BOISSIEU <fdeboiss@gmail.com >
+# copyright 2019 / 11 Jean-Baptiste FERET
+# ============================================================================= =
+# This Library includes functions dedicated to PROSAIL simulation
+# SAIL versions available are 4SAIL and 4SAIL2
+# ============================================================================= =
+
+#" computes bidirectional reflectance factor based on outputs from PROSAIL and sun position
+#"
+#" The direct and diffuse light are taken into account as proposed by:
+#" Francois et al. (2002) conversion of 400-1100 nm vegetation albedo
+#" measurements into total shortwave broadband albedo using a canopy
+#" radiative transfer model,  Agronomie
+#" Es = direct
+#" Ed = diffuse
+#"
+#" @param rdot numeric. Hemispherical-directional reflectance factor in viewing direction
+#" @param rsot numeric. Bi-directional reflectance factor
+#" @param tts numeric. Solar zenith angle
+#" @param specatm_sensor list. direct and diffuse radiation for clear conditions
+#" @return brf numeric. Bidirectional reflectance factor
+#" @export
+compute_brf  <- function(rdot, rsot, tts, specatm_sensor) {
+
+  ############################## #
+  ##	direct  /  diffuse light	##
+  ############################## #
+  es <- specatm_sensor$Direct_Light
+  ed <- specatm_sensor$Diffuse_Light
+  rd <- pi / 180
+  skyl <- 0.847 - 1.61 * sin((90 - tts) * rd) +  1.04 * sin((90 - tts) * rd) * sin((90 - tts) * rd) # diffuse radiation (Francois et al.,  2002)
+  pardiro <- (1 - skyl) * es
+  pardifo <- skyl * ed
+  brf <- (rdot * pardifo + rsot * pardiro) / (pardiro + pardifo)
+  return(brf)
+}
+
+#" Performs PROSAIL simulation based on a set of combinations of input parameters
+#" @param spec_sensor list. Includes optical constants required for PROSPECT
+#" refractive index,  specific absorption coefficients and corresponding spectral bands
+#" @param input_prospect  list. PROSPECT input variables
+#" @param n numeric. Leaf structure parameter
+#" @param chl numeric. chlorophyll content (microg.cm-2)
+#" @param car numeric. carotenoid content (microg.cm-2)
+#" @param ant numeric. anthocyain content (microg.cm-2)
+#" @param brown numeric. brown pigment content (Arbitrary units)
+#" @param ewt numeric. Equivalent Water Thickness (g.cm-2)
+#" @param lma numeric. Leaf Mass per Area (g.cm-2)
+#" @param prot numeric. protein content  (g.cm-2)
+#" @param cbc numeric. nonprotcarbon-based constituent content (g.cm-2)
+#" @param alpha numeric. Solid angle for incident light at surface of leaf (simulation of roughness)
+#" @param typelidf numeric. Type of leaf inclination distribution function
+#" @param lidfa numeric.
+#" if typelidf  == 1,  controls the average leaf slope
+#" if typelidf  == 2,  corresponds to average leaf angle
+#" @param lidfb numeric.
+#" if typelidf  == 1,  unused
+#" if typelidf  == 2,  controls the distribution"s bimodality
+#" @param lai numeric. Leaf Area Index
+#" @param q numeric. Hot Spot parameter
+#" @param tts numeric. Sun zeith angle
+#" @param tto numeric. Observer zeith angle
+#" @param psi numeric. Azimuth Sun  /  Observer
+#" @param rsoil numeric. Soil reflectance
+#" @param fraction_brown numeric. Fraction of brown leaf area
+#" @param diss numeric. Layer dissociation factor
+#" @param cv numeric. vertical crown cover percentage
+#" = % ground area covered with crowns as seen from nadir direction
+#" @param zeta numeric. Tree shape factor
+#" = ratio of crown diameter to crown height
+#" @param sailversion character. choose between 4SAIL and 4SAIL2
+#" @param brownvegetation list. Defines optical properties for brown vegetation,  if not nULL
+#" - WVL,  reflectance,  Transmittance
+#" - Set to nULL if use PROSPECT to generate it
+#"
+#" @return list. rdot, rsot, rddt, rsdt
+#" rdot: hemispherical-directional reflectance factor in viewing direction
+#" rsot: bi-directional reflectance factor
+#" rsdt: directional-hemispherical reflectance factor for solar incident flux
+#" rddt: bi-hemispherical reflectance factor
+#" @import prospect
+#" @export
+pro4sail  <- function(spec_sensor, input_prospect = nULL, n = 1.5, chl = 40.0,
+                     car = 8.0, ant = 0.0, brown = 0.0, ewt = 0.01,
+                     lma = 0.008, prot = 0.0, cbc = 0.0, alpha = 40.0,
+                     typelidf = 2, lidfa = nULL, lidfb = nULL, lai = nULL,
+                     q = nULL, tts = nULL, tto = nULL, psi = nULL, rsoil = nULL,
+                     fraction_brown = 0.0,  diss = 0.0,  cv = 1, zeta = 1,
+                     sailversion = "4SAIL", brownvegetation = nULL) {
+
+  ############################ #
+  #	LEAF OPTICAL PROPERTIES	##
+  ############################ #
+  if (is.null(input_prospect)) {
+    input_prospect <- data.frame("chl" = chl, "car" = car, "ant" = ant, "brown" = brown, "ewt" = ewt,
+                                "lma" = lma, "prot" = prot, "cbc" = cbc, "n" = n, "alpha" = alpha)
+  }
+  greenvegetation <- prospect::PROSPECT(SpecPROSPECT = spec_sensor,
+                                        n = input_prospect$n[1],
+                                        chl = input_prospect$chl[1],
+                                        car = input_prospect$car[1],
+                                        ant = input_prospect$ant[1],
+                                        brown = input_prospect$brown[1],
+                                        ewt = input_prospect$ewt[1],
+                                        lma = input_prospect$lma[1],
+                                        prot = input_prospect$prot[1],
+                                        cbc = input_prospect$cbc[1],
+                                        alpha = input_prospect$alpha[1])
+
+  if (sailversion  ==  "4SAIL2") {
+    # 4SAIL2 requires one of the following combination of input parameters
+    # Case #1: valid optical properties for brown vegetation
+    if (!is.null(brownvegetation)) {
+      # need to define reflectance and Transmittance for brownvegetation
+      if (length(grep("reflectance", names(brownvegetation))) == 0 || length(grep("Transmittance", names(brownvegetation))) == 0) {
+        message("Please define brownvegetation as a list including reflectance and Transmittance")
+        stop()
+      }
+      # check if spectral domain for optical properties of brown vegetation match
+      # with spectral domain for optical properties of green vegetation
+      if (length(setdiff(spec_sensor$lambda, brownvegetation$wvl)) > 0) {
+        message("Please define same spectral domain for brownvegetation and SpecPROSPECT")
+        stop()
+      }
+      if (length(unique(lengths(input_prospect))) == 1) {
+        if (!unique(lengths(input_prospect)) == 1) {
+          message("brownvegetation defined along with multiple leaf chemical properties")
+          message("Only first set of leaf chemical properties will be used to simulate green vegetation")
+        }
+      }
+    # if no leaf optical properties brown vegetation defined
+    } else if (is.null(brownvegetation)) {
+      # if all PROSPECT input parameters have the same length
+      if (length(unique(lengths(input_prospect))) == 1) {
+        # if all PROSPECT input parameters are unique (no possibility to simulate 2 types of leaf optics)
+        if (unique(lengths(input_prospect)) == 1) {
+          # if fraction_brown set to 0,  then assign green vegetation optics to brown vegetation optics
+          if (fraction_brown == 0) {
+            brownvegetation <- greenvegetation
+          # else run 4SAIL
+          } else {
+            message("4SAIL2 needs two sets of optical properties for green and brown vegetation")
+            message("Currently one set is defined. will run 4SAIL instead of 4SAIL2")
+            sailversion <- "4SAIL"
+          }
+        # if all PROSPECT parameters have at least 2 elements
+        } else if (unique(lengths(input_prospect)) >= 2) {
+          # compute leaf optical properties
+          brownvegetation <- prospect::PROSPECT(SpecPROSPECT = spec_sensor,
+                                                n = input_prospect$n[2],
+                                                chl = input_prospect$chl[2],
+                                                car = input_prospect$car[2],
+                                                ant = input_prospect$ant[2],
+                                                brown = input_prospect$brown[2],
+                                                ewt = input_prospect$ewt[2],
+                                                lma = input_prospect$lma[2],
+                                                prot = input_prospect$prot[2],
+                                                cbc = input_prospect$cbc[2],
+                                                alpha = input_prospect$alpha[2])
+          if (unique(lengths(input_prospect)) > 2) {
+            message("4SAIL2 needs two sets of optical properties for green and brown vegetation")
+            message("Currently more than 2 sets are defined. will only use the first 2")
+          }
+        }
+      }
+    }
+  }
+  if (sailversion  ==  "4SAIL") {
+    if (length(unique(lengths(input_prospect))) == 1) {
+      if (unique(lengths(input_prospect)) > 1) {
+        message("4SAIL needs only one set of optical properties")
+        message("Currently more than one set of leaf chemical constituents is defined.")
+        message("Will run 4SAIL with the first set of leaf chemical constituents")
+      }
+    }
+  }
+
+  if (sailversion  ==  "4SAIL") {
+    # run 4SAIL
+    ref <- foursail(leafoptics = greenvegetation,
+                    typelidf,  lidfa,  lidfb,  lai,  q,  tts,  tto,  psi,  rsoil)
+  } else if (sailversion  ==  "4SAIL2") {
+    # run 4SAIL2
+    ref <- foursail2(leafgreen = greenvegetation,  leafbrown = brownvegetation,
+                     typelidf,  lidfa,  lidfb,  lai,  q,  tts,  tto,  psi,  rsoil,
+                     fraction_brown,  diss,  cv,  zeta)
+  }
+  return(ref)
+}
+
+#" Performs PROSAIL simulation based on a set of combinations of input parameters
+#" @param leafoptics list. Includes leaf optical properties (reflectance and transmittance)
+#" and corresponding spectral bands
+#" @param typelidf numeric. Type of leaf inclination distribution function
+#" @param lidfa numeric.
+#" if typelidf  == 1,  controls the average leaf slope
+#" if typelidf  == 2,  corresponds to average leaf angle
+#" @param lidfb numeric.
+#" if typelidf  == 1,  unused
+#" if typelidf  == 2,  controls the distribution"s bimodality
+#" @param lai numeric. Leaf Area Index
+#" @param q numeric. Hot Spot parameter
+#" @param tts numeric. Sun zeith angle
+#" @param tto numeric. Observer zeith angle
+#" @param psi numeric. Azimuth Sun  /  Observer
+#" @param rsoil numeric. Soil reflectance
+#"
+#" @return list. rdot, rsot, rddt, rsdt
+#" rdot: hemispherical-directional reflectance factor in viewing direction
+#" rsot: bi-directional reflectance factor
+#" rsdt: directional-hemispherical reflectance factor for solar incident flux
+#" rddt: bi-hemispherical reflectance factor
+#" @export
+
+foursail  <- function(leafoptics,  typelidf = 2,  lidfa = nULL,  lidfb = nULL,  lai = nULL,
+                      q = nULL,  tts = nULL,  tto = nULL,  psi = nULL,  rsoil = nULL) {
+
+  ############################## #
+  #	LEAF OPTICAL PROPERTIES	##
+  ############################## #
+  rho <- leafoptics$Reflectance
+  tau <- leafoptics$Transmittance
+
+  #	Geometric quantities
+  rd <- pi / 180
+  cts <- cos(rd * tts)
+  cto <- cos(rd * tto)
+  ctscto <- cts * cto
+  tants <- tan(rd * tts)
+  tanto <- tan(rd * tto)
+  cospsi <- cos(rd * psi)
+  dso <- sqrt(tants * tants + tanto * tanto - 2. * tants * tanto * cospsi)
+
+  #	Generate leaf angle distribution from average leaf angle (ellipsoidal) or (a, b) parameters
+  if (typelidf == 1) {
+    foliar_distrib <- dladgen(lidfa, lidfb)
+    lidf <- foliar_distrib$lidf
+    litab <- foliar_distrib$litab
+
+  } else if (typelidf == 2) {
+    foliar_distrib <- campbell(lidfa)
+    lidf <- foliar_distrib$lidf
+    litab <- foliar_distrib$litab
+  }
+
+  # angular distance,  compensation of shadow length
+  #	Calculate geometric factors associated with extinction and scattering
+  #	Initialise sums
+  ks <- 0
+  ko <- 0
+  bf <- 0
+  sob <- 0
+  sof <- 0
+
+  #	Weighted sums over LIDF
+  na <- length(litab)
+  for (i in 1:na) {
+    ttl <- litab[i]	    # leaf inclination discrete values
+    ctl <- cos(rd * ttl)
+    #	SAIL volume scattering phase function gives interception and portions to be
+    #	multiplied by rho and tau
+    resvolscatt <- volscatt(tts, tto, psi, ttl)
+    chi_s <- resvolscatt$chi_s
+    chi_o <- resvolscatt$chi_o
+    frho <- resvolscatt$frho
+    ftau <- resvolscatt$ftau
+
+    #********************************************************************************
+    #*                   SUITS SYSTEM coEFFICIEnTS
+    #*
+    #*	ks  : Extinction coefficient for direct solar flux
+    #*	ko  : Extinction coefficient for direct observed flux
+    #*	att : Attenuation coefficient for diffuse flux
+    #*	sigb : Backscattering coefficient of the diffuse downward flux
+    #*	sigf : Forwardscattering coefficient of the diffuse upward flux
+    #*	sf  : Scattering coefficient of the direct solar flux for downward diffuse flux
+    #*	sb  : Scattering coefficient of the direct solar flux for upward diffuse flux
+    #*	vf   : Scattering coefficient of upward diffuse flux in the observed direction
+    #*	vb   : Scattering coefficient of downward diffuse flux in the observed direction
+    #*	w   : Bidirectional scattering coefficient
+    #********************************************************************************
+
+    #	Extinction coefficients
+    ksli <- chi_s / cts
+    koli <- chi_o / cto
+
+    #	Area scattering coefficient fractions
+    sobli <- frho * pi / ctscto
+    sofli <- ftau * pi / ctscto
+    bfli <- ctl * ctl
+    ks <- ks + ksli * lidf[i]
+    ko <- ko + koli * lidf[i]
+    bf <- bf + bfli * lidf[i]
+    sob <- sob + sobli * lidf[i]
+    sof <- sof + sofli * lidf[i]
+  }
+
+  #	Geometric factors to be used later with rho and tau
+  sdb <- 0.5 * (ks + bf)
+  sdf <- 0.5 * (ks - bf)
+  dob <- 0.5 * (ko + bf)
+  dof <- 0.5 * (ko - bf)
+  ddb <- 0.5 * (1. + bf)
+  ddf <- 0.5 * (1. - bf)
+
+  #	Here rho and tau come in
+  sigb <- ddb * rho + ddf * tau
+  sigf <- ddf * rho + ddb * tau
+  att <- 1 - sigf
+  m2 <- (att + sigb) * (att - sigb)
+  m2[which(m2 <= 0)] <- 0
+  m <- sqrt(m2)
+
+  sb <- sdb * rho + sdf * tau
+  sf <- sdf * rho + sdb * tau
+  vb <- dob * rho + dof * tau
+  vf <- dof * rho + dob * tau
+  w <- sob * rho + sof * tau
+
+  #	Here the LAI comes in
+  #   Outputs for the case LAI = 0
+  if (lai < 0) {
+    tss <- 1
+    too <- 1
+    tsstoo <- 1
+    rdd <- 0
+    tdd <- 1
+    rsd <- 0
+    tsd <- 0
+    rdo <- 0
+    tdo <- 0
+    rso <- 0
+    rsos <- 0
+    rsod <- 0
+
+    rddt <- rsoil
+    rsdt <- rsoil
+    rdot <- rsoil
+    rsodt <- 0 * rsoil
+    rsost <- rsoil
+    rsot <- rsoil
+  } else {
+    #	Other cases (LAI  >  0)
+    e1 <- exp(-m * lai)
+    e2 <- e1 * e1
+    rinf <- (att - m) / sigb
+    rinf2 <- rinf * rinf
+    re <- rinf * e1
+    denom <- 1. - rinf2 * e2
+
+    j1ks <- jfunc1(ks, m, lai)
+    j2ks <- jfunc2(ks, m, lai)
+    j1ko <- jfunc1(ko, m, lai)
+    j2ko <- jfunc2(ko, m, lai)
+
+    ps <- (sf + sb * rinf) * j1ks
+    qs <- (sf * rinf + sb) * j2ks
+    pv <- (vf + vb * rinf) * j1ko
+    qv <- (vf * rinf + vb) * j2ko
+
+    rdd <- rinf * (1. - e2) / denom
+    tdd <- (1. - rinf2) * e1 / denom
+    tsd <- (ps - re * qs) / denom
+    rsd <- (qs - re * ps) / denom
+    tdo <- (pv - re * qv) / denom
+    rdo <- (qv - re * pv) / denom
+
+    tss <- exp(-ks * lai)
+    too <- exp(-ko * lai)
+    z <- jfunc3(ks, ko, lai)
+    g1 <- (z - j1ks * too) / (ko + m)
+    g2 <- (z - j1ko * tss) / (ks + m)
+
+    tv1 <- (vf * rinf + vb) * g1
+    tv2 <- (vf + vb * rinf) * g2
+    t1 <- tv1 * (sf + sb * rinf)
+    t2 <- tv2 * (sf * rinf + sb)
+    t3 <- (rdo * qs + tdo * ps) * rinf
+
+    #	Multiple scattering contribution to bidirectional canopy reflectance
+    rsod <- (t1 + t2 - t3) / (1. - rinf2)
+
+    #	Treatment of the hotspot-effect
+    alf <- 1e6
+    #	Apply correction 2 / (K + k) suggested by F.-M. Breon
+    if (q > 0) {
+      alf <- (dso / q) * 2. / (ks + ko)
+    }
+    if (alf > 200) {
+      # inserted H. Bach 1 / 3 / 04
+      alf <- 200
+    }
+    if (alf == 0) {
+      #	The pure hotspot - no shadow
+      tsstoo <- tss
+      sumint <- (1 - tss) / (ks * lai)
+    } else {
+      #	Outside the hotspot
+      fhot <- lai * sqrt(ko * ks)
+      #	Integrate by exponential Simpson method in 20 steps
+      #	the steps are arranged according to equal partitioning
+      #	of the slope of the joint probability function
+      x1 <- 0
+      y1 <- 0
+      f1 <- 1
+      fint <- (1. - exp(-alf)) * 0.05
+      sumint <- 0
+      for (i in 1:20) {
+        if (i < 20) {
+          x2 <- -log(1. - i * fint) / alf
+        } else {
+          x2 <- 1
+        }
+        y2 <- -(ko + ks) * lai * x2 + fhot * (1. - exp(-alf * x2)) / alf
+        f2 <- exp(y2)
+        sumint <- sumint + (f2 - f1) * (x2 - x1) / (y2 - y1)
+        x1 <- x2
+        y1 <- y2
+        f1 <- f2
+      }
+      tsstoo <- f1
+    }
+    #	Bidirectional reflectance
+    #	Single scattering contribution
+    rsos <- w * lai * sumint
+    #	Total canopy contribution
+    rso <- rsos + rsod
+    #	Interaction with the soil
+    dn <- 1. - rsoil * rdd
+    # rddt: bi-hemispherical reflectance factor
+    rddt <- rdd + tdd * rsoil * tdd / dn
+    # rsdt: directional-hemispherical reflectance factor for solar incident flux
+    rsdt <- rsd + (tsd + tss) * rsoil * tdd / dn
+    # rdot: hemispherical-directional reflectance factor in viewing direction
+    rdot <- rdo + tdd * rsoil * (tdo + too) / dn
+    # rsot: bi-directional reflectance factor
+    rsodt <- rsod + ((tss + tsd) * tdo + (tsd + tss * rsoil * rdd) * too) * rsoil / dn
+    rsost <- rsos + tsstoo * rsoil
+    rsot <- rsost + rsodt
+  }
+  my_list <- list("rdot" = rdot, "rsot" = rsot, "rddt" = rddt, "rsdt" = rsdt)
+  return(my_list)
+}
+
+#" Performs pro4sail2 simulation based on a set of combinations of input parameters
+#" @param leafgreen list. includes relfectance and transmittance for vegetation #1 (e.g. green vegetation)
+#" @param leafbrown list. includes relfectance and transmittance for vegetation #2 (e.g. brown vegetation)
+#" @param typelidf numeric. Type of leaf inclination distribution function
+#" @param lidfa numeric.
+#" if typelidf  == 1,  controls the average leaf slope
+#" if typelidf  == 2,  corresponds to average leaf angle
+#" @param lidfb numeric.
+#" if typelidf  == 1,  unused
+#" if typelidf  == 2,  controls the distribution"s bimodality
+#" @param lai numeric. Leaf Area Index
+#" @param hot numeric. Hot Spot parameter = ratio of the correlation length of leaf projections in the horizontal plane and the canopy height (doi:10.1016 / j.rse.2006.12.013)
+#" @param tts numeric. Sun zeith angle
+#" @param tto numeric. Observer zeith angle
+#" @param psi numeric. Azimuth Sun  /  Observer
+#" @param rsoil numeric. Soil reflectance
+#" @param fraction_brown numeric. Fraction of brown leaf area
+#" @param diss numeric. Layer dissociation factor
+#" @param cv numeric. vertical crown cover percentage
+#" = % ground area covered with crowns as seen from nadir direction
+#" @param zeta numeric. Tree shape factor
+#" = ratio of crown diameter to crown height
+#"
+#" @return list. rdot, rsot, rddt, rsdt
+#" rdot: hemispherical-directional reflectance factor in viewing direction
+#" rsot: bi-directional reflectance factor
+#" rsdt: directional-hemispherical reflectance factor for solar incident flux
+#" rddt: bi-hemispherical reflectance factor
+#" alfast: canopy absorptance for direct solar incident flux
+#" alfadt: canopy absorptance for hemispherical diffuse incident flux
+#" @export
+
+foursail2  <- function(leafgreen,  leafbrown,
+                       typelidf = 2, lidfa = nULL, lidfb = nULL,
+                       lai = nULL,  hot = nULL, tts = nULL, tto = nULL, psi = nULL, rsoil = nULL,
+                       fraction_brown = 0.5,  diss = 0.5,  cv = 1, zeta = 1) {
+
+  #	This version does not include non-Lambertian soil properties.
+  #	original codes do,  and only need to add the following variables as input
+  rddsoil <- rdosoil <- rsdsoil <- rsosoil <- rsoil
+
+  #	Geometric quantities
+  rd <- pi / 180
+
+  #	Generate leaf angle distribution from average leaf angle (ellipsoidal) or (a, b) parameters
+  if (typelidf == 1) {
+    foliar_distrib <- dladgen(lidfa, lidfb)
+    lidf <- foliar_distrib$lidf
+    litab <- foliar_distrib$litab
+
+  } else if (typelidf == 2) {
+    foliar_distrib <- campbell(lidfa)
+    lidf <- foliar_distrib$lidf
+    litab <- foliar_distrib$litab
+  }
+
+  if (lai < 0) {
+    message("Please define positive LAI value")
+    rddt <- rsdt <- rdot <- rsost <- rsot <- rsoil
+    alfast <- alfadt <- 0 * rsoil
+  } else if (lai == 0) {
+    tss <- too <- tsstoo <- tdd <- 1.0
+    rdd <- rsd <- tsd <- rdo <- tdo <- 0.0
+    rso <- rsos <- rsod <- rsodt <- 0.0
+    rddt <- rsdt <- rdot <- rsost <- rsot <- rsoil
+    alfast <- alfadt <- 0 * rsoil
+  } else if (lai > 0) {
+    cts <- cos(rd * tts)
+    cto <- cos(rd * tto)
+    ctscto <- cts * cto
+    tants <- tan(rd * tts)
+    tanto <- tan(rd * tto)
+    cospsi <- cos(rd * psi)
+    dso <- sqrt(tants * tants + tanto * tanto - 2.0 * tants * tanto * cospsi)
+
+    # Clumping effects
+    cs <- co <- 1.0
+    if (cv <= 1.0) {
+      cs <- 1.0 - (1.0 - cv)^(1.0 / cts)
+      co <- 1.0 - (1.0 - cv)^(1.0 / cto)
+    }
+    overlap <- 0.0
+    if (zeta > 0.0) {
+      overlap <- min(cs * (1.0 - co), co * (1.0 - cs)) * exp(-dso / zeta)
+    }
+    fcd <- cs * co + overlap
+    fcs <- (1.0 - cs) * co - overlap
+    fod <- cs * (1.0 - co) - overlap
+    fos <- (1.0 - cs) * (1.0 - co) + overlap
+    fcdc <- 1.0 - (1.0 - fcd)^(0.5 / cts + 0.5 / cto)
+
+    #	Part depending on diss,  fraction_brown,  and leaf optical properties
+    #	First save the input fraction_brown as the old fraction_brown,  as the following change is only artificial
+    # Better define an fraction_brown that is actually used: fb,  so that the input is not modified!
+
+    fb <- fraction_brown
+    # if only green leaves
+    if (fraction_brown == 0.0) {
+      fb <- 0.5
+      leafbrown$Reflectance <- leafgreen$Reflectance
+      leafbrown$Transmittance <- leafgreen$Transmittance
+    }
+    if (fraction_brown == 1.0) {
+      fb <- 0.5
+      leafgreen$Reflectance <- leafbrown$Reflectance
+      leafgreen$Transmittance <- leafbrown$Transmittance
+    }
+    s <- (1.0 - diss) * fb * (1.0 - fb)
+    # rho1 && tau1 : green foliage
+    # rho2 && tau2 : brown foliage (bottom layer)
+    rho1 <- ((1 - fb - s) * leafgreen$Reflectance + s * leafbrown$Reflectance) / (1 - fb)
+    tau1 <- ((1 - fb - s) * leafgreen$Transmittance + s * leafbrown$Transmittance) / (1 - fb)
+    rho2 <- (s * leafgreen$Reflectance + (fb - s) * leafbrown$Reflectance) / fb
+    tau2 <- (s * leafgreen$Transmittance + (fb - s) * leafbrown$Transmittance) / fb
+
+    # angular distance,  compensation of shadow length
+    #	Calculate geometric factors associated with extinction and scattering
+    #	Initialise sums
+    ks <- ko <- bf <- sob <- sof <- 0
+
+    # Weighted sums over LIDF
+
+    for (i in 1:seq_along(litab)) {
+      ttl <- litab[i]
+      ctl <- cos(rd * ttl)
+      # SAIL volscatt function gives interception coefficients
+      # and two portions of the volume scattering phase function to be
+      # multiplied by rho and tau,  respectively
+      resvolscatt <- volscatt(tts, tto, psi, ttl)
+      chi_s <- resvolscatt$chi_s
+      chi_o <- resvolscatt$chi_o
+      frho <- resvolscatt$frho
+      ftau <- resvolscatt$ftau
+      # Extinction coefficients
+      ksli <- chi_s / cts
+      koli <- chi_o / cto
+      # Area scattering coefficient fractions
+      sobli <- frho * pi / ctscto
+      sofli <- ftau * pi / ctscto
+      bfli <- ctl * ctl
+      ks <- ks + ksli * lidf[i]
+      ko <- ko + koli * lidf[i]
+      bf <- bf + bfli * lidf[i]
+      sob <- sob + sobli * lidf[i]
+      sof <- sof + sofli * lidf[i]
+    }
+    # Geometric factors to be used later in combination with rho and tau
+    sdb <- 0.5 * (ks + bf)
+    sdf <- 0.5 * (ks - bf)
+    dob <- 0.5 * (ko + bf)
+    dof <- 0.5 * (ko - bf)
+    ddb <- 0.5 * (1. + bf)
+    ddf <- 0.5 * (1. - bf)
+
+    # LAIs in two layers
+    lai1 <- (1 - fb) * lai
+    lai2 <- fb * lai
+
+    tss <- exp(-ks * lai)
+    ck <- exp(-ks * lai1)
+    alf <- 1e6
+    if (hot > 0.0) {
+      alf <- (dso / hot) * 2.0 / (ks + ko)
+    }
+    if (alf > 200.0) {
+      alf <- 200.0     # inserted H. Bach 1 / 3 / 04
+    }
+    if (alf == 0.0) {
+      # The pure hotspot
+      tsstoo <- tss
+      s1 <- (1 - ck) / (ks * lai)
+      s2 <- (ck - tss) / (ks * lai)
+    } else {
+      # Outside the hotspot
+      fhot <- lai * sqrt(ko * ks)
+      # Integrate 2 layers by exponential simpson method in 20 steps
+      # the steps are arranged according to equal partitioning
+      # of the derivative of the joint probability function
+      x1 <- y1 <- 0.0
+      f1 <- 1.0
+      ca <- exp(alf * (fb - 1.0))
+      fint <- (1.0 - ca) * .05
+      s1 <- 0.0
+      for (istep in 1:20) {
+        if (istep < 20) {
+          x2 <- -log(1. - istep * fint) / alf
+        } else {
+          x2 <- 1. - fb
+        }
+        y2 <- -(ko + ks) * lai * x2 + fhot * (1.0 - exp(-alf * x2)) / alf
+        f2 <- exp(y2)
+        s1 <- s1 + (f2 - f1) * (x2 - x1) / (y2 - y1)
+        x1 <- x2
+        y1 <- y2
+        f1 <- f2
+      }
+      fint <- (ca - exp(-alf)) * .05
+      s2 <- 0.0
+      for (istep in 1:20) {
+        if (istep < 20) {
+          x2 <- -log(ca - istep * fint) / alf
+        } else {
+          x2 <- 1.0
+        }
+        y2 <- -(ko + ks) * lai * x2 + fhot * (1.0 - exp(-alf * x2)) / alf
+        f2 <- exp(y2)
+        s2 <- s2 + (f2 - f1) * (x2 - x1) / (y2 - y1)
+        x1 <- x2
+        y1 <- y2
+        f1 <- f2
+      }
+      tsstoo <- f1
+    }
+
+    # Calculate reflectances and transmittances
+    # Bottom layer
+    tss <- exp(-ks * lai2)
+    too <- exp(-ko * lai2)
+    sb <- sdb * rho2 + sdf * tau2
+    sf <- sdf * rho2 + sdb * tau2
+
+    vb <- dob * rho2 + dof * tau2
+    vf <- dof * rho2 + dob * tau2
+
+    w2 <- sob * rho2 + sof * tau2
+
+    sigb <- ddb * rho2 + ddf * tau2
+    sigf <- ddf * rho2 + ddb * tau2
+    att <- 1.0 - sigf
+    m2 <- (att + sigb) * (att - sigb)
+    m2[m2 < 0] <- 0
+    m <- sqrt(m2)
+    which_ncs <- which(m > 0.01)
+    which_cs <- which(m <= 0.01)
+
+    tdd <- rdd <- tsd <- rsd <- tdo <- rdo <- 0 * m
+    rsod <- 0 * m
+    if (length(which_ncs) > 0) {
+      resncs <- nonconservativescattering(m[which_ncs], lai2, att[which_ncs], sigb[which_ncs],
+                                          ks, ko, sf[which_ncs], sb[which_ncs], vf[which_ncs], vb[which_ncs], tss, too)
+      tdd[which_ncs] <- resncs$tdd
+      rdd[which_ncs] <- resncs$rdd
+      tsd[which_ncs] <- resncs$tsd
+      rsd[which_ncs] <- resncs$rsd
+      tdo[which_ncs] <- resncs$tdo
+      rdo[which_ncs] <- resncs$rdo
+      rsod[which_ncs] <- resncs$rsod
+    }
+    if (length(which_cs) > 0) {
+      rescs <- conservativescattering(m[which_cs], lai2, att[which_cs], sigb[which_cs],
+                                      ks, ko, sf[which_cs], sb[which_cs], vf[which_cs], vb[which_cs], tss, too)
+      tdd[which_cs] <- rescs$tdd
+      rdd[which_cs] <- rescs$rdd
+      tsd[which_cs] <- rescs$tsd
+      rsd[which_cs] <- rescs$rsd
+      tdo[which_cs] <- rescs$tdo
+      rdo[which_cs] <- rescs$rdo
+      rsod[which_cs] <- rescs$rsod
+    }
+
+    # Set background properties equal to those of the bottom layer on a black soil
+    rddb <- rdd
+    rsdb <- rsd
+    rdob <- rdo
+    rsodb <- rsod
+    tddb <- tdd
+    tsdb <- tsd
+    tdob <- tdo
+    toob <- too
+    tssb <- tss
+    # Top layer
+    tss <- exp(-ks * lai1)
+    too <- exp(-ko * lai1)
+
+    sb <- sdb * rho1 + sdf * tau1
+    sf <- sdf * rho1 + sdb * tau1
+
+    vb <- dob * rho1 + dof * tau1
+    vf <- dof * rho1 + dob * tau1
+
+    w1 <- sob * rho1 + sof * tau1
+
+    sigb <- ddb * rho1 + ddf * tau1
+    sigf <- ddf * rho1 + ddb * tau1
+    att <- 1.0 - sigf
+
+    m2 <- (att + sigb) * (att - sigb)
+    m2[m2 < 0] <- 0
+    m <- sqrt(m2)
+    which_ncs <- which(m > 0.01)
+    which_cs <- which(m <= 0.01)
+
+    tdd <- rdd <- tsd <- rsd <- tdo <- rdo <- 0 * m
+    rsod <- 0 * m
+    if (length(which_ncs) > 0) {
+      resncs <- nonconservativescattering(m[which_ncs], lai1, att[which_ncs], sigb[which_ncs],
+                                          ks, ko, sf[which_ncs], sb[which_ncs], vf[which_ncs], vb[which_ncs], tss, too)
+      tdd[which_ncs] <- resncs$tdd
+      rdd[which_ncs] <- resncs$rdd
+      tsd[which_ncs] <- resncs$tsd
+      rsd[which_ncs] <- resncs$rsd
+      tdo[which_ncs] <- resncs$tdo
+      rdo[which_ncs] <- resncs$rdo
+      rsod[which_ncs] <- resncs$rsod
+    }
+    if (length(which_cs) > 0) {
+      rescs <- conservativescattering(m[which_cs], lai1, att[which_cs], sigb[which_cs],
+                                      ks, ko, sf[which_cs], sb[which_cs], vf[which_cs], vb[which_cs], tss, too)
+      tdd[which_cs] <- rescs$tdd
+      rdd[which_cs] <- rescs$rdd
+      tsd[which_cs] <- rescs$tsd
+      rsd[which_cs] <- rescs$rsd
+      tdo[which_cs] <- rescs$tdo
+      rdo[which_cs] <- rescs$rdo
+      rsod[which_cs] <- rescs$rsod
+    }
+
+    # combine with bottom layer reflectances and transmittances (adding method)
+    rn <- 1.0 - rdd * rddb
+    tup <- (tss * rsdb + tsd * rddb) / rn
+    tdn <- (tsd + tss * rsdb * rdd) / rn
+    rsdt <- rsd + tup * tdd
+    rdot <- rdo + tdd * (rddb * tdo + rdob * too) / rn
+    rsodt <- rsod + (tss * rsodb + tdn * rdob) * too + tup * tdo
+
+    rsost <- (w1 * s1 + w2 * s2) * lai
+
+    rsot <- rsost + rsodt
+
+    # Diffuse reflectances at the top and the bottom are now different
+    rddt_t <- rdd + tdd * rddb * tdd / rn
+    rddt_b <- rddb + tddb * rdd * tddb / rn
+
+    # Transmittances of the combined canopy layers
+    tsst <- tss * tssb
+    toot <- too * toob
+    tsdt <- tss * tsdb + tdn * tddb
+    tdot <- tdob * too + tddb * (tdo + rdd * rdob * too) / rn
+    tddt <- tdd * tddb / rn
+
+    # Apply clumping effects to vegetation layer
+    rddcb <- cv * rddt_b
+    rddct <- cv * rddt_t
+    tddc <- 1 - cv + cv * tddt
+    rsdc <- cs * rsdt
+    tsdc <- cs * tsdt
+    rdoc <- co * rdot
+    tdoc <- co * tdot
+    tssc <- 1 - cs + cs * tsst
+    tooc <- 1 - co + co * toot
+
+    # new weight function fcdc for crown contribution (W. Verhoef,  22-05-08)
+    rsoc <- fcdc * rsot
+    tssooc <- fcd * tsstoo + fcs * toot + fod * tsst + fos
+    # Canopy absorptance for black background (W. Verhoef,  02-03-04)
+    alfas <- 1. - tssc - tsdc - rsdc
+    alfad <- 1. - tddc - rddct
+    # Add the soil background
+    rn <- 1 - rddcb * rddsoil
+    tup <- (tssc * rsdsoil + tsdc * rddsoil) / rn
+    tdn <- (tsdc + tssc * rsdsoil * rddcb) / rn
+
+    rddt <- rddct + tddc * rddsoil * tddc / rn
+    rsdt <- rsdc + tup * tddc
+    rdot <- rdoc + tddc * (rddsoil * tdoc + rdosoil * tooc) / rn
+    rsot <- rsoc + tssooc * rsosoil + tdn * rdosoil * tooc + tup * tdoc
+
+    # Effect of soil background on canopy absorptances (W. Verhoef,  02-03-04)
+    alfast <- alfas + tup * alfad
+    alfadt <- alfad * (1. + tddc * rddsoil / rn)
+  }
+  my_list <- list("rdot" = rdot, "rsot" = rsot, "rddt" = rddt, "rsdt" = rsdt,
+                  "alfast" = alfast,  "alfadt" = alfadt)
+  return(my_list)
+}
+
+
+
+#" computes non conservative scattering conditions
+#" @param m numeric.
+#" @param lai numeric. Leaf Area Index
+#" @param att numeric.
+#" @param sigb numeric.
+#" @param ks numeric.
+#" @param ko numeric.
+#" @param sf numeric.
+#" @param sb numeric.
+#" @param vf numeric.
+#" @param vb numeric.
+#" @param tss numeric.
+#" @param too numeric.
+#"
+#" @return list. tdd,  rdd,  tsd,  rsd,  tdo,  rdo,  rsod
+#"
+#" @export
+nonconservativescattering <- function(m, lai, att, sigb, ks, ko, sf, sb, vf, vb, tss, too) {
+
+  e1 <- exp(-m * lai)
+  e2 <- e1 * e1
+  rinf <- (att - m) / sigb
+  rinf2 <- rinf * rinf
+  re <- rinf * e1
+  denom <- 1. - rinf2 * e2
+
+  j1ks <- jfunc1(ks, m, lai)
+  j2ks <- jfunc2(ks, m, lai)
+  j1ko <- jfunc1(ko, m, lai)
+  j2ko <- jfunc2(ko, m, lai)
+
+  ps <- (sf + sb * rinf) * j1ks
+  qs <- (sf * rinf + sb) * j2ks
+  pv <- (vf + vb * rinf) * j1ko
+  qv <- (vf * rinf + vb) * j2ko
+
+  tdd <- (1. - rinf2) * e1 / denom
+  rdd <- rinf * (1. - e2) / denom
+  tsd <- (ps - re * qs) / denom
+  rsd <- (qs - re * ps) / denom
+  tdo <- (pv - re * qv) / denom
+  rdo <- (qv - re * pv) / denom
+
+  z <- jfunc2(ks, ko, lai)
+  g1 <- (z - j1ks * too) / (ko + m)
+  g2 <- (z - j1ko * tss) / (ks + m)
+
+  tv1 <- (vf * rinf + vb) * g1
+  tv2 <- (vf + vb * rinf) * g2
+
+  t1 <- tv1 * (sf + sb * rinf)
+  t2 <- tv2 * (sf * rinf + sb)
+  t3 <- (rdo * qs + tdo * ps) * rinf
+
+  # Multiple scattering contribution to bidirectional canopy reflectance
+  rsod <- (t1 + t2 - t3) / (1. - rinf2)
+  my_list <- list("tdd" = tdd,  "rdd" = rdd,  "tsd" = tsd,
+                  "rsd" = rsd,  "tdo" = tdo,  "rdo" = rdo,
+                  "rsod" = rsod)
+  return(my_list)
+}
+
+#" computes conservative scattering conditions
+#" @param m numeric.
+#" @param lai numeric. Leaf Area Index
+#" @param att numeric.
+#" @param sigb numeric.
+#" @param ks numeric.
+#" @param ko numeric.
+#" @param sf numeric.
+#" @param sb numeric.
+#" @param vf numeric.
+#" @param vb numeric.
+#" @param tss numeric.
+#" @param too numeric.
+#"
+#" @return list. tdd,  rdd,  tsd,  rsd,  tdo,  rdo,  rsod
+#"
+#" @export
+conservativescattering <- function(m, lai, att, sigb, ks, ko, sf, sb, vf, vb, tss, too) {
+
+  # near or complete conservative scattering
+  j4 <- jfunc4(m, lai)
+  amsig <- att - sigb
+  apsig <- att + sigb
+  rtp <- (1 - amsig * j4) / (1 + amsig * j4)
+  rtm <- (-1 + apsig * j4) / (1 + apsig * j4)
+  rdd <- 0.5 * (rtp + rtm)
+  tdd <- 0.5 * (rtp - rtm)
+
+  dns <- ks * ks - m * m
+  dno <- ko * ko - m * m
+  cks <- (sb * (ks - att) - sf * sigb) / dns
+  cko <- (vb * (ko - att) - vf * sigb) / dno
+  dks <- (-sf * (ks + att) - sb * sigb) / dns
+  dko <- (-vf * (ko + att) - vb * sigb) / dno
+  ho <- (sf * cko + sb * dko) / (ko + ks)
+
+  rsd <- cks * (1 - tss * tdd) - dks * rdd
+  rdo <- cko * (1 - too * tdd) - dko * rdd
+  tsd <- dks * (tss - tdd) - cks * tss * rdd
+  tdo <- dko * (too - tdd) - cko * too * rdd
+  # Multiple scattering contribution to bidirectional canopy reflectance
+  rsod <- ho * (1 - tss * too) - cko * tsd * too - dko * rsd
+
+  my_list <- list("tdd" = tdd,  "rdd" = rdd,  "tsd" = tsd,
+                  "rsd" = rsd,  "tdo" = tdo,  "rdo" = rdo,
+                  "rsod" = rsod)
+  return(my_list)
+}
+
+
+
+
+
+
+#" computes the leaf angle distribution function value (freq)
+#"
+#" Ellipsoidal distribution function characterised by the average leaf
+#" inclination angle in degree (ala)
+#" Campbell 1986
+#" @param ala average leaf angle
+#" @return foliar_distrib list. lidf and litab
+#" @export
+campbell  <- function(ala) {
+
+  tx1 <- c(10., 20., 30., 40., 50., 60., 70., 80., 82., 84., 86., 88., 90.)
+  tx2 <- c(0., 10., 20., 30., 40., 50., 60., 70., 80., 82., 84., 86., 88.)
+  litab <- (tx2 + tx1) / 2
+  n <- length(litab)
+  tl1 <- tx1 * (pi / 180)
+  tl2 <- tx2 * (pi / 180)
+  excent <- exp(-1.6184e-5 * ala**3 + 2.1145e-3 * ala**2 - 1.2390e-1 * ala + 3.2491)
+  sum0 <- 0
+
+  freq <- c()
+  for (i in 1:n) {
+    x1 <- excent / (sqrt(1. + excent**2. * tan(tl1[i])**2))
+    x2 <- excent / (sqrt(1. + excent**2. * tan(tl2[i])**2))
+    if (excent == 1) {
+      freq[i] <- abs(cos(tl1[i]) - cos(tl2[i]))
+    } else {
+      alpha <- excent / sqrt(abs(1 - excent**2))
+      alpha2 <- alpha**2
+      x12 <- x1**2
+      x22 <- x2**2
+      alpx1 <- 0 * alpha2
+      alpx2 <- 0 * alpha2
+      almx1 <- 0 * alpha2
+      almx2 <- 0 * alpha2
+      if (excent > 1) {
+        alpx1 <- sqrt(alpha2[excent > 1] + x12[excent > 1])
+        alpx2[excent > 1] <- sqrt(alpha2[excent > 1] + x22[excent > 1])
+        dum <- x1 * alpx1 + alpha2 * log(x1 + alpx1)
+        freq[i] <- abs(dum - (x2 * alpx2 + alpha2 * log(x2 + alpx2)))
+      } else {
+        almx1 <- sqrt(alpha2 - x12)
+        almx2 <- sqrt(alpha2 - x22)
+        dum <- x1 * almx1 + alpha2 * asin(x1 / alpha)
+        freq[i] <- abs(dum - (x2 * almx2 + alpha2 * asin(x2 / alpha)))
+      }
+    }
+  }
+  sum0 <- sum(freq)
+  freq0 <- freq / sum0
+  foliar_distrib <- list("lidf" = freq0, "litab" = litab)
+  return(foliar_distrib)
+}
+
+#" computes the leaf angle distribution function value (freq)
+#"
+#" Using the original bimodal distribution function initially proposed in SAIL
+#"  references
+#"  ----------
+#"  (Verhoef1998) Verhoef,  Wout. Theory of radiative transfer models applied
+#"  in optical remote sensing of vegetation canopies.
+#"  nationaal Lucht en Ruimtevaartlaboratorium,  1998.
+#"  http: /  / library.wur.nl / WebQuery / clc / 945481.
+#" @param a controls the average leaf slope
+#" @param b controls the distribution"s bimodality
+#" LIDF type 		  a 		b
+#" Planophile 	  1		  0
+#" Erectophile    -1	 	0
+#" Plagiophile 	  0		  -1
+#" Extremophile 	0		  1
+#" Spherical 	    -0.35 -0.15
+#" Uniform        0     0
+#" requirement: ||lidfa||  +  ||lidfb|| < 1
+#"
+#" @return foliar_distrib list. lidf and litab
+#" @export
+dladgen  <- function(a, b) {
+  litab <- c(5., 15., 25., 35., 45., 55., 65., 75., 81., 83., 85., 87., 89.)
+  freq <- c()
+  for (i1 in 1:8) {
+    t <- i1 * 10
+    freq[i1] <- dcum(a, b, t)
+  }
+  for (i2 in 9:12) {
+    t <- 80. + (i2 - 8) * 2.
+    freq[i2] <- dcum(a, b, t)
+  }
+  freq[13] <- 1
+  for (i in 13:2) {
+    freq[i] <- freq[i] - freq[i - 1]
+  }
+  foliar_distrib <- list("lidf" = freq, "litab" = litab)
+  return(foliar_distrib)
+}
+
+#" dcum function
+#" @param a numeric. controls the average leaf slope
+#" @param b numeric. controls the distribution"s bimodality
+#" @param t numeric. angle
+#" @return f
+#" @export
+dcum <- function(a, b, t) {
+  rd <- pi / 180
+  if (a >= 1) {
+    f <- 1 - cos(rd * t)
+  } else {
+    eps <- 1e-8
+    delx <- 1
+    x <- 2 * rd * t
+    p <- x
+    while (delx  >= eps) {
+      y <- a * sin(x) + .5 * b * sin(2. * x)
+      dx <- .5 * (y - x + p)
+      x <- x + dx
+      delx <- abs(dx)
+    }
+    f <- (2. * y + p) / pi
+  }
+  return(f)
+}
+
+#" J1 function with avoidance of singularity problem
+#"
+#" @param k numeric. Extinction coefficient for direct (solar or observer) flux
+#" @param l numeric.
+#" @param t numeric. Leaf Area Index
+#" @return jout numeric.
+#" @export
+jfunc1 <- function(k, l, t) {
+  # J1 function with avoidance of singularity problem
+  del <- (k - l) * t
+  jout <- 0 * l
+  jout[which(abs(del) > 1e-3)] <- (exp(-l[which(abs(del) > 1e-3)] * t) - exp(-k * t)) / (k - l[which(abs(del) > 1e-3)])
+  jout[which(abs(del) <= 1e-3)] <- 0.5 * t * (exp(-k * t) + exp(-l[which(abs(del) <= 1e-3)] * t)) * (1 - del[which(abs(del) <= 1e-3)] * del[which(abs(del) <= 1e-3)] / 12)
+  return(jout)
+}
+
+#" J2 function with avoidance of singularity problem
+#"
+#" @param k numeric. Extinction coefficient for direct (solar or observer) flux
+#" @param l numeric.
+#" @param t numeric. Leaf Area Index
+#" @return jout numeric.
+#" @export
+jfunc2 <- function(k, l, t) {
+  #	J2 function
+  jout <- (1. - exp(-(k + l) * t)) / (k + l)
+  return(jout)
+}
+
+#" J3 function with avoidance of singularity problem
+#"
+#" @param k numeric. Extinction coefficient for direct (solar or observer) flux
+#" @param l numeric.
+#" @param t numeric. Leaf Area Index
+#" @return jout numeric.
+#" @export
+jfunc3 <- function(k, l, t) {
+  out <- (1. - exp(-(k + l) * t)) / (k + l)
+  return(out)
+}
+
+
+#" j4 function for treating (near) conservative scattering
+#"
+#" @param m numeric. Extinction coefficient for direct (solar or observer) flux
+#" @param t numeric. Leaf Area Index
+#" @return jout numeric.
+#" @export
+jfunc4 <- function(m, t) {
+
+  del <- m * t
+  out <- 0 * del
+  out[del > 1e-3] <- (1 - exp(-del)) / (m * (1 + exp(-del)))
+  out[del <= 1e-3] <- 0.5 * t * (1. - del * del / 12.)
+  return(out)
+}
+
+
+#" compute volume scattering functions and interception coefficients
+#" for given solar zenith,  viewing zenith,  azimuth and leaf inclination angle.
+#"
+#" @param tts numeric. solar zenith
+#" @param tto numeric. viewing zenith
+#" @param psi numeric. azimuth
+#" @param ttl numeric. leaf inclination angle
+#" @return res list. includes chi_s,  chi_o,  frho,  ftau
+#" @export
+volscatt  <- function(tts, tto, psi, ttl) {
+  #********************************************************************************
+  #*	chi_s	= interception functions
+  #*	chi_o	= interception functions
+  #*	frho	= function to be multiplied by leaf reflectance rho
+  #*	ftau	= functions to be multiplied by leaf transmittance tau
+  #********************************************************************************
+  #	Wout Verhoef,  april 2001,  for CROMA
+
+  rd <- pi / 180
+  costs <- cos(rd * tts)
+  costo <- cos(rd * tto)
+  sints <- sin(rd * tts)
+  sinto <- sin(rd * tto)
+  cospsi <- cos(rd * psi)
+  psir <- rd * psi
+  costl <- cos(rd * ttl)
+  sintl <- sin(rd * ttl)
+  cs <- costl * costs
+  co <- costl * costo
+  ss <- sintl * sints
+  so <- sintl * sinto
+
+  #c ..............................................................................
+  #c     betas -bts- and betao -bto- computation
+  #c     Transition angles (beta) for solar (betas) and view (betao) directions
+  #c     if thetav + thetal > pi / 2,  bottom side of the leaves is observed for leaf azimut
+  #c     interval betao + phi<leaf azimut<2pi-betao + phi.
+  #c     if thetav + thetal<pi / 2,  top side of the leaves is always observed,  betao=pi
+  #c     same consideration for solar direction to compute betas
+  #c ..............................................................................
+
+  cosbts <- 5
+  if (abs(ss) > 1e-6) {
+    cosbts <- -cs / ss
+  }
+  cosbto <- 5
+  if (abs(so) > 1e-6) {
+    cosbto <- -co / so
+  }
+
+  if (abs(cosbts) < 1) {
+    bts <- acos(cosbts)
+    ds <- ss
+  } else {
+    bts <- pi
+    ds <- cs
+  }
+  chi_s <- 2. / pi * ((bts - pi * .5) * cs + sin(bts) * ss)
+  if (abs(cosbto) < 1) {
+    bto <- acos(cosbto)
+    doo <- so
+  } else if (tto < 90) {
+    bto <- pi
+    doo <- co
+  } else {
+    bto <- 0
+    doo <- -co
+  }
+  chi_o <- 2. / pi * ((bto - pi * .5) * co + sin(bto) * so)
+
+  #c ..............................................................................
+  #c   computation of auxiliary azimut angles bt1,  bt2,  bt3 used
+  #c   for the computation of the bidirectional scattering coefficient w
+  #c .............................................................................
+
+  btran1 <- abs(bts - bto)
+  btran2 <- pi - abs(bts + bto - pi)
+
+  if (psir <= btran1) {
+    bt1 <- psir
+    bt2 <- btran1
+    bt3 <- btran2
+  } else {
+    bt1 <- btran1
+    if (psir <= btran2) {
+      bt2 <- psir
+      bt3 <- btran2
+    } else {
+      bt2 <- btran2
+      bt3 <- psir
+    }
+  }
+  t1 <- 2. * cs * co + ss * so * cospsi
+  t2 <- 0
+  if (bt2 > 0) {
+    t2 <- sin(bt2) * (2. * ds * doo + ss * so * cos(bt1) * cos(bt3))
+  }
+
+  denom <- 2. * pi * pi
+  frho <- ((pi - bt2) * t1 + t2) / denom
+  ftau <- (-bt2 * t1 + t2) / denom
+
+  if (frho < 0) {
+    frho <- 0
+  }
+  if (ftau < 0) {
+    ftau <- 0
+  }
+  res <- list("chi_s" = chi_s, "chi_o" = chi_o, "frho" = frho, "ftau" = ftau)
+  return(res)
+}