Spaces:
Sleeping
A newer version of the Gradio SDK is available: 6.15.2
Drip Irrigation Design Logic & Accuracy Guide
Architecture Overview
The design pipeline has 3 independent but sequential stages:
Input (farm boundary + crop zones + pump)
β
[1] VALVE PLACEMENT ENGINE (valve_engine.py)
β’ Decides: how many valves, where, why
β
[2] DRIP LAYOUT GENERATOR (drip_engine.py)
β’ For each valve zone: generate main + laterals
β
[3] BOM & SUMMARY (drip_engine.py)
β’ Compute costs, material counts, flow rates
β
Output (GeoJSON with valves, zones, drips, BOM)
Each stage can be improved independently. This doc explains the logic, current assumptions, and where accuracy hurts most.
Stage 1: Valve Placement (THE MOST CRITICAL STAGE)
Decision Matrix (4-layer hierarchy)
When to split the farm into multiple zones? The engine applies these rules in order, taking the maximum zone count that satisfies all constraints:
num_zones = max(
num_zones_capacity, # [1] Pump can't deliver all emitter demand at once
num_zones_crop, # [2] Different crops in different zones
num_zones_area, # [3] Area-based minimum (crop density floor)
num_zones_topo, # [4] Elevation split
)
Layer 1: Capacity Constraint
Logic:
total_emitter_flow_lph = sum(area_m2 * emitter_density * emitter_flow_lph per crop)
pump_flow_lph = HP_TO_LPH[pump_hp] # lookup table
num_zones_capacity = ceil(total_emitter_flow_lph / pump_flow_lph)
Current assumptions:
- Emitter density derived from
lateral_spacing Γ emitter_spacing(seeCROP_FLOW_PARAMSinvalve_engine.py:47-54)- Tomato: 0.5m rows, 0.3m emitter spacing β 4.17 emitters/mΒ²
- Lettuce: 0.4m rows, 0.2m spacing β 12.5 emitters/mΒ² (intensive)
- Orchard: 2.0m rows, 1.0m spacing β 0.5 emitters/mΒ² (sparse)
- Pump HP β L/h curve is linear interpolation between discrete values (
HP_TO_LPHdict)
Accuracy issues:
- Emitter density is naive: assumes rows are perpendicular to flow, which isn't always true on irregular plots.
- Pump curve is a lookup: real pumps have pressure-dependent flow; we ignore head loss over long laterals.
- No derating for pressure drop: a 200m lateral with 4.17 emitters/mΒ² may have 30%+ flow drop by the end; we ignore this.
When to improve:
- If you're seeing valve zones with highly uneven emitter counts, increase
CROP_FLOW_PARAMS[crop]["emitter_density_m2"]for intensive crops. - If the pump can't deliver enough flow, you likely underestimated density.
Layer 2: Crop Type Constraint
Logic:
num_zones_crop = len(set(z["crop"] for z in crop_zones))
Current behavior:
- Each unique crop name gets its own zone (minimum).
- Example: if you have tomato in plot_1 and lettuce in plot_2, you'll get β₯2 zones.
Accuracy issues:
- This is exact β no assumptions.
- But it forces fragmentation if you have many small plots with different crops, even if their water needs are similar.
When to improve:
- If you want to group similar crops (e.g., tomato + pepper both ~0.5m spacing), add a crop "family" system.
Layer 3: Area-Density Floor (THE MOST OPINIONATED)
Logic:
density_valves_per_ha = VALVE_DENSITY_PER_HA[primary_crop] # e.g., 6 for tomato
num_zones_area = ceil(farm_area_ha * density)
Current densities (VALVE_DENSITY_PER_HA):
"tomato": 6, # ~0.17 ha/valve = 1700 mΒ² per valve
"pepper": 6,
"lettuce": 7,
"cucumber": 4,
"orchard": 2,
"generic": 5, # β2 valves/acre, standard default
Why this matters:
- A 1-hectare tomato field gets at least 6 zones, even if the pump could handle it in 1.
- This is not capacity-driven; it's operational best practice: narrower zones β shorter laterals β less pressure drop β more uniform water.
Current assumption:
- Rule of thumb from FAO irrigation guides: 1 valve per 1500β2000 mΒ² for row crops.
- But these are empirical, not physics-based.
Accuracy issues:
- These numbers are guessed, not calibrated to your farms.
- Real farms might benefit from 3 valves/ha or 10 valves/ha depending on topography, soil, crop sensitivity.
- No feedback loop: the engine doesn't learn from actual irrigation records.
When to improve (HIGH IMPACT):
- Collect data: run 5-10 farms and measure which density gives the most uniform soil moisture or yield.
- Stratify by local conditions: clay soils may tolerate coarser zones (lower density); sandy soils need more (higher density).
- Make it configurable: add
valve_density_overrideto the API so users can tune.
Layer 4: Topography Constraint
Logic:
should_split_topo = (max_elevation_m - min_elevation_m) > ELEVATION_DELTA_THRESHOLD_M # 5m
if should_split_topo:
num_zones_required += 1 # Just adds 1 zone; not sophisticated
Current assumption:
- If elevation differs by >5m across the farm, you need separate high/low zones.
- This avoids excessive pressure imbalance (5m β 0.5 bar).
Accuracy issues:
- Very coarse: if your field has 20m elevation span, splitting into high/low is crude.
- No secondary valve placement logic: we don't intelligently place the "high zone" valve uphill.
- Ignores soil variability: even flat farms have water-retention differences.
When to improve:
- Implement a real topographic split: use Voronoi diagram based on elevation contours.
Stage 2: Drip Layout Generation (PURELY GEOMETRIC)
Main Line Selection
Logic:
edges = polygon.exterior edges (between consecutive vertices)
edge_lengths = [distance(v1, v2) for each edge]
main_idx = argmax(edge_lengths) # or argmin if main_line_edge="shortest"
main_line = edges[main_idx]
Current assumption:
- The longest edge is the best place for the main pipe (supplies all laterals perpendicular to it).
- This works well for rectangular fields; poor for irregular/triangular fields.
Accuracy issues:
- Doesn't optimize for minimal piping: placing the main along the longest edge doesn't minimize total pipe (main + laterals).
- Doesn't consider pump location: if pump is far from the longest edge, the main should be closer to the pump.
When to improve:
- Implement a "cost-optimal main placement" algorithm:
for each edge: cost = main_length + avg_lateral_length_if_main_on_this_edge best_edge = min(cost) - Result: main placement adapts to both field shape and pump location.
Lateral Generation & Clipping
Logic:
# Generate parallel lines perpendicular to main, spaced at crop-specific intervals
spacing = params["lateral_spacing_m"] # e.g., 0.5m for tomato
num_laterals = ceil(main_length / spacing)
for i in range(num_laterals):
point_on_main = main.interpolate(i * spacing)
lateral = perpendicular_line(point_on_main, direction=perp)
clipped_lateral = lateral.intersection(polygon) # Clip to field boundary
Current assumption:
- Equally-spaced laterals perpendicular to the main.
- Works perfectly for rectangles, OK for gentle polygons, poor for irregular shapes (some laterals clip to very short lengths, wasting water).
Accuracy issues:
- Uneven emitter distribution: clipping can leave some laterals very short (e.g., 10m) while others are 100m, causing huge flow imbalance.
- Dead zones: if the field is very irregular (e.g., L-shaped), the corners near the short clipped laterals will be under-irrigated.
When to improve:
- Adaptive lateral spacing: instead of fixed spacing, space laterals so each has ~similar length (within 20% variation).
- Lateral grouping: group short laterals and feed them from a single branch main, not from the primary main.
- Visualization: highlight in the output which laterals are "problematic" (too short, too long).
Headland Buffer
Logic:
buffered_polygon = polygon.buffer(-headland_buffer_m)
Current assumption:
- Shrink the field inward by a fixed distance.
- Avoids putting drip on field edges (where machinery turns).
Accuracy issues:
- All headland is the same: real farms have varied headland: one side might be a road (no drip), other side a boundary (need drip).
- No input for headland shape: assume rectangular; doesn't account for irregular field edges.
When to improve:
- Accept a per-edge headland map:
{ "north": 1.5, "east": 1.0, "south": 2.0, "west": 0.5 }.
Stage 3: BOM & Summary (COST ESTIMATION)
Current Cost Model
Logic:
main_pipe_cost = main_length_m * PIPE_COSTS["main_line_16mm"]
drip_tape_cost = drip_length_m * PIPE_COSTS["drip_tape_16mm"]
emitter_cost = emitter_count * PIPE_COSTS["emitter_inline"]
valve_cost = num_valves * 15 # Fixed $ per valve
total_cost = main + drip + emitter + valve
Current assumption:
- All pipes are 16mm.
- All emitters are $0.08 each.
- All valves are $15 each.
- These are order-of-magnitude guesses from generic sourcing.
Accuracy issues:
- No regional pricing: India vs. Kenya vs. Brazil have very different pipe costs.
- No volume discounts: a 1-hectare vs. 100-hectare farm have different unit costs.
- No installation labor: only materials, no digging, trenching, connection labor.
- No waste allowance: we assume 100% of pipe is used; real installations have ~5-10% waste.
When to improve:
- Collect regional pricing data: build a cost table by country/region.
- Add waste factor: multiply final quantities by 1.10 (10% waste).
- Surface cost per hectare & cost per emitter: help users compare.
Summary: Accuracy Levers (in order of impact)
| Lever | Current | Improvement | Impact |
|---|---|---|---|
| Valve density (Layer 3) | Fixed 6 valves/ha for tomato | Calibrate to local data + user input | π΄ HIGHEST β wrong density = under/over-designed |
| Lateral spacing uniformity | Clipped equally-spaced lines | Adaptive spacing by target lateral length | π΄ HIGH β short laterals = dead zones |
| Main line placement | Longest edge | Cost-optimal (main + laterals) | π‘ MEDIUM β 10-20% improvement typical |
| Pump head loss | Ignored | Model pressure drop over lateral length | π‘ MEDIUM β matters >100m laterals |
| Headland map | Fixed inward buffer | Per-edge buffer (N/E/S/W) | π‘ MEDIUM β irregular fields |
| Cost calibration | Guessed $ per unit | Regional/seasonal sourcing data | π‘ MEDIUM β users need local confidence |
| Topography split | Elevation delta > 5m β +1 zone | Voronoi split + contour-aware placement | π’ LOW β only needed for >10m deltas |
How to Test & Validate Your Improvements
1. Unit Tests
- Each improvement should have a test in
test_drip_engine.pyortest_valve_engine.py. - Example: if you improve lateral spacing uniformity, add a test that checks
max(lateral_lengths) / min(lateral_lengths) < 1.5(no more than 50% variation).
2. Visual Inspection
- Use the Gradio UI or REST API to generate designs for known farms.
- Compare your design to hand-drawn designs or existing irrigation schemes.
- Look for:
- Balanced lateral lengths β
- Valves placed logically β
- No huge dead zones β
3. Field Metrics
- Once you have real farm data, collect:
- Soil moisture at 0-30cm depth (3-5 spots per field)
- Before / after irrigation water use
- Crop yield uniformity
- Correlate with design metrics:
avg_lateral_length,lateral_length_std_devemitters_per_zone- Compare uniform designs vs. non-uniform designs
4. Sensitivity Analysis
- For each improvement, run the design with:
-10% parameterβ outputnominal parameterβ output+10% parameterβ output
- Measure sensitivity:
(output_+10% - output_-10%) / output_nominal - Example: "Reducing valve density from 6β5.4 /ha increases avg_lateral_length by 8%; this is acceptable for loose clay soils but risky for sandy soils."
Next Steps
Identify your priority:
- Cost accuracy? β Fix regional pricing (Step 3).
- Design uniformity? β Adaptive lateral spacing (Step 2).
- Operational realism? β Tune valve density + add headland map (Step 1).
Collect data: 5-10 real farms (geometry, crops, pump, existing irrigation scheme if any).
Iterate:
- Improve one lever at a time.
- Validate against your test farms.
- Document assumptions.
Share improvements: push back to the repo so the next user benefits.