Dandelion Spread Analysis and Impact Factors for Other Invasive Species

15 minute read

Published:

It is a mathematical modeling problem from MCM 2023 Problem A. The problem is as follows:

Problem Background

Taraxacum officinale, commonly referred to as the dandelion, is a plant native to Eurasia that can now be found worldwide. This plant is easily identifiable by its bright yellow flowers and its distinctive “puffball” seed head. Each seed from this head is attached to a parachute-like structure, known as a ‘pappus’, which facilitates wind dispersal.

  1. If a single dandelion in its “puffball” stage is adjacent to an open one-hectare plot of land, create a mathematical model to predict the spread of dandelions over the course of 1, 2, 3, 6, and 12 months. Make sure your model incorporates the effects of various climatic conditions, such as temperate, arid, and tropical climates, on dandelion growth.
  2. Using your model, determine the impact of dandelion spread on the growth of other invasive species in the area. Consider the effects of competition for resources, such as sunlight, water, and nutrients, on the growth of these species.

Requirements

Formulate a mathematical model capable of determining an ‘impact factor’ for invasive species. This model should integrate multiple variables, including the plant’s characteristics and the nature and extent of the harm it inflicts on its environment.

  • Test your model by using it to compute an impact factor for dandelions.
  • Apply your model to determine the impact factor for two other plant species of your choice that are often considered invasive. Make sure to identify the region for whom each of the plants you choose are invasive.

Analysis

First Task: Spread of Dandelions

First of all, we need to understand the spread of dandelions. The spread of dandelions is mainly due to the wind. The seeds of dandelions are attached to a parachute-like structure, known as a ‘pappus’, which facilitates wind dispersal. The seeds are carried by the wind and are deposited in the open land. The seeds germinate and grow into dandelions. The growth of dandelions is affected by various climatic conditions, such as temperate, arid, and tropical climates. The growth of dandelions is also affected by competition for resources, such as sunlight, water, and nutrients.

But of course, we can consider first a simple model where we think of the population of dandelions as a function of time. In this case, we can use the logistic growth model. The logistic growth model is a simple model that describes the growth of a population over time. The model is based on the assumption that the growth rate of the population is proportional to the size of the population, but that the growth rate decreases as the population approaches a maximum size. The logistic growth model is given by the equation: \(\frac{dP}{dt} = rP(1 - \frac{P}{K})\)

  • $P$ is the population of dandelions
  • $t$ is time
  • $r$ is the growth rate of the population
  • $K$ is the carrying capacity of the environment
  • $\frac{dP}{dt}$ is the rate of change of the population with respect to time

Based on the established model, we can now consider other factors:

  • Base Spread Probability: The probability of a dandelion seed being deposited in the open land.
  • Climate: In here, we consider only three types of climate: temperate, arid, and tropical. We can consider the growth rate of dandelions in each of these climates.
  • Wind: The wind speed and direction can affect the spread of dandelions. We can consider the wind speed and direction in the model.

Second Task: Impact Factor for Invasive Species

To determine the impact factor for invasive species, we develop a more appropriate and custom model for the second task, which involves creating an impact factor model for invasive species. Let’s create a more comprehensive and flexible model that can be applied to various invasive plant species, including dandelions. Following is a breakdown of the key components of the model:

  • Multiple Factors: The model considers seven key factors that contribute to a species’ invasiveness and impact:
    • Growth Rate
    • Reproductive Capacity
    • Dispersal Ability
    • Competitive Ability
    • Environmental Tolerance
    • Ecosystem Impact
  • Weighted Factors: Each factor has an associated weight, allowing for the prioritization of certain characteristics over others. These weights can be easily adjusted based on expert knowledge or specific contexts. For a more accurate and comprehensive assessment, one may consider additional factors or adjust the weights accordingly.
  • Probabilistic Approach: Instead of using fixed values, the model uses probability distributions for each factor. This accounts for the uncertainty and variability in biological systems.
  • Monte Carlo Simulation: The model runs multiple simulations to generate a distribution of impact factors, providing a more robust assessment of a species’ potential impact.
  • Normalized Scoring: Each factor is normalized to a $0-1$ scale, ensuring fair comparison across different characteristics.

We then consider the following invasive species:

  • Danedelions (as requested in the problem statement)
  • Kudzu: Demonstrates a high impact factor, particularly due to its rapid growth rate, high competitive ability, and significant ecosystem and economic impacts.
  • Water Hyacinth: Also shows a high impact factor, with notable reproductive capacity and ecosystem impact, reflecting its reputation as a problematic aquatic invasive species.

Solution

We will now proceed to implement the models for the spread of dandelions and the impact factor for invasive species. We will use Python for the implementation and provide detailed explanations and visualizations to illustrate the results.

Spread of Dandelions

