Simon van Lierde

Research software engineer · PhD candidate, Leiden University

At CML, Leiden University, I write open software and collect open data for industrial ecology and the circular economy. Most of my time goes into R9lab, where we take products apart to record what they're made of.

R9lab to date: 93 products taken apart, 1 779 components catalogued ().

Open any numbered part.

1 CAMERA RIG2 CAPTURE APP3 WEB APP4 API5 DATABASE6 DOCS1 CAMERA RIG2 CAPTURE APP3 WEB APP4 API5 DATABASE6 DOCS
Fig. 1: An exploded view of R9lab, an open research platform for taking products apart.

Selected work

Research platform

R9lab

Industrial ecology has little data on what products are made of. R9lab records it by taking durable goods apart, component by component. I designed and built the platform, and CML now uses it. It has a FastAPI backend, a PostgreSQL data model for life-cycle assessment, and an Expo / React Native capture app.

In use at CML since Oct 2025, including two teardown workshops.

Notes A–D · running totals

  1. 93Products documented
  2. 1 779Components catalogued
  3. 4 454Images captured
  4. 135Workshop participants

Products, components and images as counted ; participants at the two pilot workshops.

Measure
050100Oct2025NovDecJan2026FebMarAprMayJunJulAugSepOct93

Products: 93 by Oct 2026.

Products, running total by month
PeriodAddedRunning total
Oct 20252626
Nov 20251642
Dec 2025345
Jan 20261358
Feb 20261573
Mar 2026982
Apr 2026890
May 2026292
Jun 2026092
Jul 2026092
Aug 2026092
Sep 2026092
Oct 2026193
Fig. 2: R9lab running totals of products, Oct 2025 to Oct 2026.

pre-commit hook

jsonvet

A pre-commit hook and Rust library that checks JSON, JSONC, JSON5 and other JSON dialects for syntax errors and duplicate keys. I rewrote it from Python in Rust and released 2.0 on PyPI and crates.io. It gives the same verdicts as the Python version on all 40,228 file-by-file comparisons with version 1.4.1.

  • Rust
  • pre-commit
  • PyPI

benchmark suite

brightway-benchmarks

Times the everyday calculations of the Brightway LCA framework across its releases, and checks every result against an independent reference score, so a release that gets slower or quietly changes a score shows up. It runs on synthetic databases shaped like ecoinvent, so anyone can rerun it.

  • Python
  • asv
  • LCA

web app

credit-matrix

Write CRediT contribution statements (who did what on a paper) with your co-authors. Export the grid as a contribution heatmap, and as JATS4R XML, CSV, JSON, or Markdown. It runs in your browser, in nine languages, and works offline.

  • TypeScript
  • Next.js 16
  • Tailwind CSS
  • Zustand

interactive map

ramascene-explorer

A map of where a country's consumption causes greenhouse-gas emissions, jobs and metal-ore extraction, split by 15 industry sections. It reads precomputed RaMa-Scene runs on EXIOBASE 2011: a baseline and 153 scenarios, three named interventions and 150 material-efficiency scenarios. The browser fetches only the parts of a 51.5 MB Parquet file it needs, about 0.98 MB on first load. Every number comes from a checked engine run, and none of it is a forecast.

  • Svelte
  • D3
  • Parquet
  • EXIOBASE

provenance library

sourceledger

A Python library that builds a dataset from public sources so every output row says which download it came from: the URL, the time and the file's SHA-256. It finds a source the publisher changed without saying so, and writes a Frictionless Data Package for the outputs. No dependencies; released on PyPI with a Zenodo DOI.

  • Python
  • PyPI
  • Frictionless

observability stack

monitoring

Shared monitoring for CML's research platforms. Logs, traces, and metrics sit on one host and link to each other, so you can follow a failing research service from one place.

  • OpenTelemetry
  • Grafana stack
  • Docker Compose
  • OpenTofu

project template

project-templates

Copier templates you combine to start a Python, TypeScript, Rust, Go or Docker project with linting, tests, CI and releases already set up. One command pulls later template fixes into the project.

  • Copier
  • GitHub Actions
  • just

consistency checker

codemeta-drift

Finds where the files of the CodeMeta research-software metadata standard contradict each other: its property list, examples and 46 crosswalks to other formats. On CodeMeta's main branch it caught all 46 crosswalks still listing a property the standard had dropped.

  • Python
  • CodeMeta
  • metadata

interactive visual

cv-ie-taxonomy

An interactive map of how computer vision can be used in industrial ecology, drawn as a product taken apart. It goes with an upcoming paper.

  • React
  • TypeScript
  • SVG
  • Motion

