Peano
Loading...
Searching...
No Matches
Developer guidelines and tips

This page collects design philosophy notes, patterns, idioms and practical tips that recur throughout Peano and its extensions.

Where the architecture page explains how the code is organised into layers, this page captures why* certain recurring implementation choices were made, and how to work with the code base day to day, so both can be reused (or deliberately deviated from) consistently.

Python motivation

Previous generations of Peano and the first generation of ExaHyPE 2 relied on C++ template meta programming to generate code and lacked any Python support. In principle, this would have been a valid way forward, but we wanted to write a piece of software which is accessible to colleagues without extensive C++ knowledge.

In the age of LLMs, we notably wanted to create a piece of software which is easy to use with a language model. For this purpose, Python is hard to beat.

Patterns and idioms

  • In the original ExaHyPE 2 rewrite, we did rely a lot on Jinja 2 templates to generate all kind of files. As the code evolved, we decided that we want to move away from Jinja 2 templates as they are hard to maintain and to debug. Notably, they imply that knowledge is scattered between the template and the Python code, while we saw more and more logic migrate from the Python files into the templates.
  • A Python layer only writes into the Python layer below it. Notably, no ExaHyPE 2 api generator writes directly into the Peano 4 layer. This is a design choice to avoid that knowledge is scattered across layers.

Hunting bugs with the logging

Peano's tarch::logging infrastructure (info, warning, error, debug and tracing messages, plus log filters to narrow down which classes actually report) is documented in full on the logging, tracing, statistics, profiling and assertions page. This section is not a repeat of that reference; it is the practical workflow to follow when you actually have to hunt a bug.

Before you write a single logDebug statement or chase a stack trace, rebuild against one of the _debug or _asserts archive flavours (see the build variants section of the installation page) and, ideally, link the _debug variant first. Release archives compile assertions out entirely (-DPeanoDebug=0), so a bug that trips an invariant will either silently corrupt state or segfault miles away from its actual cause. Assertions are by far the fastest way to localise a defect - let the code tell you where it broke before you start guessing.

Once you are linked against a debug/asserts build, a productive way to narrow down a bug is:

  1. Let assertions fail first. An assertion failure names the exact file, line and (often) the offending values, and it flushes all pending log output before the rank goes down. Read that flushed log before you touch anything else - the last few debug lines before the assertion usually tell you which algorithmic step was in flight.
  2. Reproduce with the smallest configuration you can. Fewer cells, one rank, one thread, a coarse mesh. Peano's traversal order is deterministic for a given setup, so a smaller reproducer keeps the same code paths without the noise of a production run.
  3. Switch on debug logging for the suspect classes only, rather than globally. A full -DPeanoDebug=4 run on anything but a toy setup produces gigabytes of output you will never read. Use a log filter file (see the log filter section on the logging page) to whitelist just the classes/namespaces you suspect, e.g. the observer or action set you are debugging plus peano4::grid for the traversal itself.
  4. Use tarch::logging::LogFilter::switchProgramPhase() if the bug only shows up in one phase of a multi-step algorithm (e.g. only during grid construction, not during the time stepping). This lets you keep the filter file small and phase-specific instead of drowning in logs from unrelated phases.
  5. Escalate to _debug before you escalate to a debugger. Peano's logging plus assertions localise the vast majority of bugs on their own; reach for gdb/gpu debuggers only once the log trail runs cold.