Edge Cases That Break Your Weather Model

Edge Cases That Break Your Weather ModelStalefish Labs

Freeze-thaw, snow melt, rain intensity, plant dormancy — the

This is a continuation of a deep-dive into the weather engine that drives our Groundwise apps. Last we looked into the core drying model, which handles most days well. Sun, wind, time, surface type — combine them sensibly and you get a reasonable verdict most of the time.

Then winter arrives and everything breaks. Interestingly, the engine was developed during the epic ice storm of 2026 that absolutely decimated parts of the southeastern U.S., including Nashville, TN where we're based. So I got to experience first-hand a very real edge case as I was building the engine, and literally each day presented new challenges to clarify for example how long it actually takes a trail to recover from a prolonged frozen period.

This article covers the edge cases that forced the most complex logic in the Groundwise engine, the scenarios where the simple model produces confidently wrong answers.

Freeze/Thaw: 360 Lines of Humility

The frozen conditions check is the single largest block of code in the engine. It runs first, before any moisture modeling, because frozen ground is a fundamentally different hazard than wet ground.

The naive approach would be simple: if the temperature is below 32°F, say No. But that misses almost everything that matters.

Hard Surfaces vs. Ground: Different Failure Modes

A frozen concrete skatepark and a frozen dirt trail are dangerous for completely different reasons, and they recover at completely different speeds.

Concrete and asphalt develop ice when moisture freezes on the surface. It's a thin layer — dangerous because it's invisible, but it clears relatively quickly once temperatures rise. At 55°F, a frozen skatepark is typically safe within 6 hours. At 50°F, give it 12. At 45°F, 24 hours, or just wait until 3 days after the last rain when there's simply no moisture left to freeze.

Dirt and natural grass hold moisture internally. When they freeze, the ice is in the ground, not just on top of it. Thawing releases that moisture all at once, creating a slurry that's worse than the original wet conditions. A ground trail at 45°F needs 72 hours to fully recover from a freeze — not because ice persists that long, but because the thaw creates its own wetness event. It's worth noting that one thing the engine does not attempt to factor in is the counterintuitive scenario where frozen mountain bike trails are sometimes more rideable when fully frozen due to the combo of frost heave breaking up the surface tread and then a deep freeze solidifying that oatmeal-like top layer into a grippy crunch. If you bundle up, some of the best winter riding here is when a trail fully heaves and freezes, but that seemed like a special enough case to not factor in (at least not yet!), especially when you factor in ride comfort.

The engine models the concrete/asphalt vs. dirt/grass freeze issue with separate escape conditions for draining vs. absorbent surfaces:

Temperature Hard Surface Recovery Ground Recovery
≥ 55°F 6 hours 24 hours
≥ 50°F 12 hours 48 hours
≥ 45°F 24 hours (or 3+ days since rain) 72 hours
< 45°F Still frozen Still frozen

The Near-Freezing Zone

32°F isn't a magic line. Ice can persist on surfaces at 34°F, especially in shade. And moisture can pose a freeze risk at 38°F if temperatures are dropping. Throw in wind and it's pretty evident that a simple 32°F freeze check isn't sufficient.

The engine treats 32-38°F as a caution zone. If there's been recent precipitation (last 24 hours) and the temperature is in this range, the verdict is No with medium confidence. Not because ice is definitely present, but because the risk isn't worth it.

Overnight Freeze, Currently Above Freezing

This is the most common winter scenario and the hardest to get right, especially in a moderate climate like the southeast where it can freeze overnight and then rise to sunny and 50s during the day. So an overnight freeze that changes to 52°F mid-day...is the trail rideable?

It depends on:

  • How long it's been above freezing — just crossed 32°F an hour ago? Still frozen. Been above freezing since 9am and it's now 2pm? Probably thawed.
  • What surface you're on — concrete sheds faster than dirt.
  • Whether there's recent precipitation — dry freeze is different from wet freeze.
  • Humidity — above 70% humidity with a recent overnight freeze means possible frost even on surfaces that look dry.

The engine tracks hoursBelowFreezing and hoursSinceThawBegan to model this progression. A surface that was frozen for 48 hours takes longer to fully thaw than one that dipped below freezing for 4 hours overnight.

Extended Freeze With No Recent Rain

It gets even trickier when you remove precipitation for a while. Here's a counterintuitive case: it's been below freezing for three days, but it hasn't rained or snowed in a week. Is it safe?

