Skip to content
All projects

Client projectDec 2024 to Feb 2025

River Effluent Simulator

A desktop app that simulates river water quality and optimizes where effluents are discharged

  • Python
  • PyQt5
  • Matplotlib
  • pandas
  • PyInstaller

A desktop app delivered to the client; the code isn't public.

At a glance

What
A Windows desktop app that simulates how effluents affect a river's water quality and optimizes where they are discharged and how much they are treated.
Client
An environmental engineering PhD researcher.
Role
Sole developer: the model in code, the optimizer, the desktop interface, tests, packaging and the user manual.
When
December 2024 to February 2025.
Stack
Python, PyQt5, Matplotlib, pandas and XlsxWriter · PyInstaller for the executable · unittest.
Results
Delivered as a Windows desktop app. The study and its findings belong to the researcher.

The problem

Deciding where sewage may be discharged into a river, and how much it must be treated first, depends on how the river absorbs that load downstream. Models such as QUAL-UFMG describe that process, from the decay of organic matter to reaeration and the mixing of tributaries, but running many scenarios by hand is slow, and searching for the best combination of discharge points and treatment levels is impractical without software. The researcher needed a tool that could run those scenarios and search them automatically.

My role

I was the only developer. I turned the QUAL-UFMG model into Python code and built the genetic algorithm that searches the scenarios, the PyQt5 interface, the charts and exports, the automated tests and a 30-page manual, then packaged everything as a Windows executable. The water-quality model is QUAL-UFMG's, and the study and its conclusions are the researcher's.

What I built

  • River model: the main river and each tributary are split into short segments, 100 m by default, and each segment updates flow, velocity, depth, BOD and dissolved oxygen from the one before it, with temperature-corrected decay and reaeration rates.
  • Scenarios: rivers, tributaries, effluents and water intakes, each saved as a JSON file that can be edited in the app or in a text editor. A project is saved and imported as a folder.
  • Optimizer: a multi-objective genetic algorithm. Each candidate sets the discharge point and treatment efficiency of every effluent chosen for optimization, and is scored on up to five objectives: total treatment effort, inequity between sources, the best stretch for each source, and violations of the dissolved oxygen and BOD limits for the river's CONAMA class.
  • Results: charts of oxygen, BOD and flow along the river, a Pareto front to choose from, and CSV and Excel export of every solution or of one chosen solution.
  • Packaging: a single Windows executable built with PyInstaller, so the researcher runs it without installing Python.

Architecture

The app is a set of small Python modules: the river model, the simulation, the genetic algorithm, the scoring functions and the PyQt5 screens. A normal run simulates one scenario. An optimized run wraps the same simulation in the genetic algorithm, so every candidate is a full simulation of the river.

ScenarioRiver, tributaries and effluents, as JSON filesWater-quality modelTributaries first, then the main river, by segmentGenetic algorithmSets discharge points and treatment levelsResultsCharts, Pareto front, CSV and Excel exportevery candidateis one full runnormal runsskip the optimizer
An optimized run simulates the river once for every candidate. Normal runs go straight from the model to the results.

Key decisions

DecisionWhyTrade-off
A Pareto front instead of one weighted scoreThe objectives conflict, so the researcher chooses among the trade-offs instead of the code hiding them in weightsMore solutions to read; near-duplicates are filtered out, and up to five of them carry over to each new generation
Mutation per gene, not per candidateEach discharge point and each treatment level can change on its ownThe rate needs tuning; the manual recommends 0.5% to 1%
One JSON file per river, tributary and effluentScenarios can be edited in the app or in a text editor, and new elements need no code changeA project is a folder of many small files
A single executableThe researcher runs it without installing PythonA file of more than 60 MB for each release

Challenges

Every candidate is a full simulation. With the default settings, 300 candidates over 100 generations, one optimized run simulates the river about 30,000 times. The app reports progress while it runs, and the manual explains how population size, mutation rate and the number of generations trade speed for quality, so the researcher can size each run.

Rivers that feed rivers. A tributary changes the main river where it joins, so tributaries are simulated first, and their flow, BOD and oxygen at the confluence enter the main river as inputs. Effluents can sit on the main river or on any tributary.

How I know it works

  • 22 automated tests with unittest, covering the model's coefficients, the river simulation, the Pareto front, the genetic operators, saving and loading results, and full optimization runs.
  • The researcher's own words, below.

Results

The software was delivered in early 2025. It has no usage metrics, and the scientific results it produced are the researcher's, not mine.

“Leonardo showed commitment and professionalism from the very first contact. He was very attentive and patient, going over the project information as many times as necessary. Excellent professional.”
Tatiana C., PhD candidate, Environmental Engineering

What I learned

  • Show the trade-offs; don't hide them. When objectives conflict, a Pareto front lets the expert choose. A single weighted score would have made that choice for her, inside the code.
  • Name the code after the model. Variables follow the model's own terms, BOD, DO, K1 and K2, so the code can be checked against the model's equations.
  • Explain the knobs. A genetic algorithm only helps if the person running it knows what population size, mutation rate and generations do. The manual spends a whole section on that.