# Import modules
import numpy as np
20 Lambda functions
Lambda functions in Python offer an alternative way to create concise, one-line expressions for specific tasks, eliminating the need for a separate named function using the def
keyword. They are characterized by their simplicity and ability to return a value directly without a return
statement, making them perfect for quick, in-line operations like applying formulas in optimization routines or sorting and filtering data. Continuing with the analogy between regular functions and tools in a toolbox, think of lambda functions as the equivalent of using a kitchen knife or a coin in your pocket for quickly tightening a screw.
Syntax
lambda arguments: expression
Let’s learn about Lambda functions by coding a few examples. We will start by importing the Numpy module, which we will need for some operations.
Example 1: Convert degrees Fahrenheit to Celsius
Consider a scenario where you need to convert temperatures from degrees Fahrenheit to degrees Celsius frequently. Instead of repeatedly typing the conversion formula, you can encapsulate the expression in a lambda function for easy reuse. This approach not only avoids code repetition, but also reduces the risk of errors, as you write the formula just once and then call the lambda function by its name whenever needed.
C = \frac{5}{9}(F-32)
where F is temperature in degrees Fahrenheit and C is the resulting temperature in degrees Celsius.
# Define the lambda function (note the bold green reserved word)
= lambda F: 5/9 * (F-32) fahrenheit_to_Celsius
# Call the function
= 212 # temperature in degrees Fahrenheit
F = fahrenheit_to_Celsius(212)
C
print(f"A temperature of {F:.1f} °F is equivalent to {C:.1f} °C")
A temperature of 212.0 °F is equivalent to 100.0 °C
Breakdown of Lambda function components
Similar to what we did with regular functions, let’s breakdown the components of a lambda function.
Defining the Lambda function:
= lambda F: 5/9 * (F-32) fahrenheit_to_Celsius
This line defines a lambda function named
fahrenheit_to_Celsius
.Lambda keyword:
lambda
: This is the keyword that signifies the start of a lambda function in Python. It’s followed by the parameters and the expression that makes up the function.
Parameter:
F
: This represents the parameter of the lambda function. In this case,F
is the input temperature in degrees Fahrenheit that you want to convert to Celsius.
Function expression:
5/9*(F-32)
: This is the expression that gets executed when the lambda function is called. It’s the formula for converting degrees Fahrenheit to Celsius.
Note that, other than a simple line comment, Lambda
functions offer very limited possibilities to provide associated documentation for the code, inputs, and outputs. If you need to a multi-line function or even a single-line function with detailed documentation, then a regular Python function is the way to go.
Example 2: Estimate atmospheric pressure from altitude
Estimating atmospheric pressure from altitude (learn more about the topic here) is a classic problem in environmental science and meteorology, and using Python functions is an excellent tool for solving it.
P = 101.3 \; exp\Bigg(\frac{-h}{8400} \Bigg)
where P is atmospheric pressure in kPa and h is altitude above sea level in meters. The coefficient 8400 is the result of aggregating the values for the gravitational acceleration, the molar mass of dry air, the universal gas constant, and sea level standard temperature; and converting from Pa to kPa.
# Define lambda function
= lambda A: 101.3 * np.exp(-A/8400) # atm pressure in kPa estimate_atm_pressure
# Compute atmospheric pressure for Kansas City, KS
= "Kansas City, KS"
city = 280 # meters a.s.l.
h = estimate_atm_pressure(h)
P
print(f"Pressure in {city} at an elevation of {h} m is {P:.1f} kPa")
Pressure in Kansas City, KS at an elevation of 280 m is 98.0 kPa
# Compute atmospheric pressure for Denver, CO
= "Denver, CO"
city = 1600 # meters a.s.l.
h = estimate_atm_pressure(h)
P
print(f"Pressure in {city} at an elevation of {h} m is {P:.1f} kPa.")
Pressure in Denver, CO at an elevation of 1600 m is 83.7 kPa.
Example 3: Volume of tree trunk
In the fields of forestry and ecology, trunk volume is a key metric for assessing and monitoring tree size. While tree trunks can have complex shapes, their general resemblance to cones allows for reasonably accurate volume estimations using basic measurements like trunk diameter and height. You can learn more about measuring tree volumes here. To calculate trunk volume, we can use a simplified formula:
V = \frac{\pi \; h \; (D_1^2 + D_1^2 + D_1 D_2)}{12}
where D_1, D_2 are the diameters of the top and bottom circular cross-sections of the tree.
Let’s implement this formula using a Lambda function and then I propose computing the approximate volume of a Giant Sequoia. The General Sherman, located in the Sequoia National Park in California, is the largest single-stem living tree on Earth with an approximate hight of 84 m and a diameter at breast height of about 7.7 m. This example for computing tree volumes illustrates the practical application of programming in environmental science.
= lambda d1, d2, h: (np.pi * h * (d1**2 + d2**2 + d1*d2))/12
compute_trunk_volume
# Approximate tree dimensions (these values result
= 7.7 # meters
diameter_base = 1 # meters (I assumed this value for the top of the stem)
diamter_top = 84 # meters
height
# Compute volume. The results is remarkably similar tot he reported 1,487 m^3
= compute_trunk_volume(diameter_base, diamter_top, height) # m^3
trunk_volume
print(f"The trunk volume of a Giant Sequoia is {trunk_volume:.0f} cubic meters")
# Find relative volume compared to an Olympic-size (50m x 25m x 2m) swimming pool.
= 50 * 25 * 2
pool_volume = trunk_volume/pool_volume*100 # Relative volume trunk/pool
rel_volume
# Ratio of volumes
print(f"Trunk volume is {rel_volume:.1f}% the size of an Olympic-size pool")
The trunk volume of a Giant Sequoia is 1495 cubic meters
Trunk volume is 59.8% the size of an Olympic-size pool
Example 4: Calculate the sodium adsorption ratio (SAR).
The Sodium Adsorption Ratio (SAR) is a water quality indicator for determining the suitability for agricultural irrigation. In high concetrations, sodium has a negative impact on plant growth and disperses soil colloids, which has a detrimental impact on soil aggregation, soil structure and infiltration. It uses the concentrations of sodium, calcium, and magnesium ions measured in milliequivalents per liter (meq/L) to calculate the SAR value based on the formula:
SAR = \frac{\text{Na}^+}{\sqrt{\frac{\text{Ca}^{2+} + \text{Mg}^{2+}}{2}}}
# Define lambda function
= lambda na,ca,mg: na / ((ca+mg) / 2)**0.5 calculate_sar
# Determine SAR value for a water sample with the following ion concentrations
= 10 # Sodium ion concentration in meq/L
na = 5 # Calcium ion concentration in meq/L
ca = 2 # Magnesium ion concentration in meq/L
mg
= calculate_sar(na, ca, mg)
sar_value print(f"Sodium Adsorption Ratio (SAR) is: {sar_value:.1f}")
# SAR values <5 are typically excellent for irrigation,
# while SAR values >15 are typically unsuitable for irrigation of most crops.
Sodium Adsorption Ratio (SAR) is: 5.3
Example 5: Compute soil porosity
Soil porosity refers to the percentage of the soil’s volume that is occupied by voids that can be occupied by air and water. Soil porosity is a soil physical property that conditions the soil’s ability to hold and transmit water, heat, and air, and is essential for root growth and microbial activity. For a given textural class, soils with lower porosity values tend to be compacted compared to soils with greater porosity values.
Porosity (f, dimensionless) is defined as the volume of voids over the total volume of soil, and it can be approximated using bulk density (\rho_b) and particle density (\rho_s, often assumed to have a value of 2.65 g cm^{-3} for mineral soils):
f = \Bigg( 1 - \frac{\rho_b}{\rho_s} \Bigg)
# Define lambda function
# bd is the bulk density
= lambda bd: 1 - (bd/2.65)
calculate_porosity
# Compute soil porosity
= 1.35 # Bulk density in g/cm^3
bd = calculate_porosity(bd)
f
# Print result
print(f'The porosity of a soil with a bulk density of {bd:.2f} g/cm^3 is {f*100:.1f} %')
The porosity of a soil with a bulk density of 1.35 g/cm^3 is 49.1 %
Example 6: Estimate osmotic potential
In soil science, osmotic potential (\psi_o, kPa) represents the measure of the soil’s capacity to retain water due to the presence of dissolved solutes. Osmotic potential directly influences soil moisture dynamics and plant water uptake, impacting crop productivity and ecosystem health. For instance, soils with lower osmotic potential (i.e., more negative values), typically resulting from a higher concentration of solutes, create a greater challenge for plants to extract water, potentially impacting their growth and survival. The osmotic potential of the soil solution can be approximated based on measurements of the bulk electrical conductivity of a saturation paste extract and volumetric water content using the following formula:
\psi_{o} = 36 \ EC_b \ \frac{\theta_s}{\theta}
where EC_b is the bulk electrical conductivity of the saturation paste extract in dS m^{-1}, \theta_s is the voluemtric water content at saturation in cm^3 cm^{-3}, and \theta is the volumetric water content cm^3 cm^{-3}. The term 36 \ EC_b represents the osmotic potential at saturation \psi_{os}
# Define lambda function
= lambda theta,theta_s,EC: 36 * EC * theta_s/theta
calculate_osmotic
# Compute osmotic potential
= 0.45 # cm^3/cm^3
theta_s = 0.15 # cm^3/cm^3
theta = 1 # dS/m
EC
= calculate_osmotic(theta,theta_s,EC)
psi_o print(f"Osmotic potential is {psi_o:.1f} kPa")
Osmotic potential is 108.0 kPa
Practice
Implement Stoke’s Law as a lambda function. Then, call the function to estimate the terminal velocity of a 1 mm diamter sand particle in water and a 1 mm raindrop in air.
Implement a quadratic polynomial describing a yield-nitrogen response curve. Here is one model that you can try, but there are many empirical yield-N relationships in the literature: y = -0.0034 x^2 + 0.9613 x + 115.6