For hard surfaces: probably yes. No moisture means nothing to freeze. The engine still checks humidity (frost can form from humid air alone), but without recent precipitation, hard surfaces are likely clear.

For ground surfaces: still no. Even without recent rain, ground retains moisture from weeks of accumulated precipitation. A multi-day freeze locks that moisture in. When thaw comes, it releases.

Snow Melt: A Bell Curve, Not a Line

Snow melt seems simple — snow melts, things get wet, then they dry. But the wetness injection from melting snow follows a curve that's nothing like the linear decay used for rain timing.

The engine models thaw wetness on a bell curve based on melt progress:

Melt Progress Wetness Factor Why
< 5% 0.7 → 1.0 Starting to melt, moisture building
5-40% 1.0 Peak wetness, active melt, ground saturated
40-70% 1.0 → 0.4 Most snow gone, drainage beginning
70%+ 0.4 → 0.2 Residual moisture, mostly clear

Melt progress is estimated from hours since thaw began, with the assumption that most accumulations take about 48 hours to fully melt. Temperature above freezing drives the rate, warmer means faster.

The peak wetness window (5-40% melted) is deliberately wide. During active melt, the ground is receiving a continuous supply of water. Unlike rain, which dumps water and stops, snow melt is a slow, sustained event that can keep surfaces saturated for hours.

Snow accumulation matters too. Did you know that on average, 10 inches of snow is equivalent to 1 inch of liquid rain (a 10:1 ratio). However, this ratio varies significantly based on temperature, ranging from 5 inches (wet snow) to over 20 inches (dry, powdery snow) of snow for every 1 inch of liquid. But what we really care about is how much snow results in complete saturation. Here's how the engine scales the initial wetness injection for snow:

snowFactor = clamp(0.5 + snowAccumulation / 4.0, 0, 1)
Enter fullscreen mode Exit fullscreen mode

Half an inch gives a snowFactor of 0.625. Four inches saturates at 1.0. This prevents a light dusting from being treated the same as a significant snowfall.

When There's No Tracked Snow

Sometimes the engine knows there was a freeze/thaw cycle but doesn't have explicit snow accumulation data. In that case, it falls back to estimating initial moisture from freeze severity:

initialMoisture = 0.3 + 0.3 × freezeSeverity
Enter fullscreen mode Exit fullscreen mode

Where freeze severity scales from 0.3 (24 hours below freezing) to 0.6 (4+ days below freezing). Longer freezes lock more ground moisture, producing more wetness when thaw arrives.

The decay uses a half-life model, a baseline of 48 hours, stretched dramatically when overnight temperatures keep dropping below freezing. A thaw that refreezes each night can keep surfaces problematic for over a week, because each night arrests the drying process and each morning restarts the moisture release.

Precipitation Intensity: Same Amount, Different Impact

The drying model article covered the rain pattern multiplier (0.7x for light, 1.1x for steady, 1.5x for downpour), but intensity creates edge cases beyond just the multiplier.

A quarter inch of light rain over four hours soaks into absorbent surfaces gradually. The ground absorbs it progressively, and drainage keeps up. Surface water is minimal. This is the kind of rain you hear gardeners, landscapers, and farmers wishing for as it's the best watering rain for plants, slow and steady.

A quarter inch dumped in 20 minutes, on the other hand, overwhelms drainage. Water pools on the surface, runs off trails causing erosion, and saturates the top layer before it can percolate down. The surface is wetter even though the total precipitation is identical.

The 1.5x downpour multiplier captures this, but it's an approximation. In reality, the impact depends heavily on the surface's infiltration rate, slope, and drainage design — none of which the engine models directly. And it doesn't try.

This is one of the spots where the engine's approximation is "good enough for most cases" rather than trying to be physically accurate to the extreme. A purpose-built trail with water bars and crowned surfaces handles a downpour better than a flat trail in a natural depression. The engine treats both as dirt with a 1.0x drying multiplier, which is imprecise but still more useful than ignoring intensity entirely. This is also worth flagging where often a Maybe verdict is truly the best answer because it tells you conditions are borderline, and your own local knowledge may tip the final ride decision. Yes, the app is attempting to assist in the human intuition of weather conditions, but not replace it entirely.

Cold-Weather Dormancy: Protecting Plants From Themselves

