Files
suter_aandClaude Opus 5 ff8fb9cf70 cmake: check at config time that ROOT provides all the ROOT7 features musrview needs.
Since musrview is built on the ROOT7 web graphics it needs a fair number of
ROOT build options which are not all on by default. Without them musrview
either does not compile at all or, worse, compiles and then shows a blank
window at run time. The only check so far was for the ROOT::ROOTWebDisplay
target.

The new cmake/MusrfitCheckROOT7.cmake collects all problems and reports them
in one go, together with the ROOT cmake flags needed to fix them:
 - the ROOT build options root7, webgui and http (ROOT_<option>_FOUND),
 - the libraries ROOT::ROOTWebDisplay and ROOT::RHTTP,
 - the headers ROOT/RWebWindow.hxx and ROOT/RWebWindowsManager.hxx,
 - the API itself, through a compile-only check of the calls musrview and
   PMusrWebCanvas make. If that fails it is retried in the ROOT::Experimental
   namespace, which tells the user that the ROOT is older than 6.32 instead of
   leaving them with a compiler error,
 - JSROOT: the js directory (overridable with -DMUSRVIEW_JSROOT_DIR=<dir>), the
   modules musrview.html imports and the '<!--jsroot_importmap-->' support of
   THttpServer which resolves the 'jsroot/...' specifiers.

Not fatal, but warned about and shown in the config summary:
 - MUSRVIEW_HAS_QT6WEB: without ROOT's qt6web musrview falls back from its
   embedded window to the standard browser of the system,
 - MUSRVIEW_HAS_IMAGE_EXPORT: without libASImage 'musrview --png/--gif/--jpg'
   writes nothing. In that case the musrview_check tests, which compare
   rendered PNGs, are no longer registered - they could then only fail for a
   reason that has nothing to do with musrfit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Ck7v5F7KjinfC2EyE7K3C
2026-09-11 16:26:48 +02:00

10 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

What this is

musrfit is a C++ data analysis package for time-differential μSR (muon spin rotation/relaxation) and β-NMR data. It provides a fitting engine (musrfit), a viewer (musrview), Fourier transform tools, run-management utilities, and a set of Qt-based GUI applications (musredit, musrWiz, musrStep, mupp). It builds on CERN ROOT (Minuit2 for minimization) and depends on Boost, GSL, FFTW3, and LibXml2.

Build

Out-of-source CMake build only (in-source builds are refused). ROOTSYS must be set/sourced before configuring (. $ROOTSYS/bin/thisroot.sh or equivalent).

mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$ROOTSYS
cmake --build . --clean-first
cmake --install .          # installs binaries + writes ~/.musrfit XML config

An existing build/ tree from a prior configure already lives at build/ in this checkout (git-ignored). Reconfigure with cmake .. inside it rather than creating a second build dir.

Key CMake options (-D<option>=1 to enable):

  • nexus — NeXus (HDF4/HDF5) file format support (needed for ISIS data)
  • BMWlibs, ASlibs, BNMRlibs — optional external theory-function libraries
  • DummyUserFcn — build the example/template user function
  • qt_based_tools (default ON) — build musredit/musrWiz/musrStep/mupp; auto-detects Qt6 → Qt5 → Qt4 → Qt3
  • qt_version — force a specific Qt major version instead of auto-detect
  • try_OpenMP (default ON) — use OpenMP if available

Requires ROOT >= 6.18, C++17. On macOS see macos26_build_issues.txt for two known local workarounds (AGL framework must be dropped from Qt6 app linking; mupp needs a mupp-1.1.0 -> mupp symlink under MacOS).

Testing

Tests are registered with CTest from the top-level tests/ directory (separate from the developer sandbox in src/tests/, which is example/scratch code, not part of the test suite).

cd build
ctest                       # run everything
ctest -N                    # list tests without running
ctest -R test-histo-MusrRoot   # run a single test by name (regex match)
ctest -R '^musrview-'          # run just the musrview rendering tests

