|
FhSim
3.1.0
Marine systems simulation
|
The <OBSERVERS> section declares what should happen with simulation output: writing to file, logging to console, streaming over the network, rendering 3D graphics, or loading a custom observer plugin.
Behaviour when <OBSERVERS> is absent: a FileOutput observer is created automatically if an output file path is configured (via CLI -o or XML). A Visualization observer is created for FhVis when the provider is an integrator.
Behaviour when <OBSERVERS> is present: only the listed observers are created. An empty <OBSERVERS/> tag runs with no observers at all (useful for benchmarking).
Writes simulation results to a semicolon-separated CSV file.
| Attribute | Required | Default | Description |
|---|---|---|---|
outputFile | No | modeloutput.csv | Output file path. Relative paths resolve from the working directory. CLI --output-file overrides this. |
TOutput | No | (every step) | Output schedule specification — controls when rows are written (see below). |
Select | No | "objects:all" | Filter expression selecting which signals to write (see below). |
By default, FileOutput writes one row per integrator step. The TOutput attribute lets you control which time points are written, using interpolation to produce evenly-spaced output independent of the integrator's internal steps.
Supported formats:
| Format | Description |
|---|---|
"start:delta:end" | Output from start with interval delta until end. |
"start::end" | Output every integrator step from start until end. |
":delta:end" | Output every delta from simulation start until end. |
":delta:" | Output every delta from simulation start until simulation end. |
"start:delta" | Output from start with interval delta until simulation end. |
"start:end" | Output only at start and end times. |
"t1,t2,t3,..." | Output at specific explicit times (interpolated). |
"start:delta:Inf" | Inf in the end position means "until simulation end". |
Examples:
Inf (any capitalisation) is accepted only in the end position of a colon form — "0:0.1:Inf" and "10:Inf" are valid, "Inf:0.1:60" is not. It is read as the simulation end time, so it is equivalent to leaving the end field empty.
[TStart, TEnd] are dropped. A schedule whose times all fall outside the simulated interval produces no rows.When TOutput is omitted or empty, every integrator step is written.
The Select attribute controls which SimObject signals appear in the output file:
| Expression | Description |
|---|---|
"objects:all" | All ports and states of all SimObjects. |
"objects:ports" | Output ports of all SimObjects. |
"objects:states" | States of all SimObjects. |
"object.spring1:all" | All ports and states of the SimObject named spring1. |
"object.spring1:ports" | Output ports of the SimObject named spring1. |
"object.spring1:states" | States of the SimObject named spring1. |
"object.spring1:port.ForceA" | Only the ForceA output port of spring1. |
"object.spring1:state.x" | Only the x state of spring1. |
"union(A, B)" | Union of two expressions. |
"intersect(A, B)" | Intersection of two expressions. |
"minus(A, B)" | Expression A minus expression B (set difference). |
The object selector uses the grammar object.<name>:<atom> or object.<name>:<atom>.<signal>, where <name> is the SimObject instance name (not its type) and <atom> is one of all, ports/port, or states/state. The plural form objects:<atom> selects across every SimObject and takes no name.
objects.<Type>:<atom> form, but it cannot be used from <FileOutput Select>. The observer evaluates the expression against the output metadata, which carries no SimObject type, so objects.Mass:all parses without complaint and matches nothing — leaving a CSV with only a Time column. Select by instance name.An unknown object name or signal name behaves the same way: it selects nothing rather than reporting an error. A malformed expression — a missing bracket, an unknown atom — is an error.
Signal names carry no scalar-index suffix. In a
port.<signal>orstate.<signal>selector, use the bare signal tag (e.g.Pos,ForceA) — not the_0/_1scalar-index suffix that appears in the CSV header. A vector signal is selected once by its base name and expands to all its scalar columns automatically.
Examples:
The output file uses semicolon-separated values with this layout:
Time in the first column.signalName_0, signalName_1, …). First column is empty.Column order: ODE state columns first, then port output columns.
This format is also read back by the <Replay> state provider.
Logs step index, simulation time, and timing statistics each step.
No attributes. Silently skipped when running without a console (e.g. from a DLL context).
Serialises each simulation snapshot and broadcasts it over a ZeroMQ PUB socket.
| Attribute | Required | Default | Description |
|---|---|---|---|
endpoint | Yes | — | ZeroMQ bind endpoint, e.g. tcp://*:5555. |
When used as an input provider (a <Network> element inside <SIMULATION>, as in the subscriber example below), it also accepts a timeout attribute (connection timeout in milliseconds, default 5000). The observer form (inside <OBSERVERS>) reads only endpoint.
A metadata handshake socket (REP) is automatically created on TCP port+1, allowing late-joining subscribers to request metadata before subscribing.
Example: endpoint="tcp://*:5555" → data on :5555, metadata on :5556.
Publisher (simulation process):
Subscriber (separate process):
Renders the simulation in a 3D window. Only available in FhVis builds (compiled with FH_VISUALIZATION).
| Attribute | Required | Default | Description |
|---|---|---|---|
frameRate | No | 30 | Target render frame rate in Hz. CLI --frame-rate overrides this. |
sceneManager | No | "DefaultSceneManager" | Ogre3D scene manager type name. |
See 3D scene navigation for camera controls and keyboard shortcuts.
Loads a shared library (.so / .dll) at runtime and delegates all observer calls to it.
| Attribute | Required | Default | Description |
|---|---|---|---|
library | Yes | — | Shared library filename. Relative paths resolve against observerPlugins/ in the working directory. |
config | No | "" | Opaque string forwarded to CreateObserver(config) in the plugin. |
Implement the fhsim::IStateObserver interface and export two C functions:
Build as a CMake MODULE library and place the resulting .so/.dll in the observerPlugins/ directory.
To turn SimMetadata::outputColumns into flat column indices, header labels (signal_0, signal_1, …) or (object, signal) lookups, construct a fhsim::OutputView (#include "fhsim/OutputView.h") in OnSimulationStart instead of re-implementing the arithmetic. It also evaluates a Select expression when given one. The example plugin in examples/plugin_observer_file/ shows the pattern.
results.html plots the CSV written by <FileOutput> in a browser: pick the X signal and any number of Y signals, zoom, pan and hover. It is installed next to the executable — playpen/bin/results.html in the playpen layout, or share/fhsim/results.html in a plain install — so in the directory a run writes its results.csv into.
By hand. Open results.html and drop one or more results files onto it (or use the file picker). Several files can be loaded at once and are drawn in the same axes: the Y list is the union of the signal names across them, and every ticked file contributes a trace per selected signal, so the same selection compares two runs directly. Runs sampled on different time grids need no alignment. Selections can be stored as named presets, which are kept in the browser and hold signal names only, so a preset made on one run applies to the next.
From the command line. fhsim_plot writes a copy of the viewer with the data baked in and opens it in the default browser:
A diagnostics JSON file is dispatched to the diagnostics viewer instead, so the same command covers both:
The data is baked into the page because a browser refuses to let a page opened from file:// read a file named in its own URL. Opening results.html itself and dropping the file on it is therefore equivalent, and the baked page needs no network and no server.
https://cdn.plot.ly. On a machine without internet access, put plotly-2.35.2.min.js next to the viewer and it is used instead.Every relative path written inside an input file is resolved against the working directory, and FhSim chooses that directory itself at startup — before any XML path is resolved. This is the single rule behind outputFile, <Plugin library>, <Replay csvFile>, JsonOutput, InitialStatesFile / FinalStatesFile, <FromFile FileName> and LibName. Absolute paths are always used as-is.
At startup FhSim looks for a marker file named FHSIM_DIR_IDENTIFIER and moves into the first place that has one:
FHSIM_DIR environment variable.If none of them has the marker, the launch directory is kept and a message says so. The move is silent in normal output: when a marker sits next to the executable, running FhSim from an arbitrary directory writes its results next to the binary instead of where you started. Run with -c 4 (the highest console verbosity) to see which directories were searched and which one was chosen.
-o / --output-file. Everything named inside the XML is relative to the directory chosen above. When in doubt, use absolute paths, or run FhSim from the directory that holds the marker file.-o.