We first import the necessary libraries

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from scipy.stats import norm, truncnorm

# Set up random seed
np.random.seed(42)

Then we define a class called ProbabilisticDandelionSpread2DWind that models the spread of dandelions in a 2D environment with wind effects. The class includes methods for initializing the environment, simulating the spread of dandelions, and visualizing the results.

class ProbabilisticDandelionSpread2DWind:
    def __init__(self, size=100, initial_dandelions=1, spread_probability=0.1, climate='temperate'):
        self.size = size
        self.climate = climate
        
        # Set spread probability based on climate
        if climate == 'temperate':
            self.spread_probability_mu, self.spread_probability_sigma = spread_probability, 0.02
        elif climate == 'arid':
            self.spread_probability_mu, self.spread_probability_sigma = spread_probability * 0.5, 0.01
        elif climate == 'tropical':
            self.spread_probability_mu, self.spread_probability_sigma = spread_probability * 1.5, 0.03
        else:
            raise ValueError("Invalid climate type")
        
        # Initialize wind parameters
        self.wind_direction_mu, self.wind_direction_kappa = 0, 2  # von Mises distribution parameters
        self.wind_strength_alpha, self.wind_strength_beta = 2, 5  # Beta distribution parameters

    def initialize_grid(self):
        grid = np.zeros((self.size, self.size), dtype=int)
        x, y = np.random.randint(0, self.size, 2)
        grid[x, y] = 1
        return grid

    def update_wind(self):
        # Update wind direction (von Mises distribution)
        self.wind_direction = np.random.vonmises(self.wind_direction_mu, self.wind_direction_kappa)
        # Update wind strength (Beta distribution)
        self.wind_strength = np.random.beta(self.wind_strength_alpha, self.wind_strength_beta)

    def spread(self, grid):
        new_grid = grid.copy()
        spread_probability = np.random.normal(self.spread_probability_mu, self.spread_probability_sigma)
        spread_probability = np.clip(spread_probability, 0, 1)  # Ensure probability is between 0 and 1
        
        for i in range(self.size):
            for j in range(self.size):
                if grid[i, j] == 1:  # If there's a dandelion
                    # Calculate wind effect
                    wind_x = int(np.round(np.cos(self.wind_direction) * self.wind_strength * 2))
                    wind_y = int(np.round(np.sin(self.wind_direction) * self.wind_strength * 2))
                    
                    # Check neighboring cells, including wind effect
                    for di in range(-2, 3):
                        for dj in range(-2, 3):
                            if di == 0 and dj == 0:
                                continue
                            ni, nj = (i + di + wind_x) % self.size, (j + dj + wind_y) % self.size
                            if grid[ni, nj] == 0:
                                # Adjust spread probability based on distance and wind
                                distance = np.sqrt(di**2 + dj**2)
                                wind_factor = 1 + self.wind_strength * (di*wind_x + dj*wind_y) / (distance * np.sqrt(wind_x**2 + wind_y**2) + 1e-6)
                                local_spread_prob = spread_probability * wind_factor / distance
                                if np.random.random() < local_spread_prob:
                                    new_grid[ni, nj] = 1
        return new_grid

    def run_simulation(self, steps, num_simulations=100):
        all_histories = []
        all_wind_histories = []
        
        for _ in range(num_simulations):
            grid = self.initialize_grid()
            history = [grid.copy()]
            wind_history = []
            
            for _ in range(steps):
                self.update_wind()
                grid = self.spread(grid)
                history.append(grid.copy())
                wind_history.append((self.wind_direction, self.wind_strength))
            
            all_histories.append(history)
            all_wind_histories.append(wind_history)
        
        return all_histories, all_wind_histories

Next, we set up the simulation, we set up the following parameters:

  • size: The size of the 2D grid
  • initial_dandelions: The number of initial dandelions
  • spread_probability: The base spread probability of dandelions
  • steps: The number of simulation steps
  • climate: The type of climate (temperate, arid, or tropical), we use temperate as the default
  • num_simulations: The number of simulations to run
# Set up the simulation
size = 100
initial_dandelions = 1
spread_probability = 0.1
steps = 30
climate = 'temperate'
num_simulations = 10

sim = ProbabilisticDandelionSpread2DWind(size, initial_dandelions, spread_probability, climate)
all_histories, all_wind_histories = sim.run_simulation(steps, num_simulations)

Since we consider the probabilistic nature in our model, we have to also calculate the statistics.

# Calculate statistics
dandelion_counts = np.array([[np.sum(grid) for grid in history] for history in all_histories])
mean_counts = np.mean(dandelion_counts, axis=0)
ci_lower = np.percentile(dandelion_counts, 2.5, axis=0)
ci_upper = np.percentile(dandelion_counts, 97.5, axis=0)

