DEV Community

Cover image for Will the fountains on my ride be running? I asked 3,831 stream observations
Dominique Siacci
Dominique Siacci

Posted on

Will the fountains on my ride be running? I asked 3,831 stream observations

Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass Submission 🌿

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass

What I Built

There's a fountain on the road just before Marato, a stone basin behind a small railing, that I count on when I ride south of Ajaccio. It runs well. OpenStreetMap doesn't have it. IGN, the French national mapping agency, does, but 55 m away, in the woods.

I ride the same roads, slowly, and I know which of their fountains run in September. Riders passing through don't. OpenStreetMap lists 608 places to fill a bottle in Corsica; 2 of them say whether they dry up in summer, and 33 carry a date when someone last checked them. The maps know roughly where the fountains are. Nobody writes down whether they are running.

So I wrote fountains, a small open-source tool that runs on a laptop. You drop the GPX of your ride on a local page, and:

  1. it lists every fountain OpenStreetMap or IGN knows within 250 m of the route;
  2. it adds the places where open data hints at a fountain no map has: a spring IGN puts next to the road, a stream crossing under it;
  3. it shows each place on photos taken from the road, an open vision model putting first the views where it sees something like a fountain, and you decide: fountain, not a fountain, or not sure. When no view shows it, you look around in 360°, walk along the road from photo to photo, and click the foot of the fountain to put it where it really is;
  4. the fountains you keep get a band for the day of the ride, likely, uncertain or unlikely to be running, with the reason: the rain of the last weeks compared with normal, the forecast, the altitude, the nearest stream someone actually walked to;
  5. on long stretches without a likely fountain, it suggests a café, a bakery or a fuel station open when you pass, about every 10 km; a fountain you know runs cuts those stretches;
  6. one GPX goes onto the bike computer, with waypoints named like likely: Funtana di Leccia.

For a 28 km ride, the preparation takes about twenty minutes of the laptop working alone the evening before, then a few minutes of looking at photos. The rest happens on the road.

One rule is printed in every output of the tool, and I'll repeat it here: a score is never a reason to leave with less water. Carry what you need, as if every fountain were dry. The tool also says nothing about whether the water is safe to drink.

Demo

The video follows a real preparation, on my laptop: a 28 km out-and-back to La Parata. The 19 minutes in which the tool finds the points, the clues and the photos, and the vision model ranks every view, go by in ten seconds. The rest shows the cases I ran into:

  • at the Fontaine des Calanques, the model boxes a red fire hydrant: it ranks photos, it decides nothing;
  • at Funtana di Mela, an old stone fountain, I mark it on the photo, and the GPX puts it 22 m from IGN's point;
  • the places found from clues, mostly streams under the road, take one answer each: none of them was a fountain;
  • for Saturday, none of the four fountains I kept comes out likely: 28 km without a likely fountain, so the tool lists five shops open when I pass; marking the three fountains I know run brings the dry stretch down to 13 km.

Funtana di Leccia on the check screen: the best view, the model's box at 0.33, and the pin of the marked position, 55 m from IGN's point

That's the fountain before Marato, on my usual 70 km loop. The tool took the photos of the road around IGN's point, and the view the model ranks first is the fountain, seen from the road about twenty metres away. Marked on two photos taken 29 m apart, it lands 4 m from the road: the two lines of sight cross inside the box the model had drawn. IGN's point is 55 m away, in the woods.

On that loop, the maps know 7 water points within 250 m of the road. The clues add 29 places, 24 of them streams under the road. On 18 of them, the model sees nothing above 0.2; the page sets them aside (a switch brings them back), which leaves 18 points to look at.

Code

GitHub logo dsiacci / fountains

Will the fountains on your ride be running? Finds the fountains along a GPX in Corsica, checks them on street photos, bands them with TabPFN. Runs on your laptop.

fountains

A score is never a reason to leave with less water. Carry what you need for the whole ride as if every fountain were dry. This tool says nothing about whether the water is safe to drink.

Will the fountains along your ride be running on the day you ride?

You export your route as a GPX file and drop it on a local page. It lists every fountain that OpenStreetMap or IGN (the French national mapping agency) knows within a short detour of the route, adds the places where clues in open data suggest a fountain no map has, and shows each one on street photos so you can say which are real. The fountains you keep get a band (likely, uncertain or unlikely to be running) for the day you ride, with the reason and the date anyone last checked them. On long stretches without…

Python, Apache 2.0, 97 tests. fountains serve opens the page, fountains score does the same computation from the command line, and a Docker image runs the page on macOS or Windows. Every data source with its license, and the limits of the tool, are in the README.

How I Built It

Fountains on the maps. OpenStreetMap, through the Overpass API: amenity=drinking_water and water_point, plus springs, taps and fountains tagged drinking_water=yes. And IGN's topographic database, open since 2021, which knows 1,493 fountains in Corsica; only 250 of them have an OpenStreetMap point within 30 m. Each point is attached to the nearest road or path, and the detour is measured along the network: a fountain 40 m from the road can be 400 m away if the only access is a loop through the village.

