Spaces:
Sleeping
Sleeping
| def initialize_parcels(parcel_map, cluster_labels): | |
| parcel_dict = {} | |
| for i in range(parcel_map.shape[0]): | |
| for j in range(parcel_map.shape[1]): | |
| cluster_id = parcel_map[i, j] | |
| land_type = cluster_labels.get(cluster_id, "Unknown") | |
| parcel_dict[(i, j)] = { | |
| "land_type": land_type, | |
| "forage": None, | |
| "health": 1.0, | |
| "degraded": False, | |
| "cattle_grazing": { | |
| "conservative": land_type == "Productive Grass", | |
| "moderate": land_type in ["Productive Grass", "Pasture/Desert"], | |
| "aggressive": land_type not in ["Water"] | |
| }, | |
| "elk_grazing": { | |
| "default": land_type in ["Riparian Sensitive Zone", "Productive Grass"] | |
| } | |
| } | |
| return parcel_dict | |
| def get_land_forage_rates(): | |
| return { | |
| 'Productive Grass': 1.0, | |
| 'Pasture/Desert': 0.4, | |
| 'Riparian Sensitive Zone': 1.2, | |
| 'Rocky Area': 0.2, | |
| 'Water': 0.0 | |
| } | |
| def assign_initial_forage(parcel_dict, land_forage_rates): | |
| for parcel in parcel_dict.values(): | |
| rate = land_forage_rates.get(parcel["land_type"], 0.0) | |
| parcel["forage"] = rate * 100 # initial AUMs | |
| import numpy as np | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| from collections import Counter | |
| from matplotlib.colors import ListedColormap | |
| import matplotlib.patches as mpatches | |
| def simulate_period(parcel_dict, grazing_strategy="moderate", cattle_stocking_rate=500, elk_pressure=300): | |
| print(f"\n🟢 Running simulation using cattle grazing strategy: **{grazing_strategy.upper()}**") | |
| # 1. Reset all forage to simulate winter die-off | |
| for parcel in parcel_dict.values(): | |
| parcel["forage"] = 0 | |
| # 2. Count eligible parcels for cattle grazing | |
| total_grazed_parcels = sum( | |
| 1 for parcel in parcel_dict.values() if parcel["cattle_grazing"][grazing_strategy] | |
| ) | |
| if total_grazed_parcels == 0: | |
| print("⚠️ No parcels match the selected grazing strategy.") | |
| return | |
| # 3. Calculate AUM pressure per parcel | |
| cattle_grazing_per_parcel = cattle_stocking_rate / total_grazed_parcels | |
| elk_grazing_per_parcel = elk_pressure / len(parcel_dict) # uniform elk pressure | |
| # 4. Simulate forage growth + grazing effects | |
| for parcel in parcel_dict.values(): | |
| if not parcel["cattle_grazing"][grazing_strategy]: | |
| continue | |
| # Forage regrowth (8-month season with weather factor) | |
| base_growth = { | |
| 'Productive Grass': 1.0, | |
| 'Pasture/Desert': 0.4, | |
| 'Riparian Sensitive Zone': 1.2, | |
| 'Rocky Area': 0.2, | |
| 'Water': 0.0 | |
| }.get(parcel["land_type"], 0.0) | |
| weather = np.random.normal(1.0, 0.2) | |
| growth = base_growth * weather * 8 | |
| parcel["forage"] = growth # no carryover between years | |
| # Total grazing pressure | |
| total_grazing = cattle_grazing_per_parcel + elk_grazing_per_parcel | |
| # Degradation or recovery | |
| if total_grazing > parcel["forage"]: | |
| parcel["degraded"] = True | |
| parcel["health"] -= 0.1 | |
| else: | |
| parcel["health"] += 0.02 | |
| # Subtract forage | |
| parcel["forage"] = max(parcel["forage"] - total_grazing, 0) | |
| def get_forage_map(parcel_dict, n_rows, n_cols): | |
| return np.array([[parcel_dict[(i, j)]["forage"] for j in range(n_cols)] for i in range(n_rows)]) | |
| def plot_forage_map(forage_map, title="Parcel Forage Levels"): | |
| plt.figure(figsize=(8, 6)) | |
| plt.imshow(forage_map, cmap='YlGn', origin='upper') | |
| plt.colorbar(label="Forage AUMs") | |
| plt.title(title) | |
| plt.axis('off') | |
| plt.tight_layout() | |
| plt.show() | |
| def run_full_simulation(parcel_map, cluster_labels, n_rows, n_cols, strategy="moderate"): | |
| parcel_dict = initialize_parcels(parcel_map, cluster_labels) | |
| land_forage_rates = get_land_forage_rates() | |
| assign_initial_forage(parcel_dict, land_forage_rates) | |
| simulate_period(parcel_dict, grazing_strategy=strategy) | |
| return parcel_dict | |