This edge case is Yardwise-specific, but it's one of my favorites because it's a case where the "right" answer is counterintuitive.

When temperatures drop below 55°F, most plants enter dormancy. Their water uptake drops dramatically. Watering dormant plants typically doesn't help them, it can all too easily create conditions for root rot and fungal disease. In this scenario the engine needs to suppress watering recommendations even when the soil looks dry.

The dormancy calculation uses a non-linear curve:

coldFactor = pow((55 - temperature) / 23, 0.6)
Enter fullscreen mode Exit fullscreen mode

Why pow(x, 0.6) instead of linear? Because the suppression should be strong even at moderate cold. At 45°F (10 degrees below the 55°F threshold), a linear model gives a cold factor of 0.43. The power curve gives 0.56, which is meaningfully stronger. The difference matters because 45°F is genuinely cold enough to suppress plant activity, and the engine should reflect that.

The dormancy score gets amplified by:

  • Freeze history — if it's been below 32°F for 24+ hours recently, plants are deeply dormant. Add 0.25 × coldFactor.
  • Recent cold-weather watering — if the user watered during cold weather, that water persists much longer because evapotranspiration is minimal. The residual window extends from 48 hours to up to 96 hours. And yes, evapotranspiration is a real word...I couldn't resist using it.

But there's a warm-day dampener too. If the daytime high reaches 65°F even though it's cold right now, the suppression eases. This handles the classic spring pattern: cold mornings, warm afternoons. Plants are still somewhat active on those warm afternoon hours, and a warm day drives real evaporation.

warmDampening = clamp((warmerTemp - 65) / 30, 0, 0.5)
dormancyMoisture *= (1.0 - warmDampening)
Enter fullscreen mode Exit fullscreen mode

At 80°F daytime highs, the dampening cuts dormancy suppression in half. At 95°F, it's fully halved. The cold mornings still matter, but the warm afternoons are doing real drying work.

Low Evaporative Demand: When Dry Isn't Thirsty

Another Yardwise-specific edge case: on overcast, humid days with moderate temperatures, the soil might technically be "dry" by the engine's moisture model, but the plants aren't actually losing much water because evaporative demand is low.

Cloudy skies reduce solar radiation. High humidity reduces the vapor pressure gradient that drives transpiration. If both conditions are present and the temperature is under 85°F, the engine injects a small wetness boost (up to 0.25) to push borderline "water today" verdicts toward "check soil" or "skip."

cloudFactor = clamp((cloudCover - 0.3) / 0.7, 0, 1)
humidityFactor = clamp((humidity - 0.4) / 0.5, 0, 1)
demandReduction = cloudFactor × 0.55 + humidityFactor × 0.45
boost = demandReduction × 0.25
Enter fullscreen mode Exit fullscreen mode

The guard at 85°F is important. Hot weather drives real water demand regardless of clouds or humidity. Above that threshold, evaporative demand is high enough that the boost doesn't apply.

This is a small adjustment, 0.25 at maximum, but it prevents the engine from recommending watering on days when the lawn genuinely doesn't need it. Overwatering is a real problem, especially for casual gardeners who might not realize that a cool, overcast day means their yard is fine.

The Meta-Lesson

Every one of these edge cases started as a wrong verdict. A friend texted me "your app said Yes but the trail was iced over." A beta tester reported "it's telling me to water but it's 40 degrees." More personally, I'm literally looking at my skateboard ramp covered in ice and the app telling me it's shred-ready. Nope.

The temptation each time was to add a quick patch, an if statement for the specific scenario. What I tried to do instead was understand why the model was wrong and fix the underlying assumption. Usually the answer was: the model was treating something as a smooth continuum when reality has phase transitions and state changes.

Water doesn't gradually become less liquid as it gets colder. It freezes. Plants don't linearly reduce water uptake as temperature drops. They go dormant. Snow doesn't dry like rain. It melts.

The edge cases are where the domain expertise lives. The drying model is arithmetic. The freeze/thaw logic is hard-won knowledge about how the physical world actually works.

Next in the Series

The next article covers the Yardwise inversion, how the engine flips from "is it too wet?" to "is it too dry?" and the additional features (manual watering tracking, establishment sensitivity) that make gardening a distinct problem from riding and field sports.


The Groundwise engine powers Ridewise, Fieldwise, and Yardwise — all available for iOS from Stalefish Labs.