Skip to content

Architecture

Jgocunha edited this page Jun 1, 2026 · 3 revisions

Module map

dynamic-neural-field-composer/
β”œβ”€β”€ application/        Application entry point and GUI lifecycle
β”œβ”€β”€ simulation/         Time-stepped simulation engine + JSON persistence
β”œβ”€β”€ elements/           All element types (neural fields, kernels, couplings, ...)
β”œβ”€β”€ element_parameters/ Shared parameter structs and element identity types
β”œβ”€β”€ visualization/      Plot management (line plots, heatmaps)
β”œβ”€β”€ user_interface/     ImGui windows (node graph, inspector, metrics, ...)
β”œβ”€β”€ tools/              Logger, math utilities, profiling, file dialogs
└── exceptions/         Custom exception hierarchy

Namespaces

Namespace Contents
dnf_composer Simulation, Visualization, Application, Exception, learning rules
dnf_composer::element All element classes and their parameter structs, ElementFactory
dnf_composer::user_interface All ImGui window classes
dnf_composer::tools::logger Logging utilities
dnf_composer::tools Math, profiling, utils

Layer design

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Application                β”‚  GUI lifecycle, window management
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   Visualization  β”‚    User Interface    β”‚  Plotting, node graph, inspectors
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚               Simulation                β”‚  Element management, time loop
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚               Elements                  β”‚  Neural fields, kernels, couplings
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚          Tools / Exceptions             β”‚  Logger, math, profiling, errors
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Each layer depends only on layers below it. The Application drives both the Simulation and the Visualization; neither of them knows about the other's internals.


Execution flow

  1. Setup β€” create Simulation, Visualization, Application; add windows; create elements and wire interactions; register plots
  2. Init β€” app.init() initializes the GUI and calls Simulation::init() on all elements
  3. Loop β€” app.step() calls Simulation::step() (advances all elements by deltaT) and Visualization::render() (updates plots), then renders the ImGui frame
  4. Shutdown β€” app.close() tears down the GUI and frees resources
app.init()
    └─► simulation.init()
            └─► element.init()  [for each element]

app.step()  [called every frame]
    β”œβ”€β–Ί simulation.step()
    β”‚       └─► element.step(t, deltaT)  [for each element]
    └─► visualization.render()
            └─► [update each plot from simulation components]

Key design decisions

Elements as nodes in a graph

Elements form a directed graph. Each element holds references to its input elements and reads from a named component (e.g. "output") during step(). Interactions are explicit: calling a->addInput(b) registers b as a source for a.

Components as named buffers

Every element exposes its internal state as named std::vector<double> buffers called components (e.g. "activation", "output", "input", "weights"). The visualization and UI read from these buffers directly, with no coupling to the element's type.

ElementFactory

ElementFactory::createElement() is one way to construct elements: it takes an ElementLabel enum and typed parameter structs, decoupling callers from concrete constructors. This is the path used by the JSON loader and wherever the element type is chosen at runtime. Elements can equally be constructed directly with std::make_shared<ConcreteType>(commonParams, specificParams) β€” the type-safe approach used by the examples and most application code.

JSON persistence

SimulationFileManager serializes and deserializes the full element graph to/from JSON. It is invoked via Simulation::save() and Simulation::read(). Each simulation's files are co-located under data/<simulation_name>/:

data/
└── <simulation_name>/
    β”œβ”€β”€ <simulation_name>.dnf           # element graph + parameters
    β”œβ”€β”€ <coupling_name>_weights.txt     # FieldCoupling weight matrix (one file per coupling element)
    β”œβ”€β”€ exports/                        # snapshot CSV files (one per takeSnapshot() call)
    └── recordings/                     # time-series CSV files (one per startRecording() session)

Recording and snapshot export

SimulationRecorder (owned by Simulation, accessible via getRecorder()) manages ongoing time-series recordings and one-shot snapshot exports. It is called automatically from Simulation::step() and closed in close() / clean().

Clone this wiki locally