Note for now much of the docs is LLM written. This was done to save time and focus on code development. The docs have been LOOSLEY reviewed. However, the code itself has been either fully written by hand or fully reviewed. Therefore, the docs should at the moment be seen as a loose resource rather than authoratiative (and this is on top of the general ability for docs to drift)
247 lines
12 KiB
Markdown
247 lines
12 KiB
Markdown
# RayFEM visualization
|
|
|
|
RayFEM is a local source snapshot of `GLVis++` in `subprojects/rayfem`. The
|
|
`rayfem.wrap` URL deliberately uses the reserved `.invalid` domain: the checked-out
|
|
folder supplies the source. Keep the folder alongside the wrap; the inert URL
|
|
cannot restore this snapshot in another checkout. Configure with
|
|
`--wrap-mode=nodownload` to require local dependencies. The snapshot includes the
|
|
RayFEM library, desktop viewer, and their raylib/CZMQ/ImGui sources; the parent
|
|
supplies MFEM and CLI11. ZeroMQ remains a system dependency. Existing repository
|
|
ignore rules exclude vendored subproject directories from version control.
|
|
|
|
RayFEM uses SERiF's MFEM dependency and original SERiF library for archive loading.
|
|
The downstream `serif_dep` additionally exports `rayfem_dep`, so programs already
|
|
using `dependencies: serif_dep` can include the RayFEM headers and call its API.
|
|
The core SERiF library does not depend on RayFEM; no solver hooks or numerical
|
|
policies are changed. The viewer is enabled by default. Library-only builds can
|
|
set `-Drayfem:build_viewer=disabled`. RayFEM requires double-precision MFEM with
|
|
exceptions, as checked by its existing compatibility source.
|
|
|
|
## Build and open a saved solution
|
|
|
|
For optimized stellar solves, configure the whole build in release mode:
|
|
|
|
```sh
|
|
meson setup --reconfigure build --buildtype=release --wrap-mode=nodownload
|
|
meson compile -C build complete_sandbox
|
|
```
|
|
|
|
For a new directory, omit `--reconfigure`. Release uses Meson's standard `-O3`
|
|
and disables `MFEM_DEBUG` in the bundled MFEM and every consumer, including
|
|
SERiF, STROID and RayFEM. To select the `-O2` level and debugging symbols used
|
|
in the performance comparison, apply the overrides after setting the build type:
|
|
|
|
```sh
|
|
meson configure build -Doptimization=2 -Ddebug=true
|
|
meson compile -C build complete_sandbox
|
|
```
|
|
|
|
Meson 1.9.1 can reset explicit optimization/symbol settings when the build type
|
|
is changed in the same command; separate commands avoid that ordering issue.
|
|
Debugging symbols do not re-enable MFEM's checks. `--buildtype=debugoptimized`
|
|
also provides `-O2` with symbols and MFEM debug checks off.
|
|
`--buildtype=debug` enables MFEM's checks again.
|
|
|
|
Meson's `b_ndebug` setting controls ordinary C/C++ assertions separately and
|
|
remains unchanged (default `false`). Numerical tolerances, geometry guards and
|
|
physical acceptance criteria are unchanged. Switching build modes rebuilds the
|
|
private MFEM bundle and its consumers; the first build can take substantially
|
|
longer than an incremental build. A preinstalled MFEM with debug checks enabled
|
|
is rejected for non-debug build types; `-Dallow_preinstalled=false` selects the
|
|
matching source build. Custom optimization, symbol and assertion settings are
|
|
forwarded to MFEM's C/C++ compilation rather than replaced by CMake's defaults.
|
|
CUDA backend compiler flags retain their existing policy; this configuration was
|
|
validated with the CPU backend.
|
|
|
|
Use SERiF's existing compiler/MFEM configuration and Meson >= 1.9.1. For an existing
|
|
build directory:
|
|
|
|
```sh
|
|
meson setup --reconfigure build --wrap-mode=nodownload
|
|
meson compile -C build RayFEM
|
|
./build/subprojects/rayfem/src/RayFEM --open saved-solution.serif
|
|
```
|
|
|
|
On the current macOS machine, Homebrew LLVM selects the CommandLineTools SDK
|
|
while CZMQ's optional curl dependency discovers the Xcode SDK. Match them explicitly
|
|
if using `llvm_compiler.ini`; otherwise exported SDK headers can precede libc++:
|
|
|
|
```sh
|
|
meson configure build \
|
|
"-Dc_args=['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk']" \
|
|
"-Dcpp_args=['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk']"
|
|
meson compile -C build RayFEM
|
|
```
|
|
|
|
These are toolchain settings, not changes to RayFEM. Preserve any additional
|
|
existing `c_args`/`cpp_args` when adding the SDK setting. Use a matching installed
|
|
SDK on other machines. The isolated validation build reused SERiF's existing MFEM
|
|
installation and redirected compiler caches into its own workspace.
|
|
|
|
The viewer also accepts drag-and-drop or **Open**. The archive reader reconstructs
|
|
saved serial H1, L2 and H(div) fields, including constrained/nonconforming DOFs,
|
|
and preserves field material support. Multiple distinct saved states require an
|
|
explicit `RayFEM::SerifLoadOptions::state_path` through the C++ loader; identical
|
|
checkpoint/state duplicates are deduplicated.
|
|
|
|
Saved nodal `displacement.vector` data can deform the display. Surface-harmonic
|
|
coefficients are not nodal displacement: without a saved nodal displacement,
|
|
the viewer shows reference geometry. The compactified exterior stays in saved
|
|
mesh coordinates; this integration does not reconstruct SERiF's physical exterior
|
|
mapping. Global scalars and unsupported surface coordinates are reported rather
|
|
than rendered as spatial fields. Archive snapshots have no inferred physical time.
|
|
|
|
## Stream a solution or intermediate field
|
|
|
|
Call the existing RayFEM API from the application or its observer. Start the
|
|
viewer above, or set `RayFEM::WindowParams::executable` to the built viewer and
|
|
call `RayFEM::init` once. For existing MFEM grid functions on one mesh:
|
|
|
|
```cpp
|
|
#include "libRayfem/network/client.hpp"
|
|
#include <stdexcept>
|
|
|
|
RayFEM::Client viewer("127.0.0.1", 5555);
|
|
if (!viewer.sendMesh(1, mesh)) {
|
|
throw std::runtime_error(viewer.getLastError());
|
|
}
|
|
|
|
// Repeat after updating the fields; frame_index must increase.
|
|
RayFEM::FrameMetadata metadata{.frame_index = 0, .sim_time = 0.0};
|
|
if (!viewer.sendFrame(1, {{"solution", &solution_field},
|
|
{"intermediate", &intermediate_field}}, metadata)) {
|
|
throw std::runtime_error(viewer.getLastError());
|
|
}
|
|
```
|
|
|
|
Each frame's grid functions must reference the **same registered mesh**. Fields
|
|
on a material submesh and a full mesh need separate mesh IDs and frames. Keep
|
|
meshes/spaces alive through their registrations, and grid functions alive through
|
|
each send. Use one client from one thread. Re-register changed topology or changed
|
|
reference geometry; optionally pass a pointwise vector displacement as the fourth
|
|
`sendFrame` argument. Displacement is measured from the registered reference mesh,
|
|
not from the preceding frame. Sending succeeds when the local transport accepts
|
|
the packet; it is not an acknowledgment of rendering.
|
|
|
|
SERiF state blocks contain supported independent coefficients, not necessarily a
|
|
full MFEM `GridFunction`. Use the matching term binding's `scatter` operation to
|
|
expand a copied block and satisfy nonconforming constraints:
|
|
|
|
```cpp
|
|
#include "mfem.hpp"
|
|
#include <span>
|
|
#include <stdexcept>
|
|
|
|
template<class Binding>
|
|
mfem::GridFunction field_for_viewer(const Binding& binding,
|
|
std::span<const double> values) {
|
|
if (values.size() != static_cast<std::size_t>(binding.size())) {
|
|
throw std::invalid_argument("State and visualization binding differ");
|
|
}
|
|
mfem::Vector reduced(binding.size());
|
|
for (int i = 0; i < reduced.Size(); ++i) { reduced[i] = values[i]; }
|
|
mfem::GridFunction field(&binding.space());
|
|
field = binding.scatter(reduced);
|
|
return field;
|
|
}
|
|
|
|
// For a spatial Term from the matching discretization/state:
|
|
// auto field = field_for_viewer(finite_elements.template binding<Term>(),
|
|
// state.template get<Term>());
|
|
```
|
|
|
|
Recreate or update this visualization copy at the state you want to inspect;
|
|
it does not change the solver state. A Newton residual is a dual vector and must
|
|
not be presented as physical field coefficients without an explicit conversion.
|
|
The streaming protocol does not transmit SERiF's material-support metadata: exclude
|
|
unsupported materials in the viewer, use a suitable submesh, or load an archive
|
|
when support-aware inspection is required. Zero extension outside support is not
|
|
physical data. Geometry/displacement must correspond to the same state as the
|
|
fields; copying scalar coefficients alone does not reconstruct the deformed star.
|
|
|
|
See the vendored [RayFEM README](../subprojects/rayfem/README.md) for clipping,
|
|
profiles, vector flow, frame history, tracking, and viewer controls.
|
|
|
|
## Watch a stellar solve
|
|
|
|
`complete_sandbox` has an opt-in live observer; without arguments its existing
|
|
nonrotating n=1 solve and numerical settings are unchanged. Build and run:
|
|
|
|
```sh
|
|
meson compile -C build complete_sandbox
|
|
OMP_NUM_THREADS=1 ./build/tests/sandbox/complete_sandbox \
|
|
--angular-momentum 0.15 --surface-degree 2 --visualize
|
|
```
|
|
|
|
Building `complete_sandbox` also builds the enabled RayFEM viewer. `--visualize`
|
|
uses `RayFEM::init` to reuse a compatible running viewer on port 5555 or launch
|
|
the viewer from this build automatically. `--viewer PATH` and `RAYFEM_EXECUTABLE`
|
|
remain explicit overrides. If the build has no viewer, normal sibling/PATH
|
|
discovery remains available. `--viewer-port PORT` selects another
|
|
stream/control port pair. `--help` lists defaults. With no options it solves the
|
|
n=2, J=0.1 star (Omega/Omega_K about 0.70) at surface degree 12, which converges
|
|
from the spherical seed in 19 Newton steps and matches its ESTER/TOP reference
|
|
within 0.55 PLATO sigma. Units are M=G=R_nonrotating=1; angular momentum is the
|
|
target J in those code units.
|
|
These are accepted Newton iterates toward equilibrium, not a time evolution.
|
|
|
|
### Refine the stellar surface
|
|
|
|
The sandbox exposes mesh refinement separately from `--surface-degree`, which
|
|
controls the spherical-harmonic shape basis. Refinement is applied before
|
|
creating the field spaces; the defaults are surface 1, equatorial 1 (10 degree
|
|
band) and radial surface 3, with no uniform refinement:
|
|
|
|
- `--mesh-refinement N` uniformly refines the whole mesh N times.
|
|
- `--surface-refinement N` adds N isotropic refinement levels to the cells
|
|
touching the stellar surface, on both the stellar and vacuum sides.
|
|
- `--equatorial-refinement N` then adds N latitude splits to rings intersecting
|
|
the equatorial band. These concentrate resolution toward the equator while
|
|
keeping the polar caps at their previous resolution.
|
|
- `--equatorial-band-degrees D` sets the band's half-width, default 10 degrees;
|
|
the supported range is `0 < D <= 35`.
|
|
- `--rotation-axis X Y Z` selects the rotation axis, default `0 0 1`. Any finite
|
|
nonzero vector is normalized and used for both rotation physics and mesh
|
|
alignment.
|
|
|
|
For example, refine the entire stellar surface once and add two equatorial
|
|
levels around a tilted axis:
|
|
|
|
```sh
|
|
OMP_NUM_THREADS=1 ./build/tests/sandbox/complete_sandbox \
|
|
--angular-momentum 0.15 --surface-degree 2 \
|
|
--surface-refinement 1 --equatorial-refinement 2 \
|
|
--equatorial-band-degrees 15 --rotation-axis 1 1 1 --visualize
|
|
```
|
|
|
|
Use `--mesh-only` in place of `--visualize` to print element and surface-face
|
|
counts without solving. Counts are also printed at the start of normal solves.
|
|
On the coarsest mesh, three equatorial levels increase stellar surface faces
|
|
from 6 to 26 while leaving the two polar faces unchanged.
|
|
|
|
Equatorial refinement splits latitude only, following complete rings so that
|
|
the moving-surface representation remains compatible with the volume mesh.
|
|
Whole intersecting rings can extend beyond the requested band, especially at
|
|
low refinement levels. The 35-degree limit keeps these rings within the four
|
|
side blocks of the cubed-sphere mesh; the polar blocks begin at approximately
|
|
35.26 degrees latitude. This is fixed refinement chosen before the solve, not
|
|
adaptive refinement during Newton iterations. Field polynomial orders and
|
|
solver tolerances are unchanged; additional cells increase solve cost.
|
|
|
|
The reusable example helper `tests/sandbox/stellar_rayfem.hpp` copies density,
|
|
potential, and the evaluator's existing nodal displacement onto a submesh of the
|
|
stellar material attributes. It excludes the compactified exterior and sends the
|
|
unmodified interior reference mesh once. Each frame supplies the full current
|
|
displacement from that reference, so deformation is applied exactly once.
|
|
Scalar fields retain their physical code units. The displacement is also available
|
|
as a field for inspection; select density or potential to color the star.
|
|
|
|
The observer publishes only initial/resumed/accepted events. It checks the cached
|
|
surface parameters match the callback state, then expands the cached displacement
|
|
through its actual term binding (including ordering and constraints). A `finished`
|
|
event can leave a rejected trial in the evaluator cache and is deliberately not
|
|
streamed. The helper owns field copies and does not move solver mesh nodes or
|
|
change coefficients. Transport errors disable visualization while the solve
|
|
continues. Frame labels and terminal output give iteration and residual; frame time
|
|
is zero because no physical time integration is being performed.
|