Two test families, both driven by Python wrapper scripts against .msr files in doc/examples/:

  • maxLH_check (tests/maxLH_check/) — runs musrfit on an .msr file and asserts the final max-log-likelihood/χ² value matches an expected value to 1e-4 (registered in tests/maxLH_check/CMakeLists.txt).
  • musrview_check (tests/musrview_check/) — runs musrview (optionally with -f/-a for Fourier/averaged-Fourier) and compares rendered PNG output against references in tests/musrview_check/ref/.

When adding a new example/regression case: drop the .msr (and data file) into doc/examples/, then add a corresponding add_maxLH_test(...) / add_musrview_test(...) line in the relevant tests/*/CMakeLists.txt.

Documentation

The user documentation for setting it up, as well as for its usage can be find either under ../musrfit-docu (sphinx) or under https://lmu.pages.psi.ch/musrfit-docu/

Architecture

Core fitting pipeline

The central data model and control flow (all in src/classes/ with headers in src/include/):

  • PMsrHandler parses/writes the .msr fit-definition file format (theory block, parameters, run blocks, Fourier/plot options) — the human-editable input driving every fit.
  • PRunDataHandler loads raw histogram data from the various supported file formats (MusrRoot/HDF5, PSI-BIN, PSI-MDU, ROOT (LEM), MUD (TRIUMF), NeXus, WKM-deprecated).
  • PRunBase is the abstract base for all fit types; concrete subclasses implement format/analysis-specific PrepareData()/theory-evaluation logic: PRunSingleHisto, PRunAsymmetry, PRunSingleHistoRRF, PRunAsymmetryRRF, PRunAsymmetryBNMR, PRunMuMinus, PRunNonMusr. The run type is selected by the PRUN_* constants in PMusr.h.
  • PRunListCollection aggregates all runs of a fit for global/simultaneous fitting.
  • PTheory parses the algebraic theory expression from the msr file into a tree of built-in functions (~34 of them) and evaluates it per bin.
  • PFunction / PFunctionHandler / PFunctionGrammar / PFunctionAst implement a small Boost.Spirit-based expression grammar used for user-defined parameter functions (FUNCTIONS block in the msr file).
  • PFitterFcn wraps the χ²/max-log-likelihood objective for ROOT's Minuit2; PFitter drives the minimization and post-fit error analysis.
  • PMusrViewMode / PMusrViewModel / PMusrWebCanvas (namespace musrview) are what musrview is built from since the ROOT7 rewrite:
    • PMusrViewMode describes what is shown as four orthogonal properties: domain (time/Fourier), Fourier component, difference (and whether it is formed before or after the transform, d-f vs f-d) and average. No GUI/ROOT dependency; unit tested in tests/viewmode_check/.
    • PMusrViewModel is the GUI-free data layer: it builds the data/theory histograms, their Fourier transforms, the differences and the average, and answers GetCurves(mode) with the histograms that mode makes visible. Plotting and ascii export both go through that one selector, so they cannot disagree.
    • PMusrWebCanvas is the front end. CollectDrawables() returns the objects of the current view with their ROOT draw options; from that, the interactive path serializes a plain TList with TBufferJSON and pushes it through an ROOT::RWebWindow to a JSROOT page (src/musrview_web/musrview.html), which draws them in order and shows title/parameters/theory/run-info as scrollable, individually collapsible HTML panels. Deliberately no TCanvas is built for that path: a TCanvas maps its window in the constructor, which would put an empty ROOT window next to the musrview window (toggling gROOT->SetBatch() at run time crashes in TCanvas::Build(), and ROOT web canvases open their own window). The graphics export (--png, ...) uses the same collector but draws into a real TCanvas with the classic pad layout, running with ROOT in batch mode, so batch runs need no browser.
    • The web assets are installed to <prefix>/share/musrfit/musrview; set MUSRFIT_WEB_DIR to run from the source tree, and MUSRVIEW_DEBUG=1 to trace the websocket traffic.
    • musrview needs a ROOT built with -Droot7=ON -Dwebgui=ON -Dhttp=ON, plus -Dqt6web=ON for the embedded window (--embedded, the default). --browser uses the system browser, --browser=server only prints the URL. All of that (build options, ROOT::ROOTWebDisplay/ ROOT::RHTTP, the ROOT7 headers, the ROOT::RWebWindow API itself via a compile check, JSROOT and its import map) is verified at config time by cmake/MusrfitCheckROOT7.cmake, which also sets MUSRVIEW_HAS_QT6WEB / MUSRVIEW_HAS_IMAGE_EXPORT (the latter gates the musrview_check tests, since they compare rendered PNGs and thus need ROOT's libASImage).
  • PFourier / PFourierCanvas / PPrepFourier handle the Fourier transform and its (still TCanvas based) display, used by musrview/musrFT.
  • PMsr2Data implements msr2data's logic for generating follow-up/global msr files from a template across a run list.

Executables in src/*.cpp are thin drivers over these classes: musrfit.cpp (fitter), musrview.cpp (viewer), musrFT.cpp (Fourier tool), musrt0.cpp (t0 determination), msr2data.cpp / msr2msr.cpp (msr file generation/conversion), addRun.cpp (run summation), any2many.cpp / dump_header.cpp / write_musrRoot_runHeader.cpp (format conversion/inspection), musrRootValidation.cpp.

Extending with user functions (plugins)

Beyond the built-in theory functions, custom physics models are added as PUserFcnBase subclasses compiled into standalone shared libraries and loaded dynamically at runtime via ROOT's plugin mechanism — no core rebuild needed. See the doc comment in src/include/PUserFcnBase.h for the full header/impl/LinkDef pattern. Existing examples of this pattern live under src/external/ (libFitPofB, libGbGLF, libLFRelaxation, libZFRelaxation, libSpinValve, libGapIntegrals, libPhotoMeissner, libCalcMeanFieldsLEM, libCuba, LF_GL, Nonlocal, MagProximity, DepthProfile, BMWtools, libBNMR, DummyUserFcn as a minimal template). Each has its own CMake option gate (ASlibs, BMWlibs, BNMRlibs, DummyUserFcn) or is built unconditionally.

Third-party/vendored format support (src/external/)

mud (TRIUMF MUD format), MusrRoot (ROOT/HDF5-based format + its LaTeX definition doc), TLemRunHeader (LEM ROOT files), MuSR_software/Class_MuSR_PSI (PSI-BIN/PSI-MDU), nexus (NeXus/HDF4/HDF5, only built when -Dnexus=1) are vendored client libraries for reading each raw data format; PRunDataHandler dispatches to the appropriate one based on file extension/content.

GUI tools (src/musredit_qt6/, with _qt5/legacy musredit/musrgui siblings)

Qt6 is the primary target; CMake auto-falls-back to Qt5 → Qt4 → Qt3 equivalents if Qt6 isn't found (qt_based_tools/qt_version options above). Four independent Qt apps:

  • musredit — msr-file editor/front-end for running musrfit.
  • musrWiz — wizard for constructing new msr files from instrument/function templates (func_defs/, instrument_defs/).
  • musrStep — step-through/interactive fit tool.
  • mupp — μSR parameter plotter (plots fit results extracted across multiple msr files).

Runtime configuration

Installed binaries read an XML startup config from ~/.musrfit (written at cmake --install time), not from the source tree — check that location when debugging why an installed binary behaves differently from a locally-built one in build/.

Notes

  • Version is tracked in CMakeLists.txt (project(musrfit VERSION x.y.z ...)); the current branch (root6) is mid-refactor targeting ROOT 6-only support (PMsrHandler C++17 tokenizer rewrite, PMsrHighlighter renamed to CERN/ROOT naming scheme — see ChangeLog).
  • Full user documentation lives externally at https://lmu.pages.psi.ch/musrfit-docu/index.html, not in this repo; doc/ here holds Doxygen configs (doc/*.dox, doc/*_dox.cfg) and the example/regression .msr files consumed by the test suite.