Files
MeanField_SERiF/docs/rayfem.md
Emily Boudreaux 6b57738330 docs(docs): built docs
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)
2026-11-09 14:09:44 -05:00

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.