We then plot the Dandelion Population Growth over Time in Temperate Climate and Wind Effects.

# Plot results
plt.figure(figsize=(12, 6))
time = np.arange(steps + 1) / 12 # Convert months to years

plt.plot(time, mean_counts, label='Mean', color='blue')
plt.fill_between(time, ci_lower, ci_upper, alpha=0.2, color='blue', label='95% CI')

plt.title(f'Dandelion Population Growth in {climate.capitalize()} Climate with Wind Effects')
plt.xlabel('Years')
plt.ylabel('Number of Dandelions')
plt.legend()
plt.grid(True)
plt.show()

We then have the figure as follows for the Dandelion Population Growth in Temperate Climate with Wind Effects. We have also depicted the 95% confidence interval.

Dandelion Spread

Afterwards, we print the statistics for the Dandelion Population Growth.

# Print final statistics
print(f"Final dandelion count:")
print(f"  Mean: {mean_counts[-1]:.0f}")
print(f"  95% CI: ({ci_lower[-1]:.0f}, {ci_upper[-1]:.0f})")
print(f"  Percentage of area covered (mean): {mean_counts[-1] / (size * size) * 100:.2f}%")

Followings are the statistics for the Dandelion Population Growth.

Final dandelion count:
  Mean: 2856
  95% CI: (2399, 3122)
  Percentage of area covered (mean): 28.56%

Finally, we visualize the spread of dandelions over time using an animation.

# Visualize a single simulation run
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 7))
ax1.set_title(f'Sample Dandelion Spread in {climate.capitalize()} Climate')
ax2.set_title('Wind Direction and Strength')

history = all_histories[0]  # Take the first simulation for visualization
wind_history = all_wind_histories[0]

im = ax1.imshow(history[0], cmap='YlGn', interpolation='nearest',vmin=0, vmax=1)
im_2 = ax2.imshow(history[0], cmap='YlGn', interpolation='nearest',vmin=0, vmax=1)
quiver = ax2.quiver(0, 0, 0, 0)
ax2.set_xlim(-0.5, 1.5)
ax2.set_ylim(-0.5, 1.5)
text = ax1.text(0.02, 0.95, '', transform=ax1.transAxes, color='white')

# Update function for animation
def update(frame):
    im.set_array(history[frame])
    wind_dir, wind_str = wind_history[frame]
    quiver.set_offsets([0, 0])
    quiver.set_UVC(np.cos(wind_dir) * wind_str, np.sin(wind_dir) * wind_str)
    text.set_text(f'Year: {frame // 12 + 1}, Month: {frame % 12 + 1}')
    text.set_color('red' if frame < 30 else 'black')
    return im, quiver, text
# Create animation with slow frame rate
anim = FuncAnimation(fig, update, frames=len(history) - 1, interval=200, blit=False)

# Save the animation as a gif
anim.save('dandelion_spread_animation.gif', writer='pillow', fps=5)

print("Animation saved as 'dandelion_spread_animation.gif'")

# Close the figure to free up memory
plt.close(fig)

The animation is saved as a gif file named dandelion_spread_animation.gif. The animation shows the spread of dandelions over time in a 2D grid, with wind direction and strength displayed in the second subplot. We demonstrate it as follows:

Dandelion Spread Animation

Impact Factor for Invasive Species

We define the class InvasiveSpeciesImpactModel that models the impact factor for invasive species based on multiple factors. The class includes methods for calculating the impact factor for a given species and visualizing the results.

class InvasiveSpeciesImpactModel:
    def __init__(self):
        self.factors = {
            'growth_rate': {'weight': 0.15, 'min': 0, 'max': 10},
            'reproductive_capacity': {'weight': 0.15, 'min': 0, 'max': 10},
            'dispersal_ability': {'weight': 0.15, 'min': 0, 'max': 10},
            'competitive_ability': {'weight': 0.1, 'min': 0, 'max': 10},
            'environmental_tolerance': {'weight': 0.1, 'min': 0, 'max': 10},
            'ecosystem_impact': {'weight': 0.2, 'min': 0, 'max': 10},
            'economic_impact': {'weight': 0.15, 'min': 0, 'max': 10}
        }
        
    def get_truncated_normal(self, mean, sd, low, high):
        return truncnorm((low - mean) / sd, (high - mean) / sd, loc=mean, scale=sd)
    
    def calculate_impact_factor(self, species_data, num_simulations=10000):
        impact_factors = []
        
        for _ in range(num_simulations):
            impact = 0
            for factor, data in self.factors.items():
                if isinstance(species_data[factor], tuple):  # If it's a distribution
                    mean, sd = species_data[factor]
                    value = self.get_truncated_normal(mean, sd, data['min'], data['max']).rvs()
                else:  # If it's a single value
                    value = species_data[factor]
                
                normalized_value = (value - data['min']) / (data['max'] - data['min'])
                impact += normalized_value * data['weight']
            
            impact_factors.append(impact)
        
        return np.mean(impact_factors), np.std(impact_factors)
    
    def plot_impact_distribution(self, species_name, impact_factors):
        plt.figure(figsize=(10, 6))
        plt.hist(impact_factors, bins=50, density=True, alpha=0.7, color='skyblue')
        plt.title(f'Impact Factor Distribution for {species_name}')
        plt.xlabel('Impact Factor')
        plt.ylabel('Density')
        plt.grid(True, alpha=0.3)
        plt.show()

