feat(fp_mcp): expose set_param_str tool for KNAMEQ / MODELG=3 equilibrium load - #231
Open
HengyuLi-Ozaki-lab wants to merge 1 commit into
Open
Conversation
…rium load
Every layer below MCP already supported string-valued fp parameters;
only the MCP server did not, so `KNAMEQ` was unreachable from any MCP
client:
* C ABI fp/fp_api.f90:155 — fp_api_set_param_str is
BIND(C, NAME="fp_set_param_str"), and the symbol is
present in the built library
(nm -gU fp/libfpapi.so | grep set_param_str ->
T _fp_set_param_str). No .so rebuild is required.
* registry fp/fp_param_registry.f90:171-182 — fp_param_set_str
has CASE ("KNAMEQ").
* wrapper python/fplib/fplib.py:163 — Fplib.set_param_str().
* MCP (this commit) — the gap.
This unlocks EQ->FP: eq_mcp's `save` writes an equilibrium file, and fp
can now be pointed at it with MODELG=3 + set_param_str("KNAMEQ", path),
the same file-handoff shape EQ->TR already uses. Without it, MODELG=3
falls back to the pl_init default KNAMEQ='eqdata', eq_load fails, and
BESEKNX trips with NCALC=-2 (see the comment block in
fp_param_registry.f90).
Changes mirror eq_mcp/server.py and tr_mcp/server.py:
* new `set_param_str` tool + handle_set_param_str() handler;
* `str` added to the SupportedValue union and to _apply_bulk_params,
so set_params({"KNAMEQ": "eq.bin"}) also routes correctly instead
of failing the float() coercion;
* KNAMEQ added to PARAMETER_REGISTRY as type "str";
* --print-tools, server instructions and docstrings updated (9 -> 10
tools).
Tests: two tests pinned the old numeric-only contract and were updated
to pin the new one (string -> set_param_str; 10 tools). Added coverage
for the registry entry, the handler, and the old-.so error mapping.
45 passed, 55 subtests passed.
Live-verified against the built libfpapi.so:
handle_set_param_str('KNAMEQ', 'eq.bin') -> ok
handle_set_param_str('KNAMFP', 'x.bin') -> rc=1 (registry has one CASE)
handle_set_params({'MODELG': 3, 'KNAMEQ': 'eq.bin'}) -> 2 parameter(s)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Exposes
set_param_stras anfp_mcpMCP tool. This is pure wiring — every layer below the MCP server already supports it:fp/fp_api.f90:155fp_api_set_param_str…BIND(C, NAME="fp_set_param_str")— already an exported symbolfp/fp_param_registry.f90:171-182fp_param_set_strwithCASE ("KNAMEQ")python/fplib/fplib.py:163Fplib.set_param_str()python/mcp-servers/fp_mcp/server.pyNo
.sorebuild is required — the symbol is already in a stocklibfpapi.so:Why
fp_param_registry.f90's own comment states the intent:Until now that entry point was unreachable from an MCP client, so
fp_mcpcould not use theMODELG=3equilibrium-load path at all.eq_mcpandtr_mcpboth already exposeset_param_str; this bringsfp_mcpto parity.Changes
stradded to theSupportedValueunion, soset_params({"KNAMEQ": ...})routes to the string setter instead of dying infloat()KNAMEQregistered inPARAMETER_REGISTRYastype: "str"handle_set_param_str()handler, error-mapped through the existing_wrap_fplib_error(FplibError→ rebuild hint, registryrc=1→invalid parameter)--print-tools(9 → 10 tools), instructions string, docstringsREADME.md: tool table,--print-toolsoutput, and two corrections — §8.3 describedMODELG=3as "analytic" when it is the file-loading path, and §8.4 said string parameters were unsupportedVerification
Against a stock build (
gfortran 15.2.0, macOS arm64):set_param_str("KNAMEQ", "eq.bin")accepted;set_param_str("KNAMFP", ...)correctly rejected withrc=1(the registry has exactly oneCASE)eq_mcp'ssavetool is loaded by FP —# OLD FILE (eq.bin) IS ASSIGNED FOR INPUT., andeqgetbwrites the file's geometry back into FP (DEVICE, RR, RA, BB = 3.60E+00 1.20E+00 4.50E+00, matching the perturbed EQ run rather than FP's own defaults). Mesh metrics move accordingly (rsrhon0.805→1.0264,bpm0.3506→0.1829,ql2.2961→7.0134), and global integrals scale with the volume ratio (stored energy 5.369→10.341 MJ = 1.93× vsTVOL28.42→53.12 = 1.87×)KNAMEQat a missing file reproduces exactly the chain the registry comment predicts —XX FROPEN (EQ): FILE NOT FOUND→eq_load: eqload: ierr=7→XX FPMESH:EQLOAD:IERR=7→XX fp_prep: fp_mesh failedtest_rejects_string_value,test_print_tools_lists_nine) and were rewritten to pin the new one; added coverage for the registry entry, the handler, and the error mapping against an older.soNote for reviewers
Independent of the companion PR that adds the
dup2(2,1)stdout guard tofp_mcp— the two touch different regions ofserver.pyand either can merge first.One finding worth recording, though it needs no change here: FP's six
get_stateprofile arrays are local per-unit-volume moments, so withMODELD=0and no wave/current-drive model they are bit-identical across different equilibria. The equilibrium enters only through the volume element and mesh metrics, whichfp_state_tdoes not currently expose. The geometry-dependent globals the code already computes (rtotalIP, stored energy, total collision/absorption power,TVOL) are written to unit 6 but not returned in the state. Happy to open a separate issue/PR for that if it is of interest.🤖 Generated with Claude Code