Fountains on no map. Two kinds of clues, both in open data: IGN springs, wash houses and water points close to a paved road, and the places where a stream crosses one, because a spout is often built where the slope brings water down to the road. For each place, the tool takes the 360° photos within 100 m on Panoramax, the open street-imagery commons (in Corsica, mostly IGN's 2025 captures), cuts them into views of both roadsides, and asks OWLv2, an open-vocabulary object detector, for "a water fountain", "a water spout", "a stone water trough", "a water tap". Boxes touching the bottom of a view are ignored: that's where the bonnet of IGN's car shows. The model decides nothing; it sorts photos. Near Marato, its first view was my fountain; elsewhere, it took a fire hydrant or a decorative urn for a fountain. So I look at the photos, and I don't trust the score.

Putting the fountain where it is. A map can be fifty metres off, and a GPX that sends you into the woods is no use. When I click the foot of a fountain on a photo, the tool knows where the photo was taken and the direction of the click: that's a line of sight. Two photos give two lines, which cross at the fountain. With one, the distance is guessed from the angle below the horizon, for a camera on a car roof; the page says it's a guess, and the pin can be dragged on the map.

Rain. Météo-France opened all its public data on 1 January 2024, including the daily rain gauges: 103 gauges in Corsica have reported since 2010, 52 still do. The tool interpolates the rain at each fountain from the three nearest gauges, compares the last 30, 90 and 180 days with the 1991-2020 normal, and adds the Météo-France forecast (through Open-Meteo) for the days between the last report and the ride.

Labels. This is the part I didn't have. Nobody publishes whether fountains run, but France publishes whether small streams run: every summer since 2012, agents of the French Office for Biodiversity walk to the same points on small streams and write down what they see, from flowing to dry. The network is called ONDE. In Corsica that is 33 streams and 3,831 observations. I kept one question, is flowing water visible?, because a fountain only fills a bottle if water flows, and because it's the only split the observers used the same way every year (from 2016 to 2019 they didn't separate normal flow from weak flow).

The model. TabPFN, from Prior Labs, is a foundation model for tabular data: a transformer pre-trained on millions of synthetic tables. You give it the 3,831 rows as context (day of the year, altitude, rain over 30, 90 and 180 days, how the last 90 and 180 days compare with normal, and whether water was flowing), then the new rows, and it returns a probability for each in one forward pass. No training loop, no hyperparameters to tune. I use the open v2 weights, on the CPU: scoring a ride takes half a minute on my laptop.

How much to trust it. I hid each stream in turn and asked the model about it, given only the other 32. Over the 3,831 hidden observations:

Brier score (lower is better)
TabPFN 0.114
Logistic regression, same inputs 0.115
The rate for the month 0.127
Always "83 % flowing" 0.141

TabPFN is a little better than a logistic regression on the same inputs, by a margin too small to matter, and both beat the calendar by about 10 %. The ratios to normal earned their place: without them, TabPFN scored 0.118.

Reliability curve: the share of hidden observations actually flowing, against the probability TabPFN gave them

On streams it has never seen, its probabilities are too sure of themselves: cases it scored around 0.85 were flowing 72 % of the time, cases around 0.15 were flowing 43 % of the time. So I fixed the rule for the bands before the first run, and let the hidden streams set their limits: likely where at least 90 % of the hidden cases were flowing, unlikely where at most 50 % were. In the validation, "likely" streams were flowing 1,917 times out of 1,965, "uncertain" ones 1,232 times out of 1,734, "unlikely" ones 43 times out of 132. That's why the tool shows bands and not percentages: a percentage measured on streams would claim more than I know about fountains.

The weak link. A fountain is not a stream. The model assumes a fountain fed by a spring dries like a small headwater stream after the same weather. That's plausible for a village on a shallow spring, wrong for a tap on the town mains, and unknown for a deep spring that reacts months later. The page says so, and you can mark a fountain you know runs: it then counts as water, whatever the model says.

On Saturday I'm riding the route from the video again, to La Parata, and I'll update this post with what the four fountains actually did.

I built it this week with an AI coding agent.

Why Does Open Innovation Matter?

Every piece of this is open, and none of it would exist otherwise. The rain is measured by Météo-France and free to reuse since 2024. The stream observations are walked and written down by public agents and published under an open licence. The fountains were mapped by volunteers on OpenStreetMap and by IGN, whose database and street photos are open too. The models are open, so the whole thing runs on my laptop, with no account and nothing to pay, and it will give the same answer next year. Nobody would sell an API that says whether the fountain in a Corsican village is running; the market is a few hundred cyclists and hikers.

And it can go back. When a rider sees a fountain running or dry, the right place for that is OpenStreetMap's check_date and seasonal tags, and a fountain found on the photos belongs on the map too, where the next person (and the next version of this tool) will find it. The tool never edits the map itself; that stays a human's call.

Prize Categories

Best Use of TabPFN. TabPFN is the model that turns 3,831 stream observations, and the rain before each of them, into a probability that water is flowing, for streams it has never seen and then for fountains. The table is small, the classes are unbalanced (83 % of the observations are flowing), and what matters is whether the probabilities can be trusted, which I measured stream by stream. It did as well as the best simple baseline I tried, with no tuning at all, in one forward pass on a laptop CPU, and the validation told me exactly how far to trust it. Built with PriorLabs-TabPFN.


How do you deal with water on long rides or hikes, when you don't know the fountains? Do you trust them, carry everything, or ask at the café?

Top comments (0)