Community Foodshed Methodology
This page documents the rules, constants, and academic sources that power the tier assignment, parcel clustering, and yield estimation algorithms.
Data Source Citations
Every third-party dataset used in the algorithm, how the provider requires it to be cited, and the license terms. Last updated: March 2026.
1. National Land Cover Database (NLCD) 2021
| Used for | Land cover classification (forest, crop, urban, wetland, etc.), impervious surface percentage |
| GEE Asset | USGS/NLCD_RELEASES/2021_REL/NLCD/2021 |
| DOI | 10.5066/P9JZ7AO3 |
| License | Public domain (U.S. Government work). No restrictions. |
| Source | USGS MRLC Consortium |
2. Shuttle Radar Topography Mission (SRTM)
| Used for | Elevation (meters), slope (degrees), aspect (compass direction) |
| GEE Asset | USGS/SRTMGL1_003 |
| DOI (data) | 10.5067/MEaSUREs/SRTM/SRTMGL1.003 |
| DOI (paper) | 10.1029/2005RG000183 |
| License | Public domain (NASA/USGS). Freely available for any use. |
| Source | NASA JPL / USGS EROS |
3. POLARIS Soil Properties
| Used for | Soil pH, clay %, sand %, organic matter %, saturated hydraulic conductivity (ksat) — 30m resolution, 0–5cm depth |
| DOI | 10.1029/2018WR022797 |
| License | Freely available for research and non-commercial use. Contact authors for commercial use. |
| Source | Duke University Hydrology Group |
4. JRC Global Surface Water
| Used for | Flood occurrence probability (% of time water present), flood recurrence |
| GEE Asset | JRC/GSW1_4/GlobalSurfaceWater |
| DOI | 10.1038/nature20584 |
| License | Copernicus Programme. Free and open access. Attribution required. |
| Source | European Commission Joint Research Centre |
5. PRISM Climate Normals
| Used for | Annual precipitation (mm), minimum temperature for USDA hardiness zone, frost-free period, growing degree days |
| GEE Asset | OREGONSTATE/PRISM/Norm91m |
| License | Free to reproduce and distribute with attribution. |
| Source | PRISM Climate Group, Oregon State University |
6. U.S. Census Bureau (Decennial 2020, ACS, TIGER/Line)
| Used for | Population, households, demographics (age, income, housing type), block-level geography |
| License | Public domain (U.S. Government work). No restrictions. |
| Source | U.S. Census Bureau |
7. gNATSGO (Gridded National Soil Survey)
| Used for | Available water storage (soil quality proxy), drainage class, farmland classification |
| License | Public domain (U.S. Government work). No restrictions. |
| Source | USDA NRCS |
8. USDA Food Access Research Atlas
| Used for | Food desert designation (tract-level), food access indicators |
| License | Public domain (U.S. Government work). No restrictions. |
| Source | USDA ERS |
Platforms & Tools
Google Earth Engine
| Used for | Data access, sampling, and processing platform |
| DOI | 10.1016/j.rse.2017.06.031 |
| Terms | Free for research, education, noncommercial. Commercial use requires license. |
| Source | Google Earth Engine |
H3 Hexagonal Hierarchical Spatial Index
| Used for | Spatial indexing — all data assigned to H3 resolution-8 hexagons (~3.75 acres each) |
| License | Apache License 2.0. Free for any use including commercial. |
| Source | H3 Docs / GitHub |
1. Lot-Size to Tier Mapping
Parcels are classified into production tiers based on their contiguous acreage, NLCD land cover type, and impervious surface percentage.
| Tier | Description | Acreage Range | Adjacent LX Hexes | NLCD Types | Max Impervious |
|---|---|---|---|---|---|
| C1 | Home Garden | 0.25 - 2 acres | 1 hex | dev_low, dev_med (solo hex, no clustering) | 40% |
| C2 | Market Garden | 0.5 - 5 acres | 2+ hexes | dev_open, grassland (clustered open space only) | 25% |
| C3 | Smallhold | 5 - 40 acres | 2 - 10 hexes | grassland, pasture, cultivated | 15% |
| C4 | Farm | 40 - 200 acres | 10 - 50 hexes | pasture, cultivated | 10% |
| C5 | Anchor Farm | 200 - 2,000 acres | 50+ hexes | cultivated, pasture | 5% |
Source: SPEC Distributed Portfolio v5 — Tier system based on USDA farm size classifications and Peters et al. (2016) carrying capacity methodology.
2. Method × System Matrix
Each tier assumes specific production systems, methods, skill levels, and loss profiles. These assumptions drive the yield calculations.
| Tier | System(s) | Method | Skill | Loss Profile | Max Portfolio Share |
|---|---|---|---|---|---|
| C1 | Intensive Garden | Raised Bed | Intermediate | Home Garden (22% loss) | 15% |
| C2 | Intensive Garden | Biointensive | Experienced | Home Garden (22% loss) | 25% |
| C3 | Intensive Garden 20%, Pasture 40%, Orchard 15%, Row Crop 25% | Conventional | Experienced | Home Garden (22% loss) | 30% |
| C4 | Row Crop 50%, Pasture 35%, Intensive Garden 15% | Conventional | Expert | Commercial (31% loss) | 20% |
| C5 | Row Crop 65%, Pasture 35% | Conventional | Expert | Commercial (31% loss) | 10% |
Base Yield by Production System
| System | Base Yield (kcal/acre/yr) | Labor (hrs/acre/yr) | Years to Full | Citation |
|---|---|---|---|---|
| Intensive Garden | 2,900,000 | 500 | 1 | McDougall (2019), CoDyre (2015) |
| Food Forest | 2,100,000 | 80 | 7 | Bjorklund (2019) |
| Silvopasture | 1,500,000 | 40 | 5 | Silveira (2023) |
| Pasture | 800,000 | 20 | 1 | USDA-NASS |
| Orchard | 3,500,000 | 200 | 5 | Lordan (2019) |
| Row Crop | 13,718,000 | 10 | 1 | Peters (2016) corn baseline |
Method Yield Modifiers
| Method | Yield Modifier | Labor Modifier | Citation |
|---|---|---|---|
| Conventional | 1.0x | 1.0x | Baseline |
| Biointensive | 1.3 - 4.0x (by skill) | 2.0 - 3.0x | Beeby (2020), Resoil Foundation (2022) |
| Square Foot Gardening | 1.2 - 1.5x | 0.6x | U of Minnesota Extension |
| No-Dig | 0.97 - 1.12x (by year) | 0.40x | Dowding (2013-2024) 13-year trial |
| Raised Bed | 1.5 - 2.0x | 0.7x | Dawes Arboretum / OSU Extension |
| Container | 0.50 - 0.70x | 1.75x | Pulighe (2023) |
Skill Level Modifiers
| Skill Level | Yield Modifier | Description |
|---|---|---|
| Beginner | 0.30x | First year, learning fundamentals |
| Intermediate | 0.65x | 2-4 years, consistent routine |
| Experienced | 0.85x | 5+ years, succession planting |
| Expert | 1.0x | 8+ years, commercial-grade output |
Sources: [8] McDougall (2019), [9] CoDyre (2015), [10] Beeby (2020), [22] Dowding (2013-2024), [23] U of Minnesota Extension, [26] Resoil Foundation (2022).
curl -H "X-API-Key: $KEY" \ "$API/api/crops/viable?zone=8" curl -H "X-API-Key: $KEY" \ "$API/api/labor/breakdown?sqft=2500&system=intensive_garden&method=raised_bed&skill=beginner"
Labor: { "base_labor_per_acre": 500, "method_labor_modifier": 0.7, "skill_labor_modifier": 1.5, "total_hours_yr": 30.13, "hours_per_week": 0.58 }
3. NLCD Compatibility Groups
Adjacent hexes cluster into parcels only if they belong to the same compatibility group AND that group supports clustering. Residential hexes (dev_low, dev_med) are never clustered — each home is its own C1 parcel.
| Compatibility Group | NLCD Types | Eligible Tiers | Clustering |
|---|---|---|---|
| Agricultural | cultivated, pasture, grassland | C2, C3, C4, C5 | Union-Find (adjacent same-type hexes form parcels) |
| Open Space | dev_open | C1, C2 | Union-Find (parks, campuses form parcels) |
| Residential | dev_low, dev_med | C1 only | None — each hex = 1 parcel (individual home garden) |
| Excluded | forest, water, wetland, barren, dev_high, shrub | - | - |
NLCD classification from USGS National Land Cover Database 2021. Compatibility rules from SPEC-300 tessellation design.
4. Effective Acres — Density-Weighted Garden Potential
Effective acres uses a density-weighted garden potential model that combines NLCD land cover type with impervious surface percentage to estimate realistic garden space per hex. For residential hexes, this estimates homes per hex, then garden space per home.
Agricultural Land
Cultivated, pasture, and grassland use the full hex area minus impervious surfaces. Typically 95-100% of 3.75 acres.
Residential Land (NLCD dev_low, dev_med)
garden_sqft_per_home = max(150, 3500 - impervious_pct × 45)
garden_potential = min(homes × garden_sqft / 43560, max_available)
| NLCD Type | Impervious % | Est. Homes/Hex | Garden sqft/Home | Garden Acres | Old Calc | Reduction |
|---|---|---|---|---|---|---|
| dev_low | 35% | ~7.5 | ~1,925 | 0.33 | 2.44 | 7.4× |
| dev_med | 70% | ~20 | ~350 | 0.16 | 1.13 | 7.0× |
| dev_open | 10% | ~1.3 | ~3,050 | 3.38 | 3.38 | 1.0× |
| cultivated | 2% | - | - | 3.68 | 3.68 | 1.0× |
Demand Weighting
Dense residential hexes also generate demand weight (estimated population × 2.5 persons/household). High-density clusters become demand centers (more mouths to feed), while sparse residential areas become the production base.
Density model uses NLCD 2021 + impervious surface data. Residential density estimates are calibrated heuristics, not census-tract-level data.
5. Livestock Integration — Feed-Land Competition
Livestock is integrated into the expansion loop — not added after it. When a C3+ parcel is activated, livestock potential is calculated alongside plant yield. Pasture animals consume effective acres (feed-land competition), reducing the land available for crops.
Unlock Thresholds
| Animal | Min Space | Space/Head | Uses Pasture | kcal/head/yr | Labor hrs/head/yr |
|---|---|---|---|---|---|
| Laying Hens | 2,000 sqft | 14 sqft | No (structures) | 14,800 | 20 |
| Feeder Pigs | 0.25 ac | 0.1 ac | Yes | 117,120 | 20 |
| Hair Sheep | 1.5 ac | 0.4 ac | Yes | 61,791 | 5 |
| Beef Cattle | 5 ac | 2.0 ac | Yes | 269,000 | 30 |
| Aquaculture | 0.25 ac | 54 sqft | No (pond) | 695 | 10 per 50 fish |
Feed-Land Competition Model
plant_acres = effective_acres - pasture_used
total_kcal = plant_yield(plant_acres) + livestock_kcal
Pasture animals (sheep, beef, pigs) consume land from the parcel's effective acres — up to 30%. This means a 20-acre C4 farm allocates at most 6 acres to livestock grazing, leaving 14 acres for crops.
Non-pasture animals (laying hens, aquaculture) use structures or ponds and do not deduct from crop land. Laying hens are capped at 12 (C3), 25 (C4), or 50 (C5) per parcel.
Portfolio Cap Enforcement
Livestock kcal is included in the portfolio cap check. A C3 parcel producing 500K plant kcal + 200K livestock kcal counts as 700K toward the C3 tier cap (30% of target). This prevents livestock from inflating results beyond cap limits.
Sources: USDA-FDC (nutrition), USDA-NASS (production), ATTRA (small-scale guides), Virginia Tech Extension (sheep), Penn State Extension (housing), Missouri Extension (economics). All citations verified against source PDFs.
curl -H "X-API-Key: $KEY" \ "$API/api/livestock/viable?sqft=10000®ion=humid_east"
6. Reference Designs — 5-Acre Market Farm
1-LX Parcel (3.75 acres effective)
| Zone | Acres | System | Primary Crops |
|---|---|---|---|
| Market Garden | 1.0 | Biointensive | Tomatoes, greens, herbs, peppers |
| Orchard | 0.5 | Fruit trees | Peaches, figs, pecans |
| Pasture/Poultry | 1.5 | Rotational | 25 laying hens, cover crops |
| Infrastructure | 0.75 | - | Barn, wash station, parking, paths |
2-LX Parcel (7.5 acres effective)
| Zone | Acres | System | Primary Crops |
|---|---|---|---|
| Market Garden | 2.0 | Biointensive | Full vegetable rotation (20+ crops) |
| Orchard | 1.0 | Fruit/nut trees | Peaches, pecans, figs, persimmons |
| Row Crop | 1.5 | Conventional | Sweet potatoes, corn, dry beans |
| Pasture | 2.0 | Rotational grazing | 25 hens + 3 sheep |
| Infrastructure | 1.0 | - | Barn, cooler, wash station, CSA pickup |
3-LX Parcel (11.25 acres effective)
| Zone | Acres | System | Primary Crops |
|---|---|---|---|
| Market Garden | 3.0 | Biointensive | Full rotation + succession planting |
| Orchard/Food Forest | 2.0 | Multi-strata | Fruit trees, berry understory, nitrogen fixers |
| Row Crop | 2.0 | Conventional | Sweet potatoes, corn, winter wheat, dry beans |
| Pasture | 3.0 | Silvopasture | 2 cattle + 25 hens + 3 sheep, scattered trees |
| Infrastructure | 1.25 | - | Barn, cold storage, processing, farm stand |
7. Yield Calculation Formula
Per-Hex Yield (Liebig's Law — Multiplicative)
hex_yield = base_system_yield x effective_acres x phi_hex
Stage 2: Aggregation-Level Adjustments (applied during regional rollup, NOT per-hex)
Per-Parcel Yield (Sum of Member Hexes)
Regional Portfolio Yield (Capped Tiers)
capped_share[tier] = min( raw_share, max_share_of_total )
portfolio_yield = SUM( total_yield x capped_share[tier] for each tier )
Yield Variance Disclosure
- Skill level: Beginner (0.30×) vs Expert (1.0×) = 3.3× range
- Crop focus: Vegetables-only vs calorie-optimized = 1.5-2× range
- Land quality (phi_hex): Poor soil/slope (0.3) vs optimal (1.0) = 3.3× range
- Method: Container (0.5×) vs biointensive (4.0×) = 8× range
- Zone modifier: Zone 3 (0.65×) vs Zone 8 (1.0×) = 1.5× range
Combined worst-to-best case: 0.30 × 0.5 × 0.3 = 0.045× vs 1.0 × 4.0 × 1.0 = 4.0×, a ~90× theoretical range. In practice, the typical range across activated parcels is 5-15× due to correlation between skill and method choice.
Coefficient framework: FAO (1976) Framework for Land Evaluation. Multiplicative model: Liebig's Law of the Minimum.
curl -H "X-API-Key: $KEY" \ "$API/api/caloric-plan?sqft=2500&zone=8&skill=beginner&focus=mixed_garden&method=raised_bed&mouths=4"
"allocations": [{ "commodity": "Garlic", "allocated_sqft": 875, "expected_kcal_yr": 87394 }, ...],
"summary": { "total_kcal_yr": 182304, "self_sufficiency_pct": 6.2, "loss_factor": 0.78 } }
8. Post-Harvest Loss and Waste
| Supply Chain | Loss Factor | Total Loss | Used By |
|---|---|---|---|
| Commercial (retail chain) | 0.69 | 31% | C4 Farm, C5 Anchor |
| Home Garden (direct sale) | 0.78 | 22% | C1 Community, C2 Market, C3 Smallhold |
| Home Garden Expert (preservation) | 0.82 | 18% | Expert-level operators |
Source: USDA-ERS LAFA (2011) Loss-Adjusted Food Availability data. Blended factors computed from per-crop retail loss, consumer loss, and inedible share.
8a. Production Methods (Source of Truth: Python Coefficients)
Production method modifiers are hardcoded in foodshed_core_v3.py METHODOLOGIES dict with inline citations. The methods.json file exists for UI display only and is NOT consumed by calculations.
Each method defines: land cover requirements (NLCD types), hard gates (min/max acreage, tree cover), preferred conditions, and a yield key that maps to the YIELD_TABLE for production estimates.
Method Definitions
| Method | Scale | Required NLCD | Food Type | Skill Required |
|---|---|---|---|---|
| Market Garden | micro-small | dev_open, dev_low | vegetables | medium |
| Backyard Garden | micro | dev_open, dev_low | vegetables | low |
| Mushrooms | micro | forest_dec, forest_evg, forest_mix | fungi | medium |
| Container Garden | micro | dev_open, dev_low, dev_med | vegetables | low |
| Raised Bed | micro | dev_open, dev_low, dev_med | vegetables | low |
| Community Garden | micro-small | dev_open, dev_low | vegetables | low |
| Row Crop | large | cultivated, pasture | grain | high |
| Orchard | medium-large | cultivated, pasture, dev_open | fruit | medium |
| Food Forest | small-medium | forest types, dev_open | mixed | high |
| Silvopasture | large | forest, pasture, grassland | mixed | high |
| Pasture Rotation | large | pasture, grassland | livestock | medium |
Method definitions derived from USDA extension publications, ATTRA sustainable agriculture guides, and peer-reviewed field studies. See inline citations in foodshed_core_v3.py METHODOLOGIES dict.
8b. Gardener Skill Level Modifiers (Source of Truth: Python Coefficients)
Skill modifiers are hardcoded in foodshed_core_v3.py SKILL_MODIFIERS dict with inline citations. The skills.json file exists for UI display only and is NOT consumed by calculations.
Skill creates 3-11x yield variance on identical plots. This is the LARGEST source of uncertainty in residential food production estimates.
| Level | Modifier | Typical Yield (lbs/sqft) | Used For | Citation |
|---|---|---|---|---|
| General Population | 0.10 | 0.15 | L1 community estimates | CoDyre et al. (2015), n=50, Guelph ON |
| Beginner | 0.30 | 0.45 | First 1-2 seasons, actively learning | Conk & Porter (2016) lower quartile |
| Intermediate | 0.65 | 1.00 | 3-5 seasons experience | Conk & Porter (2016) median |
| Experienced | 0.85 | 1.25 | 5-10 seasons, succession planting | U of MN upper quartile, CoDyre 7+ years |
| Expert | 1.00 | 1.50 | 10+ years, optimized systems | Conk & Porter (2016) maximum 2.06 lbs/sqft |
Participation Rate (Survey Penalty)
Applied during site assessment. Each red-flag answer reduces yield estimate by 3%, floored at 50%. This captures site-specific risks (contamination, access issues, etc.) that satellite data cannot detect.
CoDyre et al. (2015) doi:10.1016/j.ufug.2014.11.001; Conk & Porter (2016) doi:10.2105/AJPH.2015.302991; University of Minnesota Master Gardener Study (2018-2022).
8c. Data Sources and Lineage
The yield calculation pipeline draws from multiple data sources with a clear hierarchy:
Primary Yield Data
| Source | File | What It Provides | Used By |
|---|---|---|---|
| USDA-NASS, Extension Guides, Knott's Handbook | crops_garden.json | Per-crop yields (lbs/acre, kcal/acre) for garden-scale production | caloric_engine.load_crop_data() |
| USDA stocking rate guides, Extension publications | livestock.json | Livestock unlock thresholds, production values, citations | assessment_engine.LIVESTOCK_UNLOCKS |
| USDA-NASS zone data | zone_modifiers.json | Growing season adjustments by USDA hardiness zone | caloric_engine.get_zone_modifier() |
Constants and Framework (Peters et al. 2016)
| What | Value | Source | Used By |
|---|---|---|---|
| Per capita demand | 2,150 kcal/day | Peters (2016) p.4 | Self-sufficiency calculations |
| ROW_CROP baseline | 13.7M kcal/acre | Peters Table S12 (corn grain) | BASE_YIELDS[ROW_CROP] |
| Diet adjustments | 0.85-1.15x | Peters Table 3 | DIET_ADJUSTMENTS multipliers |
| Environmental thresholds | varies | Peters supplementary | Drainage, slope, flood coefficients |
Citation Enrichment (Reference Only)
peters_yields.json contains 127 crop yields from Peters et al. (2016) Table S12. These are attached to crop recommendations as reference metadata for transparency but are NOT used as the calculation driver. The actual per-crop kcal/acre values come from crops_garden.json.
crops_garden.json drives actual caloric calculations.
Peters et al. (2016) provides the theoretical framework (constants, baselines, environmental coefficients)
and citation metadata. Do not conflate the two.
Peters, C.J. et al. (2016). Carrying capacity of U.S. agricultural land: Ten diet scenarios. Elementa: Science of the Anthropocene, 4, 000116. DOI: 10.12952/journal.elementa.000116
10. Future Capabilities
Planned but Not Yet Implemented
- Computer vision photo analysis: Upload 3 photos of your land, AI estimates sun exposure, tree cover, and existing infrastructure.
- Sensor integration: IoT soil moisture sensors feed real-time data into yield estimates.
- Mesh network: Community sensor mesh for hyper-local microclimate data across L0 neighborhoods.
- Climate adjustment coefficients: Regional climate multipliers (currently, Peters yields are national averages that implicitly include climate variation).
- Food forest tier: Assign existing forest hexes to food forest production with 7-year establishment curve.
Part 2: Full Coefficient Registry
Every number the algorithm uses, its source paper, and confidence level. Loaded from Section B of foodshed_core_v1.py.
Confidence levels: HIGH peer-reviewed / official data MEDIUM extension / grey literature LOW estimates / extrapolations UNKNOWN needs citation
Loading coefficient registry...
Part 3: Algorithm Reference
Detailed algorithm documentation for the six core computation modules. Source code references included for each section.
10. Site Assessment Pipeline
Source: assessment_engine.py
8-Phase Pipeline
| Phase | Function | Description |
|---|---|---|
| 1 | score_questions | Ternary answers: good=1.0, warning=0.5, red_flag=0.0 |
| 2 | aggregate_categories | Weighted category scores with status assignment |
| 3 | derive_hex_modifiers | Satellite-measured coefficients (soil, slope, flood, sun) |
| 4 | extract_constraints | Cross-reference survey + hex data to identify blockers |
| 5 | recommend_methods | Rank production methods by suitability score |
| 6 | calculate_yield | Combine area, skill, method, survey, hex, and climate factors |
| 7 | self_sufficiency | Calculate % of annual caloric needs satisfied |
| 8 | recommend_crops | Filter crops by constraints + hex conditions |
Hex Data Derivation
The system auto-answers 7 survey questions from satellite/soil data:
| Question | Hex Field(s) | Derivation Logic |
|---|---|---|
| Q0: Sun hours | tree_pct | 14 hrs x (1 - tree_pct/100). 0% tree = 14 hrs, 100% = 1 hr |
| Q1: Aspect | aspect_deg | 135-225 = good (south); 90-270 = warning (E/W); else red |
| Q2: Tree proximity | tree_pct | <20% = good; 20-60% = warning; >60% = red |
| Q4: Pooling/drainage | drainage_class | well/excessive = good; moderate = warning; poor = red |
| Q6: Flooding | flood_risk | minimal = good; moderate = warning; high = red |
| Q9: Soil texture | clay_pct, sand_pct | Loam (15-40% clay, 30-70% sand) = good; extremes = red |
| Q13: Slope | slope_deg | <5 deg = good; 5-10 deg = warning; >10 deg = red |
Yield Formula
x base_kcal_per_sqft
x skill_modifier (0.10 - 1.0x, see Section 8b)
x method_modifier (raised_bed: 1.75x, no_dig: 1.10x, etc.)
x survey_penalty (1.0 - 0.03 x red_flag_count, floor 0.5)
x hex_soil_mod (from calculate_soil_coefficient)
x hex_slope_mod (from calculate_slope_coefficient)
x hex_flood_mod (from calculate_flood_coefficient)
x hex_sun_mod (from tree_pct canopy: 0.45 - 1.00x)
x season_multiplier
Season Multiplier
| Crop Focus | Maturity (days) | Turnaround | Cycle Length |
|---|---|---|---|
| vegetables_only | 55 | 14 | 69 days |
| mixed_garden | 85 | 14 | 99 days |
| calorie_focused | 95 | 14 | 109 days |
| calorie_optimized | 100 | 14 | 114 days |
Constraint Extraction Rules
Cross-references survey answers with hex data. Hex data can escalate but not downgrade a constraint.
| Constraint | Survey Source | Hex Override |
|---|---|---|
| sun_limited | Q0, Q2 red | tree_pct > 60% |
| water_limited | Q3 red | drainage = poor/very_poor |
| flood_concern | Q6 red | flood_risk != minimal |
| contamination_risk | Q31-Q33 (history) | NLCD type via B.14 + impervious > 50% |
| slope_concern | Q13 red | slope_deg > 8 deg |
| poor_soil | (inferred) | hex soil_modifier < 0.5 |
Method Ranking Algorithm
Each method starts with a base score of 50 and is adjusted by constraint interactions:
| Constraint | Boosted Methods (+) | Penalized Methods (-) |
|---|---|---|
| contamination_high | raised_bed +40, container +30 | others -20 |
| sun_limited | container +15 | biointensive -30 |
| water_limited | no_dig +20 | container -15 |
| flood_concern | raised_bed/container +15 | others -10 |
| poor_soil | raised_bed +25, container +20 | - |
| large land (>1 ac) | conventional/biointensive +20 | raised -15, container -25 |
| small land (<500 sqft) | raised/container/SFG +15 | conventional/biointensive -10 |
Returns top 3 viable methods plus all blocked methods. Biointensive is blocked by high contamination and requires full sun.
Source: assessment_engine.py. Contamination thresholds from EPA (400 ppm lead action level).
# Get the 38-question checklist
curl -H "X-API-Key: $KEY" "$API/api/checklist"
# Submit a quick plot assessment
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"space_type":"backyard_medium","area_sqft":1500,"skill_level":"beginner","mouths_to_feed":2,"crop_focus":"mixed_garden"}' \
"$API/api/myplot"
My Plot: { "assessment": { "land_score": 0.75, "recommended_method": "raised_bed", "constraints": ["partial_shade"], "top_crops": [...] },
"yield": { "total_kcal_yr": 180000 }, "self_sufficiency": { "pct": 24.7, "mouths": 2 } }
10a. My Plot: Space Types & Area Integrity
Source: assessment.py SPACE_TYPES + plot_routes.py /api/myplot
Space Type Definitions
The user selects a space type that defines their growing context. Each type has a square-footage range, default area, and constraints on which growing methods are available.
| Space Type | Min (sqft) | Max (sqft) | Default (sqft) | Allowed Methods | Min Hexes |
|---|---|---|---|---|---|
| Balcony | 20 | 100 | 50 | Container | - |
| Patio | 50 | 200 | 120 | Container, Raised Bed | - |
| Backyard S | 200 | 1,000 | 500 | Raised Bed, No-Dig, Biointensive | - |
| Backyard M | 1,000 | 5,000 | 2,500 | Raised Bed, No-Dig, Biointensive, Conventional | - |
| Backyard L | 5,000 | 20,000 | 10,000 | Raised Bed, No-Dig, Biointensive, Conventional | - |
| Open Lot (0.5-4 ac) | 21,780 | 174,240 | 43,560 | Conventional, No-Dig, Biointensive | 1 |
| Small Acreage (4-10 ac) | 174,240 | 435,600 | 217,800 | Conventional, No-Dig, Biointensive | 2 |
| Farm (10+ ac) | 435,600 | 4,356,000 | 871,200 | Conventional, No-Dig | 3 |
Hex-Area Integrity Constraint
When a user selects hex cells on the map, the system constrains which space types are available based on the physical land area those hexes represent. This prevents incoherent configurations (e.g., claiming 20 acres of farmland when only 3.75 acres of satellite data is selected).
| Hexes Selected | Physical Area | Available Space Types | Disabled Space Types |
|---|---|---|---|
| 0 (estimation mode) | unbounded | All | None |
| 1 | 3.75 ac (163,350 sqft) | Balcony through Open Lot | Small Acreage, Farm |
| 2 | 7.50 ac (326,700 sqft) | Balcony through Small Acreage | Farm |
| 3+ | 11.25+ ac (490,050+ sqft) | All | None |
Backend Area Cap (Safety Net)
Even if a disallowed space type reaches the backend (e.g., direct API call), the server caps the growing area to the physical hex coverage:
total_area_sqft = min(requested_area, max_area)
user_area = min(user_area, max_area)
Canopy Area Reduction (Physical Land Exclusion)
When satellite data shows tree canopy coverage on selected hexes, the system reduces the available growing area proportionally. This is a physical geometry reduction, not a yield coefficient. If 65% of the land has trees on it, only 35% is physically plantable — regardless of how productive that 35% might be.
usable_fraction = max(1.0 - canopy_pct / 100, 0.05)
effective_area = total_hex_area x usable_fraction
| Canopy % | Usable Land | Example (3 hexes = 11.25 ac) |
|---|---|---|
| 0% (open field) | 100% | 11.25 acres usable |
| 30% (scattered trees) | 70% | 7.88 acres usable |
| 65% (dense forest) | 35% | 3.94 acres usable |
| 90% (closed canopy) | 10% | 1.13 acres usable |
| 95%+ (full forest) | 5% (floor) | 0.56 acres usable |
Survey-Hex Dampening
When satellite data and user survey answers cover the same environmental factor, the system dampens the satellite penalty based on the user's ground observation. This prevents double-counting and respects the user's direct knowledge of their site.
| Hex Modifier | Overlapping Survey Questions | What They Measure |
|---|---|---|
| sun_modifier | Q0 (sun hours), Q2 (tree proximity) | Light availability / canopy shading |
| soil_modifier | Q4 (drainage), Q9 (soil texture) | Soil quality and workability |
| flood_modifier | Q6 (flooding history) | Flood risk |
| slope_modifier | Q13 (slope steepness) | Terrain slope |
dampened_modifier = 1.0 - ((1.0 - raw_hex_modifier) x best_dampening_factor)
Raised Bed Soil Bypass
When the recommended method is raised_bed or container, the soil modifier penalty is reduced by 70% because imported soil replaces native ground:
Space type boundaries aligned to H3 resolution-8 hex area (3.75 acres). Survey-hex overlap mapping derived from HEX_COVERED_QUESTIONS in assessment.py. Dampening factors are design choices calibrated to balance satellite confidence against user observation.
11. Spatial Clustering (Union-Find)
Source: parcels.py
Algorithm Steps
| Step | Operation | Description |
|---|---|---|
| 1 | classify_hex | Map each hex to an NLCD compatibility group |
| 2 | Separate residential | Residential hexes (dev_low, dev_med) become solo 1-hex parcels — skip Union-Find |
| 3 | Build Union-Find | Create disjoint set for agricultural + open-space hexes only |
| 4 | Union adjacent | For each hex, union with same-group H3 neighbors (ring 1) |
| 5 | Extract components | Collect connected components from Union-Find |
| 6 | Normalize IDs | Use lexicographically smallest hex_id as stable parcel_id |
| 7 | Merge solo parcels | Add residential solo hexes into final parcel set |
Compatibility Groups
| Group | NLCD Types | Eligible Tiers | Clustering |
|---|---|---|---|
| Agricultural | cultivated, pasture, grassland | C2, C3, C4, C5 | Union-Find (2-50+ hexes) |
| Open Space | dev_open | C1, C2 | Union-Find (1-2+ hexes) |
| Residential | dev_low, dev_med | C1 only | None (each hex = 1 parcel) |
| Excluded | forest, water, wetland, barren, dev_high, shrub | - | - |
Performance
Typical workload: 11,547 hexes x 6 neighbors = ~70K operations, under 200ms
Effective Acres
Uses the density-weighted garden potential model (Section 4). Agricultural land uses simple impervious deduction; residential land estimates homes per hex, then garden sqft per home.
Demand Clustering
Demand hexes are identified using NLCD classification (dev_med/dev_high = definite, dev_low > 35% impervious = likely). Clusters use Haversine distance (accurate at all latitudes) with adaptive radius:
| Demand Density | Cluster Radius | Context |
|---|---|---|
| > 15% | 2 km | Dense metro — tight clusters |
| 5-15% | 5 km | Suburban — moderate reach |
| 1-5% | 8 km | Semi-rural — wider for towns |
| < 1% | 15 km | Rural — catches small towns |
Cluster centroids are population-weighted using demand_weight from the Phase 2 density model, not simple geographic averaging.
Tier Assignment
For each parcel, check acreage ranges against eligible tiers for its compatibility group. Checked largest-first (C5 before C1). Must also satisfy minimum hex count.
| Tier | Min Acres | Max Acres | Min Hexes |
|---|---|---|---|
| C5 Anchor | 200.0 | 2,000.0 | 50 |
| C4 Farm | 40.0 | 200.0 | 10 |
| C3 Smallhold | 5.0 | 40.0 | 2 |
| C2 Market Garden | 0.5 | 5.0 | 2 |
| C1 Home Garden | 0.25 | 2.0 | 1 |
Union-Find: Tarjan (1975). H3 adjacency: Uber Engineering H3 resolution 8 hexagonal grid.
12. Portfolio Optimization — Strategy-Dependent Caps
Source: services/simulation.py
Portfolio Caps
Caps prevent any single tier from dominating production. They are design choices (not peer-reviewed parameters) and vary by optimization strategy to match each strategy's objective.
| Tier | Default | Yield/Labor | Resilience | Network | Rationale |
|---|---|---|---|---|---|
| C1 Home | 15% | 15% | 20% | 25% | Network raises for super-cluster activation |
| C2 Market | 25% | 25% | 20% | 35% | Network raises for residential density |
| C3 Smallhold | 30% | 30% | 25% | 30% | Resilience tightens for true diversity |
| C4 Farm | 20% | 30% | 20% | 20% | Yield/labor raise (large farms = efficient) |
| C5 Anchor | 10% | 20% | 15% | 10% | Yield/labor raise; resilience slightly raises |
Diversification Score
Higher entropy = more balanced distribution across tiers
Used by the resilience strategy to score parcels that increase portfolio diversity.
Demand Constants — Two Baselines
| Context | kcal/person/year | Source | Usage |
|---|---|---|---|
| Regional foodshed analysis | 784,750 | Peters et al. (2016) Elementa 4:000116 | Simulation, scenarios, foodshed solver |
| Individual garden self-sufficiency | 730,000 | FAO/WHO sedentary adult (2,000 kcal/day) | Caloric engine (Grow Food tab) |
Peters et al. (2016) "Carrying capacity of U.S. agricultural land" Elementa 4:000116, p.4. Portfolio caps: local design decision for production diversity — not derived from academic research.
# Step 1: Load a community (returns session_id) curl -H "X-API-Key: $KEY" "$API/api/location/load?l1_id=YOUR_L1_ID" # Step 2: Run simulation (use session_id from step 1) curl -H "X-API-Key: $KEY" -H "X-Session-ID: $SESSION" \ "$API/api/simulation?local_target=0.70&strategy=labor" # Step 3: Compare all 8 strategies curl -H "X-API-Key: $KEY" -H "X-Session-ID: $SESSION" \ "$API/api/simulation/compare?local_target=0.70"
"workforce": { "total_people": 1634, "pct_of_population": 18.2,
"by_commitment": { "dedicated": { "count": 334 }, "regular": { "count": 358 }, "casual": { "count": 942 } } },
"portfolio": { "tier_shares": { "C1_home_garden": { "share_pct": 12.1 }, "C2_market_garden": { "share_pct": 54.3 }, ... } } }
Compare: [{ "strategy": "labor", "total_people": 1634, "dedicated": 334, "local_pct_achieved": 32.3 }, ...]
12a. Workforce Model — Commitment-Based Staffing
Source: services/simulation.py
After the simulation builds its plan (which parcels to activate, how many labor hours each needs), the Workforce Model converts raw labor hours into real people at real commitment levels. There is no user-facing "hours per week" input — the model determines workforce composition from the plan itself.
Three Commitment Levels
| Level | Hours/Week | Hours/Year | Who This Is |
|---|---|---|---|
| Dedicated | 20 | 1,000 | Lead growers, farm managers — this is their primary activity |
| Regular | 8 | 400 | Weekend crew, co-op members — serious recurring commitment |
| Casual | 2 | 100 | Harvest days, occasional help — community participation |
Staffing Mix by Tier
Each tier has a fixed staffing mix — the fraction of its total labor hours filled by each commitment level. These are design choices based on observed patterns in community agriculture, not peer-reviewed parameters.
| Tier | Dedicated | Regular | Casual | Rationale |
|---|---|---|---|---|
| C1 Home Garden | Special case: 1 person per garden, classified by actual time needed | A backyard garden is one person. Commitment level depends on plot size. | ||
| C2 Market Garden | 50% | 30% | 20% | 1 lead grower + weekend crew + community helpers |
| C3 Smallhold | 60% | 30% | 10% | Farmer + part-timers + occasional help |
| C4 Farm | 70% | 20% | 10% | Mostly professional with some community support |
| C5 Anchor | 80% | 15% | 5% | Farm operation with minimal outside help |
Calculation
level_hours = tier_total_labor_hours × staffing_mix[level]
people = ceil(level_hours / commitment_level_hrs_year)
For C1 Home Gardens:
people = parcel_count (1 person per garden)
commitment_level = based on avg_hours_per_garden / 52 weeks
Example: 2-Acre Market Garden
At 1,000 hrs/acre, a 2-acre market garden needs 2,000 labor hours/year:
| Level | Share | Hours | People |
|---|---|---|---|
| Dedicated (20 hrs/wk) | 50% | 1,000 | 1 |
| Regular (8 hrs/wk) | 30% | 600 | 2 |
| Casual (2 hrs/wk) | 20% | 400 | 4 |
| Total | 2,000 | 7 people |
Commitment-level model: local design decision. Labor hours per acre per tier from BASE_YIELDS (Section 2) with method modifiers applied.
13. Foodshed Solver
Source: foodshed_solver.py
5 Fixed Scenarios
| Scenario | Method | Diet | Participation | Purpose |
|---|---|---|---|---|
| 1. Current Reality | conventional | us_average | 3% | Today's baseline |
| 2. Motivated Community | mixed (50% conv + 50% no_dig) | us_average | 10% | Achievable with effort |
| 3. Break-Even | solved | solved | ≤ 50% | First combo that feeds everyone |
| 4. Mobilization | intensive (raised_bed) | reduced_meat | 25% | Diet shift scenario |
| 5. Crisis Response | biointensive | plant_forward | 50% | Expert gardeners + vegan |
Effective kcal/acre
x method_modifier
x skill_modifier
x diet_efficiency
x loss_factor
Participation Solver
min_participation = total_demand / (suitable_acres x effective_kcal_per_acre)
Result capped at 100%
Break-Even Finder
Iterates method x diet combos in escalating intensity order (conventional/us_avg first, biointensive/vegan last). Returns the first combination where min_participation ≤ 50%. If none achieve 50%, returns the best combo with achievable=false.
Diet Efficiency Table
| Diet | Efficiency Multiplier | kcal/person/yr | Rationale |
|---|---|---|---|
| us_average | 1.0x | 784,750 | Standard American diet (baseline) |
| reduced_meat | 1.3x | 784,750 | 30% less land per calorie |
| plant_forward | 1.6x | 730,000 | 60% less land per calorie |
| vegan | 2.0x | 700,000 | 100% less land per calorie |
Loss Factors by Method
| Method Category | Supply Chain | Loss Factor | Total Loss |
|---|---|---|---|
| conventional | commercial | 0.69 | 31% |
| mixed | home_garden | 0.78 | 22% |
| intensive | home_garden | 0.78 | 22% |
| biointensive | home_garden_expert | 0.82 | 18% |
Diet efficiency from Peters et al. (2016). Loss factors from USDA-ERS LAFA (2011).
# Requires a location loaded first (see Section 12 API example) curl -H "X-API-Key: $KEY" -H "X-Session-ID: $SESSION" \ "$API/api/foodshed"
{ "method": "intensive", "participation_pct_us_diet": 28 }, { "method": "biointensive", "participation_pct_us_diet": 18 }],
"hex_quality": { "prime_count": 120, "good_count": 340, "marginal_count": 80 },
"suitable_hexes": 540, "total_hexes": 3400 }
14. Garden Layout Engine (archived)
This feature is currently archived. The layout engine code is preserved in _archived/draw-plot/garden_layout.py for future re-addition.
Source: _archived/draw-plot/garden_layout.py
Bed Positioning
Beds are arranged within a rectangular plot using a border-inset grid layout:
| Step | Operation |
|---|---|
| 1 | Load method config (bed size + path width) |
| 2 | Calculate usable area (total - 2 ft border on all sides) |
| 3 | Arrange beds: East-West orientation, spaced by path_width, rows extend North-South |
| 4 | Return list of bed dicts with (x, y, width, height, label) |
Method Bed Dimensions
| Method | Bed Size | Path Width |
|---|---|---|
| raised_bed | 4 x 8 ft | 2 ft |
| biointensive | 5 x 20 ft | 1.5 ft |
| no_dig | 4 x 12 ft | 1.5 ft |
| conventional | 2.5 ft row width | 2.5 ft spacing (30-inch row) |
Crop Assignment
Crops are assigned to beds using round-robin from the recommendation list, with companion planting checks:
| Main Crop | Companions | Antagonists |
|---|---|---|
| Tomatoes | basil, carrots, parsley | cabbage, fennel |
| Corn | beans, squash (Three Sisters) | - |
| Beans | corn, squash, carrots | onions, garlic |
| Potatoes | beans, corn | tomatoes, squash |
Planting Calendar
Timing is calculated relative to frost dates. Each crop stores:
| Field | Description | Example (Tomatoes) |
|---|---|---|
| direct_sow | Seed vs transplant method | false (transplant) |
| start_indoor_weeks | Weeks before last frost to start indoors | 6 weeks |
| transplant_weeks_after | Weeks after last frost to transplant | 2 weeks |
| days_to_harvest | Maturity from planting | 75 days |
| season | "cool" (spring/fall) or "warm" (summer) | warm |
Materials Calculator
volume_cy = volume_cf / 27
| Method | Soil Mix |
|---|---|
| raised_bed | 1/3 topsoil + 1/3 compost + 1/3 peat/coco coir |
| no_dig | Cardboard base + 3-4 inches compost buildup annually |
| biointensive | Double-dug native soil + compost integration |
Companion planting: Carrots Love Tomatoes (Riotte, 1998). Bed dimensions: Jeavons (2012) biointensive standards.
15. Additional Coefficients
Source: foodshed_core_v1.py — Section C coefficient functions (not covered in B.1-B.17 registry)
Elevation Coefficient (beta_elevation)
Based on adiabatic lapse rate (~6.5 deg C per 1,000m):
| Elevation Range | beta_elevation | Description |
|---|---|---|
| 0 - 300 m | 1.00 | Low elevation |
| 300 - 600 m | 0.95 | Moderate |
| 600 - 1,000 m | 0.85 | High |
| 1,000 - 1,500 m | 0.70 | Mountain |
| 1,500 - 2,000 m | 0.50 | High mountain |
| 2,000+ m | 0.25 | Alpine |
Aspect Coefficient (beta_aspect)
Northern Hemisphere only. South-facing slopes receive maximum solar radiation.
| Aspect Range | beta_aspect | Exposure |
|---|---|---|
| 135 - 225 deg (South) | 1.00 | Maximum solar |
| 90 - 135 or 225 - 270 deg (SE/SW) | 0.95 | Good |
| 45 - 90 or 270 - 315 deg (E/W) | 0.90 | Moderate |
| 315 - 360 or 0 - 45 deg (North) | 0.85 | Reduced |
Farmland Class Coefficient (beta_farmland)
Based on USDA farmland classification system:
| Farmland Class | beta_farmland | Notes |
|---|---|---|
| Prime | 1.15 | Best soils, validated high productivity |
| Prime if Irrigated | 1.10 | Prime quality with water access |
| Statewide Important | 1.00 | Baseline reference |
| Local Important | 0.95 | Locally significant |
| Marginal | 0.85 | Marginal potential |
| Not Farmland | 0.70 | Urban, water, etc. |
Complete Expanded Hex Yield Formula
x beta_soil (geometric mean of pH, OM, texture, drainage)
x beta_slope (system-specific thresholds)
x beta_flood (FEMA recurrence intervals)
x beta_elevation (adiabatic lapse rate)
x beta_aspect (solar exposure by orientation)
x beta_farmland (USDA classification)
x method_modifier x skill_modifier x loss_factor
phi_hex = beta_soil x beta_slope x beta_flood
S1 (highly suitable): phi ≥ 0.80 | S2 (moderate): 0.50 ≤ phi < 0.80 | S3 (marginal): 0.25 ≤ phi < 0.50 | N1 (unsuitable): 0.10 ≤ phi < 0.25 | N2 (permanent): phi < 0.10
Elevation: adiabatic lapse rate (standard atmospheric). Aspect: Northern Hemisphere solar geometry. Farmland: USDA-NRCS Farmland Classification System. FAO classes: FAO (1976) Framework for Land Evaluation.
All constants sourced from peer-reviewed literature. Full coefficient registry with confidence levels above.