thesis + dashboard

msc-thesis-ie

My MSc Industrial Ecology thesis (Leiden / TU Delft): how much cooling The Hague's buildings need, and the life-cycle impact of that cooling, worked out building by building. It joins the Dutch building register (BAG) with an hourly heat-balance model and life-cycle assessment. A dashboard maps the demand across the city's 112 neighbourhoods.

  • Python
  • LCA
  • Geospatial
  • TypeScript

Smaller projects

  • AI4IE hub: a proposed resource hub for the AI for industrial ecology working group, with 75 literature entries and in-browser demos. (live)
  • cml-gallery: a demo gallery of CML's research projects, one Markdown file per project, filtered in the browser. (live)
  • io-notebook: a marimo course on environmentally extended input-output analysis that runs in the browser, with self-checks that rerun as you move the sliders. (live)

When an industrial-ecology library I use gets something wrong or runs slowly, I fix it upstream:

Merged upstream (30 pull requests)

  • lca_algebraic: fixed truncated-normal and lognormal sampling, method lookup and a cache that went stale across time zones; halved the time to expand parameters, and made Sobol analysis about 20× faster when second-order indices are not needed (#106, #107, #108, #109, #110)
  • Brightway (bw2calc): fixed normalized and weighted scores that went stale after a new impact assessment, and a cutoff that broke on negative scores (#167, #168)
  • pymrio: made one step of the account calculation 26× faster with identical results, fixed three small bugs, and got the development test job passing again (#179, #180, #181)
  • Brightway (stats_arrays): stopped loading scipy.stats at import, which makes importing bw2calc and bw2data about 0.3 s faster (#43)
  • flodym: stopped lifetime extension from overwriting the model's parameters, and made it about 9× faster (#198)
  • premise: fixed two bugs in how external scenarios apply efficiency changes, one of which scaled flows they were meant to leave alone (#316, #317)
  • Activity Browser: kept parameter amounts editable, loaded scenario files with empty keys, and kept a Monte Carlo seed of 0 (#1743, #1744)
  • Brightway (bw2data): upgraded deepdiff past two security advisories without breaking saved project revisions (#295)
  • Boavizta API: made the use phase return values for six impact criteria that said 'not implemented' (#583)
  • CodeMeta: fixed the GitHub crosswalk, which mapped a project's name to its owner/repo path (#505)
  • SchemaStore: added sourceledger's config schema, and fixed a schema that failed its own valid tests under draft-07 (#6522, #6531)
  • pyOpenSci Python package guide: updated the tutorials for project URL labels and PEP 735 dependency groups, and fixed a version pin that does not exist (#823, #824, #827)
  • wanderer: made the list editor's trail search show up to 20 matches ranked by relevance, not three (#1417)
  • fastapi-mail: improved Redis connection handling and let it reuse an existing connection (#283, #284)
  • cspell-dicts: added the notebook file type and new technical terms (#5339, #5364)
  • sentier_data_tools: improved IRI handling (#2)

Personal projects (5)

multiplayer game

6-second-scribbles

A real-time multiplayer drawing and guessing game, with a Vue 3 front end and a FastAPI back end that talk over WebSockets. In a load test, one back-end container with one CPU holds about 200 rooms of 6 players, and 95% of messages arrive within 250 ms.

  • Vue 3
  • FastAPI
  • WebSockets

CLI tool

roadmap-sh-file-integrity-checker

My answer to the roadmap.sh file integrity checker exercise, written three times: in bash, Python and Rust. All three share one signed store format, and a test runs them against each other on random file trees. It has a written threat model and refuses an older signed store put back in place.

  • Rust
  • Python
  • bash

web app

tide

A period tracker you install from the browser, with no accounts, no network and no analytics: the data never leaves the device. Backtested on an open cohort of 581 people, its next-period prediction is off by 2.0 days on average after six cycles, against 2.6 days for a fixed 28-day cycle.

  • React
  • TypeScript
  • PWA

web app

bikespot

Remembers where you parked your bike, the way a station bike park labels it (lane, rack level, rack number), with an optional photo and GPS position. It installs from the browser, works offline, keeps everything on your device, and speaks seven languages.

  • Preact
  • TypeScript
  • PWA

web app

scattergories

An unofficial table companion for the Scattergories party game: it rolls the letter, draws the categories and runs the timer. Each language draws letters from its own alphabet, weighted by how often that language uses each letter, in nine languages.

  • React
  • i18next
  • PWA