We then initialize the InvasiveSpeciesImpactModel.

# Initialize the model
model = InvasiveSpeciesImpactModel()

We define the data for the three invasive species: dandelions, kudzu, and water hyacinth. We provide the data for each species based on the seven key factors.

# Define species data
species_data = {
    'Dandelion': {
        'growth_rate': (7, 1),  # mean and standard deviation
        'reproductive_capacity': (8, 1),
        'dispersal_ability': (9, 0.5),
        'competitive_ability': (6, 1),
        'environmental_tolerance': (8, 1),
        'ecosystem_impact': (5, 1),
        'economic_impact': (4, 1)
    },
    'Kudzu': {
        'growth_rate': (9, 0.5),
        'reproductive_capacity': (7, 1),
        'dispersal_ability': (6, 1),
        'competitive_ability': (9, 0.5),
        'environmental_tolerance': (7, 1),
        'ecosystem_impact': (9, 0.5),
        'economic_impact': (8, 1)
    },
    'Water Hyacinth': {
        'growth_rate': (8, 1),
        'reproductive_capacity': (9, 0.5),
        'dispersal_ability': (7, 1),
        'competitive_ability': (8, 1),
        'environmental_tolerance': (6, 1),
        'ecosystem_impact': (9, 0.5),
        'economic_impact': (8, 1)
    }
}

We finally calculate the impact factor for each species and plot the impact factor distribution. We set the number of simulations to 1000 for each species. For a better computation, we can increase the number of simulations. However, the current number of simulations is sufficient for demonstration purposes.

# Calculate and plot impact factors for each species
for species_name, data in species_data.items():
    mean_impact, std_impact = model.calculate_impact_factor(data)
    print(f"{species_name}:")
    print(f"  Mean Impact Factor: {mean_impact:.4f}")
    print(f"  Standard Deviation: {std_impact:.4f}")
    print(f"  95% Confidence Interval: ({mean_impact - 1.96*std_impact:.4f}, {mean_impact + 1.96*std_impact:.4f})")
    print()
    
    # Generate impact factors for plotting
    impact_factors = [model.calculate_impact_factor(data, num_simulations=1)[0] for _ in range(1000)]
    model.plot_impact_distribution(species_name, impact_factors)

We then have the following results for the impact factors of the three invasive species: dandelions, kudzu, and water hyacinth.

Dandelion:

Dandelion:
  Mean Impact Factor: 0.6581
  Standard Deviation: 0.0361
  95% Confidence Interval: (0.5874, 0.7288)

The impact factor distribution for dandelions is shown below: Dandelion Impact Distribution

Kudzu:

Kudzu:
  Mean Impact Factor: 0.7877
  Standard Deviation: 0.0302
  95% Confidence Interval: (0.7284, 0.8470)

The impact factor distribution for kudzu is shown below: Kudzu Impact Distribution

Water Hyacinth:

Water Hyacinth:
  Mean Impact Factor: 0.7969
  Standard Deviation: 0.0303
  95% Confidence Interval: (0.7374, 0.8563)

The impact factor distribution for water hyacinth is shown below: Water Hyacinth Impact Distribution

Conclusion

In conclusion, we have successfully developed a mathematical model to predict the spread of dandelions over time in different climates and wind conditions. We have also created an impact factor model for invasive species based on multiple factors, including growth rate, reproductive capacity, dispersal ability, competitive ability, environmental tolerance, ecosystem impact, and economic impact. We have applied the model to calculate the impact factors for dandelions, kudzu, and water hyacinth, providing insights into the invasiveness of these species. The results demonstrate the potential impact of these invasive species on the environment and highlight the importance of effective management strategies to mitigate their negative effects.

The models presented in this analysis can be further refined and extended to incorporate additional factors and scenarios. Future research could focus on exploring the interactions between invasive species and native ecosystems, as well as developing predictive models to assess the long-term impacts of invasive species on biodiversity and ecosystem services. By combining mathematical modeling with empirical data and expert knowledge, we can enhance our understanding of invasive species dynamics and inform evidence-based management strategies to protect natural ecosystems and promote sustainable development.

Comments